summaryrefslogtreecommitdiff
path: root/spec/features
diff options
context:
space:
mode:
Diffstat (limited to 'spec/features')
-rw-r--r--spec/features/admin/admin_projects_spec.rb97
-rw-r--r--spec/features/admin/admin_settings_spec.rb15
-rw-r--r--spec/features/admin/dashboard_spec.rb10
-rw-r--r--spec/features/alerts_settings/user_views_alerts_settings_spec.rb7
-rw-r--r--spec/features/boards/boards_spec.rb20
-rw-r--r--spec/features/boards/sidebar_spec.rb30
-rw-r--r--spec/features/boards/user_adds_lists_to_board_spec.rb92
-rw-r--r--spec/features/commit_spec.rb16
-rw-r--r--spec/features/dashboard/group_spec.rb2
-rw-r--r--spec/features/dashboard/projects_spec.rb8
-rw-r--r--spec/features/discussion_comments/commit_spec.rb2
-rw-r--r--spec/features/discussion_comments/issue_spec.rb4
-rw-r--r--spec/features/discussion_comments/merge_request_spec.rb3
-rw-r--r--spec/features/discussion_comments/snippets_spec.rb4
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb10
-rw-r--r--spec/features/groups/container_registry_spec.rb8
-rw-r--r--spec/features/groups/members/list_members_spec.rb42
-rw-r--r--spec/features/groups/members/manage_members_spec.rb12
-rw-r--r--spec/features/groups/settings/user_searches_in_settings_spec.rb36
-rw-r--r--spec/features/groups/show_spec.rb5
-rw-r--r--spec/features/groups_spec.rb22
-rw-r--r--spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb2
-rw-r--r--spec/features/issues/csv_spec.rb4
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb682
-rw-r--r--spec/features/issues/issue_state_spec.rb26
-rw-r--r--spec/features/issues/service_desk_spec.rb16
-rw-r--r--spec/features/issues/user_interacts_with_awards_spec.rb8
-rw-r--r--spec/features/labels_hierarchy_spec.rb2
-rw-r--r--spec/features/markdown/markdown_spec.rb2
-rw-r--r--spec/features/markdown/math_spec.rb16
-rw-r--r--spec/features/merge_request/batch_comments_spec.rb2
-rw-r--r--spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb33
-rw-r--r--spec/features/merge_request/user_posts_diff_notes_spec.rb2
-rw-r--r--spec/features/merge_request/user_posts_notes_spec.rb5
-rw-r--r--spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb10
-rw-r--r--spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb6
-rw-r--r--spec/features/merge_request/user_sees_discussions_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb1
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb217
-rw-r--r--spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb2
-rw-r--r--spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb8
-rw-r--r--spec/features/merge_request/user_suggests_changes_on_diff_spec.rb2
-rw-r--r--spec/features/merge_request/user_toggles_whitespace_changes_spec.rb4
-rw-r--r--spec/features/merge_requests/user_exports_as_csv_spec.rb6
-rw-r--r--spec/features/participants_autocomplete_spec.rb1
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb6
-rw-r--r--spec/features/profiles/user_visits_notifications_tab_spec.rb9
-rw-r--r--spec/features/project_group_variables_spec.rb2
-rw-r--r--spec/features/project_variables_spec.rb3
-rw-r--r--spec/features/projects/active_tabs_spec.rb6
-rw-r--r--spec/features/projects/ci/lint_spec.rb2
-rw-r--r--spec/features/projects/commit/mini_pipeline_graph_spec.rb52
-rw-r--r--spec/features/projects/container_registry_spec.rb8
-rw-r--r--spec/features/projects/environments/environments_spec.rb80
-rw-r--r--spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb2
-rw-r--r--spec/features/projects/files/gitlab_ci_syntax_yml_dropdown_spec.rb54
-rw-r--r--spec/features/projects/fork_spec.rb270
-rw-r--r--spec/features/projects/members/anonymous_user_sees_members_spec.rb22
-rw-r--r--spec/features/projects/members/group_members_spec.rb244
-rw-r--r--spec/features/projects/members/groups_with_access_list_spec.rb176
-rw-r--r--spec/features/projects/members/invite_group_spec.rb77
-rw-r--r--spec/features/projects/members/list_spec.rb254
-rw-r--r--spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb110
-rw-r--r--spec/features/projects/members/sorting_spec.rb186
-rw-r--r--spec/features/projects/members/tabs_spec.rb72
-rw-r--r--spec/features/projects/merge_request_button_spec.rb64
-rw-r--r--spec/features/projects/new_project_spec.rb48
-rw-r--r--spec/features/projects/pages/user_edits_settings_spec.rb4
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb90
-rw-r--r--spec/features/projects/releases/user_creates_release_spec.rb31
-rw-r--r--spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb2
-rw-r--r--spec/features/projects/settings/operations_settings_spec.rb8
-rw-r--r--spec/features/projects/settings/service_desk_setting_spec.rb45
-rw-r--r--spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb8
-rw-r--r--spec/features/projects/settings/user_manages_project_members_spec.rb129
-rw-r--r--spec/features/projects/settings/user_searches_in_settings_spec.rb42
-rw-r--r--spec/features/projects/show/user_manages_notifications_spec.rb34
-rw-r--r--spec/features/projects/show/user_uploads_files_spec.rb20
-rw-r--r--spec/features/projects/user_sees_sidebar_spec.rb4
-rw-r--r--spec/features/projects/user_uses_shortcuts_spec.rb4
-rw-r--r--spec/features/projects_spec.rb2
-rw-r--r--spec/features/security/group/internal_access_spec.rb35
-rw-r--r--spec/features/security/group/private_access_spec.rb42
-rw-r--r--spec/features/security/group/public_access_spec.rb35
-rw-r--r--spec/features/sentry_js_spec.rb2
-rw-r--r--spec/features/task_lists_spec.rb8
-rw-r--r--spec/features/uploads/user_uploads_avatar_to_profile_spec.rb3
-rw-r--r--spec/features/user_can_display_performance_bar_spec.rb24
89 files changed, 1722 insertions, 2103 deletions
diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb
index aab2e6d7cef..bf280595ec7 100644
--- a/spec/features/admin/admin_projects_spec.rb
+++ b/spec/features/admin/admin_projects_spec.rb
@@ -92,97 +92,46 @@ RSpec.describe "Admin::Projects" do
end
end
- context 'when `vue_project_members_list` feature flag is enabled', :js do
- describe 'admin adds themselves to the project' do
- before do
- project.add_maintainer(user)
- stub_feature_flags(invite_members_group_modal: false)
- end
-
- it 'adds admin to the project as developer', :js do
- visit project_project_members_path(project)
-
- page.within '.invite-users-form' do
- select2(current_user.id, from: '#user_ids', multiple: true)
- select 'Developer', from: 'access_level'
- end
-
- click_button 'Invite'
-
- expect(find_member_row(current_user)).to have_content('Developer')
- end
+ describe 'admin adds themselves to the project', :js do
+ before do
+ project.add_maintainer(user)
+ stub_feature_flags(invite_members_group_modal: false)
end
- describe 'admin removes themselves from the project' do
- before do
- project.add_maintainer(user)
- project.add_developer(current_user)
- end
-
- it 'removes admin from the project' do
- visit project_project_members_path(project)
-
- expect(find_member_row(current_user)).to have_content('Developer')
+ it 'adds admin to the project as developer' do
+ visit project_project_members_path(project)
- page.within find_member_row(current_user) do
- click_button 'Leave'
- end
+ page.within '.invite-users-form' do
+ select2(current_user.id, from: '#user_ids', multiple: true)
+ select 'Developer', from: 'access_level'
+ end
- page.within('[role="dialog"]') do
- click_button('Leave')
- end
+ click_button 'Invite'
- expect(current_path).to match dashboard_projects_path
- end
+ expect(find_member_row(current_user)).to have_content('Developer')
end
end
- context 'when `vue_project_members_list` feature flag is disabled' do
+ describe 'admin removes themselves from the project', :js do
before do
- stub_feature_flags(vue_project_members_list: false)
+ project.add_maintainer(user)
+ project.add_developer(current_user)
end
- describe 'admin adds themselves to the project' do
- before do
- project.add_maintainer(user)
- stub_feature_flags(invite_members_group_modal: false)
- end
-
- it 'adds admin to the project as developer', :js do
- visit project_project_members_path(project)
-
- page.within '.invite-users-form' do
- select2(current_user.id, from: '#user_ids', multiple: true)
- select 'Developer', from: 'access_level'
- end
+ it 'removes admin from the project' do
+ visit project_project_members_path(project)
- click_button 'Invite'
+ expect(find_member_row(current_user)).to have_content('Developer')
- page.within '.content-list' do
- expect(page).to have_content(current_user.name)
- expect(page).to have_content('Developer')
- end
+ page.within find_member_row(current_user) do
+ click_button 'Leave'
end
- end
- describe 'admin removes themselves from the project' do
- before do
- project.add_maintainer(user)
- project.add_developer(current_user)
+ page.within('[role="dialog"]') do
+ click_button('Leave')
end
- it 'removes admin from the project' do
- visit project_project_members_path(project)
-
- page.within '.content-list' do
- expect(page).to have_content(current_user.name)
- expect(page).to have_content('Developer')
- end
-
- find(:css, '.content-list li', text: current_user.name).find(:css, 'a.btn-danger').click
-
- expect(page).not_to have_selector(:css, '.content-list')
- end
+ expect(current_path).to match dashboard_projects_path
end
end
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 52f39f65bd0..249621f5835 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -384,7 +384,20 @@ RSpec.describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(current_settings.repository_storages_weighted_default).to be 50
+ expect(current_settings.repository_storages_weighted).to eq('default' => 50)
+ end
+
+ it 'still saves when settings are outdated' do
+ current_settings.update_attribute :repository_storages_weighted, { 'default' => 100, 'outdated' => 100 }
+
+ visit repository_admin_application_settings_path
+
+ page.within('.as-repository-storage') do
+ fill_in 'application_setting_repository_storages_weighted_default', with: 50
+ click_button 'Save changes'
+ end
+
+ expect(current_settings.repository_storages_weighted).to eq('default' => 50)
end
end
diff --git a/spec/features/admin/dashboard_spec.rb b/spec/features/admin/dashboard_spec.rb
index c040811ada1..618fae3e46b 100644
--- a/spec/features/admin/dashboard_spec.rb
+++ b/spec/features/admin/dashboard_spec.rb
@@ -30,7 +30,6 @@ RSpec.describe 'admin visits dashboard' do
describe 'Users statistic' do
let_it_be(:users_statistics) { create(:users_statistics) }
- let_it_be(:users_count_label) { Gitlab.ee? ? 'Billable users 71' : 'Active users 71' }
it 'shows correct amounts of users', :aggregate_failures do
visit admin_dashboard_stats_path
@@ -42,9 +41,16 @@ RSpec.describe 'admin visits dashboard' do
expect(page).to have_content('Users with highest role Maintainer 6')
expect(page).to have_content('Users with highest role Owner 5')
expect(page).to have_content('Bots 2')
+
+ if Gitlab.ee?
+ expect(page).to have_content('Billable users 69')
+ else
+ expect(page).not_to have_content('Billable users 69')
+ end
+
expect(page).to have_content('Blocked users 7')
expect(page).to have_content('Total users 78')
- expect(page).to have_content(users_count_label)
+ expect(page).to have_content('Active users 71')
end
end
end
diff --git a/spec/features/alerts_settings/user_views_alerts_settings_spec.rb b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb
index 07c87f98eb6..60f2f776595 100644
--- a/spec/features/alerts_settings/user_views_alerts_settings_spec.rb
+++ b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb
@@ -19,7 +19,6 @@ RSpec.describe 'Alert integrations settings form', :js do
describe 'when viewing alert integrations as a maintainer' do
context 'with the default page permissions' do
before do
- stub_feature_flags(multiple_http_integrations_custom_mapping: false)
visit project_settings_operations_path(project, anchor: 'js-alert-management-settings')
wait_for_requests
end
@@ -30,8 +29,8 @@ RSpec.describe 'Alert integrations settings form', :js do
end
end
- it 'shows the new alerts setting form' do
- expect(page).to have_content('1. Select integration type')
+ it 'shows the integrations list title' do
+ expect(page).to have_content('Current integrations')
end
end
end
@@ -44,7 +43,7 @@ RSpec.describe 'Alert integrations settings form', :js do
wait_for_requests
end
- it 'shows the old alerts setting form' do
+ it 'does not have rights to access the setting form' do
expect(page).not_to have_selector('.incident-management-list')
expect(page).not_to have_selector('#js-alert-management-settings')
end
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index 2d6b669f28b..2392f9d2f8a 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -13,8 +13,6 @@ RSpec.describe 'Issue Boards', :js do
let_it_be(:user2) { create(:user) }
before do
- stub_feature_flags(board_new_list: false)
-
project.add_maintainer(user)
project.add_maintainer(user2)
@@ -68,6 +66,8 @@ RSpec.describe 'Issue Boards', :js do
let_it_be(:issue10) { create(:labeled_issue, project: project, title: 'issue +', description: 'A+ great issue', labels: [a_plus]) }
before do
+ stub_feature_flags(board_new_list: false)
+
visit project_board_path(project, board)
wait_for_requests
@@ -168,19 +168,6 @@ RSpec.describe 'Issue Boards', :js do
expect(page).to have_selector('.board', count: 3)
end
- it 'removes checkmark in new list dropdown after deleting' do
- click_button 'Add list'
- wait_for_requests
-
- find('.js-new-board-list').click
-
- remove_list
-
- wait_for_requests
-
- expect(page).to have_selector('.board', count: 3)
- end
-
it 'infinite scrolls list' do
create_list(:labeled_issue, 50, project: project, labels: [planning])
@@ -311,7 +298,7 @@ RSpec.describe 'Issue Boards', :js do
it 'shows issue count on the list' do
page.within(find(".board:nth-child(2)")) do
- expect(page.find('.js-issue-size')).to have_text(total_planning_issues)
+ expect(page.find('[data-testid="board-items-count"]')).to have_text(total_planning_issues)
expect(page).not_to have_selector('.js-max-issue-size')
end
end
@@ -321,6 +308,7 @@ RSpec.describe 'Issue Boards', :js do
context 'new list' do
it 'shows all labels in new list dropdown' do
click_button 'Add list'
+
wait_for_requests
page.within('.dropdown-menu-issues-board-new') do
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index 08bc70d7116..c79bf2abff1 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -72,36 +72,6 @@ RSpec.describe 'Issue Boards', :js do
end
end
- it 'removes card from board when clicking' do
- click_card(card)
-
- page.within('.issue-boards-sidebar') do
- click_button 'Remove from board'
- end
-
- wait_for_requests
-
- page.within(find('.board:nth-child(2)')) do
- expect(page).to have_selector('.board-card', count: 1)
- end
- end
-
- it 'does not show remove button for backlog or closed issues' do
- create(:issue, project: project)
- create(:issue, :closed, project: project)
-
- visit project_board_path(project, board)
- wait_for_requests
-
- click_card(find('.board:nth-child(1)').first('.board-card'))
-
- expect(find('.issue-boards-sidebar')).not_to have_button 'Remove from board'
-
- click_card(find('.board:nth-child(3)').first('.board-card'))
-
- expect(find('.issue-boards-sidebar')).not_to have_button 'Remove from board'
- end
-
context 'assignee' do
it 'updates the issues assignee' do
click_card(card)
diff --git a/spec/features/boards/user_adds_lists_to_board_spec.rb b/spec/features/boards/user_adds_lists_to_board_spec.rb
new file mode 100644
index 00000000000..b9945207bb2
--- /dev/null
+++ b/spec/features/boards/user_adds_lists_to_board_spec.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User adds lists', :js do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:group) { create(:group, :nested) }
+ let_it_be(:project) { create(:project, :public, namespace: group) }
+ let_it_be(:group_board) { create(:board, group: group) }
+ let_it_be(:project_board) { create(:board, project: project) }
+ let_it_be(:user) { create(:user) }
+
+ let_it_be(:milestone) { create(:milestone, project: project) }
+
+ let_it_be(:group_label) { create(:group_label, group: group) }
+ let_it_be(:project_label) { create(:label, project: project) }
+ let_it_be(:group_backlog_list) { create(:backlog_list, board: group_board) }
+ let_it_be(:project_backlog_list) { create(:backlog_list, board: project_board) }
+
+ let_it_be(:issue) { create(:labeled_issue, project: project, labels: [group_label, project_label]) }
+
+ before_all do
+ project.add_maintainer(user)
+ group.add_owner(user)
+ end
+
+ where(:board_type, :graphql_board_lists_enabled, :board_new_list_enabled) do
+ :project | true | true
+ :project | false | true
+ :project | true | false
+ :project | false | false
+ :group | true | true
+ :group | false | true
+ :group | true | false
+ :group | false | false
+ end
+
+ with_them do
+ before do
+ sign_in(user)
+
+ set_cookie('sidebar_collapsed', 'true')
+
+ stub_feature_flags(
+ graphql_board_lists: graphql_board_lists_enabled,
+ board_new_list: board_new_list_enabled
+ )
+
+ if board_type == :project
+ visit project_board_path(project, project_board)
+ elsif board_type == :group
+ visit group_board_path(group, group_board)
+ end
+
+ wait_for_all_requests
+ end
+
+ it 'creates new column for label containing labeled issue' do
+ click_button button_text(board_new_list_enabled)
+ wait_for_all_requests
+
+ select_label(board_new_list_enabled, group_label)
+
+ wait_for_all_requests
+
+ expect(page).to have_selector('.board', text: group_label.title)
+ expect(find('.board:nth-child(2) .board-card')).to have_content(issue.title)
+ end
+ end
+
+ def select_label(board_new_list_enabled, label)
+ if board_new_list_enabled
+ page.within('.board-add-new-list') do
+ find('label', text: label.title).click
+ click_button 'Add'
+ end
+ else
+ page.within('.dropdown-menu-issues-board-new') do
+ click_link label.title
+ end
+ end
+ end
+
+ def button_text(board_new_list_enabled)
+ if board_new_list_enabled
+ 'Create list'
+ else
+ 'Add list'
+ end
+ end
+end
diff --git a/spec/features/commit_spec.rb b/spec/features/commit_spec.rb
index 02754cc803e..80a30ab01b2 100644
--- a/spec/features/commit_spec.rb
+++ b/spec/features/commit_spec.rb
@@ -35,9 +35,8 @@ RSpec.describe 'Commit' do
end
end
- context "pagination enabled" do
+ describe "pagination" do
before do
- stub_feature_flags(paginate_commit_view: true)
stub_const("Projects::CommitController::COMMIT_DIFFS_PER_PAGE", 1)
visit project_commit_path(project, commit)
@@ -61,18 +60,5 @@ RSpec.describe 'Commit' do
expect(page).to have_selector(".files ##{files[1].file_hash}")
end
end
-
- context "pagination disabled" do
- before do
- stub_feature_flags(paginate_commit_view: false)
-
- visit project_commit_path(project, commit)
- end
-
- it "shows both diffs on the page" do
- expect(page).to have_selector(".files ##{files[0].file_hash}")
- expect(page).to have_selector(".files ##{files[1].file_hash}")
- end
- end
end
end
diff --git a/spec/features/dashboard/group_spec.rb b/spec/features/dashboard/group_spec.rb
index 0b99fed2a2d..bc6f449edc5 100644
--- a/spec/features/dashboard/group_spec.rb
+++ b/spec/features/dashboard/group_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'Dashboard Group' do
it 'creates new group', :js do
visit dashboard_groups_path
- find('.btn-success').click
+ find('[data-testid="new-group-button"]').click
new_name = 'Samurai'
fill_in 'group_name', with: new_name
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 8705c22c41a..d7330b5267b 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -198,14 +198,6 @@ RSpec.describe 'Dashboard Projects' do
it_behaves_like 'hidden pipeline status'
end
- context 'when dashboard_pipeline_status is disabled' do
- before do
- stub_feature_flags(dashboard_pipeline_status: false)
- end
-
- it_behaves_like 'hidden pipeline status'
- end
-
context "when last_pipeline is missing" do
before do
project.last_pipeline.delete
diff --git a/spec/features/discussion_comments/commit_spec.rb b/spec/features/discussion_comments/commit_spec.rb
index 32c0ba2a9a7..261e9fb9f3b 100644
--- a/spec/features/discussion_comments/commit_spec.rb
+++ b/spec/features/discussion_comments/commit_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe 'Thread Comments Commit', :js do
visit project_commit_path(project, sample_commit.id)
end
- it_behaves_like 'thread comments', 'commit'
+ it_behaves_like 'thread comments for commit and snippet', 'commit'
it 'has class .js-note-emoji' do
expect(page).to have_css('.js-note-emoji')
diff --git a/spec/features/discussion_comments/issue_spec.rb b/spec/features/discussion_comments/issue_spec.rb
index 86743e31fbd..ebb57b37918 100644
--- a/spec/features/discussion_comments/issue_spec.rb
+++ b/spec/features/discussion_comments/issue_spec.rb
@@ -8,13 +8,11 @@ RSpec.describe 'Thread Comments Issue', :js do
let(:issue) { create(:issue, project: project) }
before do
- stub_feature_flags(remove_comment_close_reopen: false)
-
project.add_maintainer(user)
sign_in(user)
visit project_issue_path(project, issue)
end
- it_behaves_like 'thread comments', 'issue'
+ it_behaves_like 'thread comments for issue, epic and merge request', 'issue'
end
diff --git a/spec/features/discussion_comments/merge_request_spec.rb b/spec/features/discussion_comments/merge_request_spec.rb
index 82dcdf9f918..f60d7da6a30 100644
--- a/spec/features/discussion_comments/merge_request_spec.rb
+++ b/spec/features/discussion_comments/merge_request_spec.rb
@@ -9,7 +9,6 @@ RSpec.describe 'Thread Comments Merge Request', :js do
before do
stub_feature_flags(remove_resolve_note: false)
- stub_feature_flags(remove_comment_close_reopen: false)
project.add_maintainer(user)
sign_in(user)
@@ -20,5 +19,5 @@ RSpec.describe 'Thread Comments Merge Request', :js do
wait_for_requests
end
- it_behaves_like 'thread comments', 'merge request'
+ it_behaves_like 'thread comments for issue, epic and merge request', 'merge request'
end
diff --git a/spec/features/discussion_comments/snippets_spec.rb b/spec/features/discussion_comments/snippets_spec.rb
index 42053e571e9..ca0a6d6e1c5 100644
--- a/spec/features/discussion_comments/snippets_spec.rb
+++ b/spec/features/discussion_comments/snippets_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe 'Thread Comments Snippet', :js do
visit project_snippet_path(project, snippet)
end
- it_behaves_like 'thread comments', 'snippet'
+ it_behaves_like 'thread comments for commit and snippet', 'snippet'
end
context 'with personal snippets' do
@@ -32,6 +32,6 @@ RSpec.describe 'Thread Comments Snippet', :js do
visit snippet_path(snippet)
end
- it_behaves_like 'thread comments', 'snippet'
+ it_behaves_like 'thread comments for commit and snippet', 'snippet'
end
end
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index 55bdf4c244e..cbd1ae628d1 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -17,7 +17,6 @@ RSpec.describe 'Expand and collapse diffs', :js do
# Ensure that undiffable.md is in .gitattributes
project.repository.copy_gitattributes(branch)
visit project_commit_path(project, project.commit(branch))
- execute_script('window.ajaxUris = []; $(document).ajaxSend(function(event, xhr, settings) { ajaxUris.push(settings.url) });')
end
def file_container(filename)
@@ -191,10 +190,6 @@ RSpec.describe 'Expand and collapse diffs', :js do
expect(small_diff).to have_selector('.code')
expect(small_diff).not_to have_selector('.nothing-here-block')
end
-
- it 'does not make a new HTTP request' do
- expect(evaluate_script('ajaxUris')).not_to include(a_string_matching('small_diff.md'))
- end
end
end
@@ -264,7 +259,6 @@ RSpec.describe 'Expand and collapse diffs', :js do
find('.note-textarea')
wait_for_requests
- execute_script('window.ajaxUris = []; $(document).ajaxSend(function(event, xhr, settings) { ajaxUris.push(settings.url) });')
end
it 'reloads the page with all diffs expanded' do
@@ -300,10 +294,6 @@ RSpec.describe 'Expand and collapse diffs', :js do
expect(small_diff).to have_selector('.code')
expect(small_diff).not_to have_selector('.nothing-here-block')
end
-
- it 'does not make a new HTTP request' do
- expect(evaluate_script('ajaxUris')).not_to include(a_string_matching('small_diff.md'))
- end
end
end
end
diff --git a/spec/features/groups/container_registry_spec.rb b/spec/features/groups/container_registry_spec.rb
index cacabdda22d..65374263f45 100644
--- a/spec/features/groups/container_registry_spec.rb
+++ b/spec/features/groups/container_registry_spec.rb
@@ -67,7 +67,13 @@ RSpec.describe 'Container Registry', :js do
end
it 'shows the image title' do
- expect(page).to have_content 'my/image tags'
+ expect(page).to have_content 'my/image'
+ end
+
+ it 'shows the image tags' do
+ expect(page).to have_content 'Image tags'
+ first_tag = first('[data-testid="name"]')
+ expect(first_tag).to have_content 'latest'
end
it 'user removes a specific tag from container repository' do
diff --git a/spec/features/groups/members/list_members_spec.rb b/spec/features/groups/members/list_members_spec.rb
index b0a896ec8cb..b81949da85d 100644
--- a/spec/features/groups/members/list_members_spec.rb
+++ b/spec/features/groups/members/list_members_spec.rb
@@ -47,4 +47,46 @@ RSpec.describe 'Groups > Members > List members', :js do
expect(first_row).to have_selector('gl-emoji[data-name="smirk"]')
end
end
+
+ describe 'when user has 2FA enabled' do
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:user_with_2fa) { create(:user, :two_factor_via_otp) }
+
+ before do
+ group.add_guest(user_with_2fa)
+ end
+
+ it 'shows 2FA badge to user with "Owner" access level' do
+ group.add_owner(user1)
+
+ visit group_group_members_path(group)
+
+ expect(find_member_row(user_with_2fa)).to have_content('2FA')
+ end
+
+ it 'shows 2FA badge to admins' do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+
+ visit group_group_members_path(group)
+
+ expect(find_member_row(user_with_2fa)).to have_content('2FA')
+ end
+
+ it 'does not show 2FA badge to users with access level below "Owner"' do
+ group.add_maintainer(user1)
+
+ visit group_group_members_path(group)
+
+ expect(find_member_row(user_with_2fa)).not_to have_content('2FA')
+ end
+
+ it 'shows 2FA badge to themselves' do
+ sign_in(user_with_2fa)
+
+ visit group_group_members_path(group)
+
+ expect(find_member_row(user_with_2fa)).to have_content('2FA')
+ end
+ end
end
diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb
index c27d0afba6f..3b637a10abe 100644
--- a/spec/features/groups/members/manage_members_spec.rb
+++ b/spec/features/groups/members/manage_members_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'Groups > Members > Manage members' do
sign_in(user1)
end
- shared_examples 'includes the correct Invite Members link' do |should_include, should_not_include|
+ shared_examples 'includes the correct Invite link' do |should_include, should_not_include|
it 'includes either the form or the modal trigger' do
group.add_owner(user1)
@@ -31,15 +31,13 @@ RSpec.describe 'Groups > Members > Manage members' do
stub_feature_flags(invite_members_group_modal: true)
end
- it_behaves_like 'includes the correct Invite Members link', '.js-invite-members-trigger', '.invite-users-form'
+ it_behaves_like 'includes the correct Invite link', '.js-invite-members-trigger', '.invite-users-form'
+ it_behaves_like 'includes the correct Invite link', '.js-invite-group-trigger', '.invite-group-form'
end
context 'when Invite Members modal is disabled' do
- before do
- stub_feature_flags(invite_members_group_modal: false)
- end
-
- it_behaves_like 'includes the correct Invite Members link', '.invite-users-form', '.js-invite-members-trigger'
+ it_behaves_like 'includes the correct Invite link', '.invite-users-form', '.js-invite-members-trigger'
+ it_behaves_like 'includes the correct Invite link', '.invite-group-form', '.js-invite-group-trigger'
end
it 'update user to owner level', :js do
diff --git a/spec/features/groups/settings/user_searches_in_settings_spec.rb b/spec/features/groups/settings/user_searches_in_settings_spec.rb
new file mode 100644
index 00000000000..819d0c4faba
--- /dev/null
+++ b/spec/features/groups/settings/user_searches_in_settings_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User searches group settings', :js do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :repository, namespace: group) }
+
+ before do
+ group.add_owner(user)
+ sign_in(user)
+ end
+
+ context 'in general settings page' do
+ let(:visit_path) { edit_group_path(group) }
+
+ it_behaves_like 'can search settings with feature flag check', 'Naming', 'Permissions'
+ end
+
+ context 'in Repository page' do
+ before do
+ visit group_settings_repository_path(group)
+ end
+
+ it_behaves_like 'can search settings', 'Deploy tokens', 'Default initial branch name'
+ end
+
+ context 'in CI/CD page' do
+ before do
+ visit group_settings_ci_cd_path(group)
+ end
+
+ it_behaves_like 'can search settings', 'Variables', 'Runners'
+ end
+end
diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb
index 5067f11be67..4bcba4c21ed 100644
--- a/spec/features/groups/show_spec.rb
+++ b/spec/features/groups/show_spec.rb
@@ -163,7 +163,6 @@ RSpec.describe 'Group show page' do
let!(:project) { create(:project, namespace: group) }
before do
- stub_feature_flags(vue_notification_dropdown: false)
group.add_maintainer(maintainer)
sign_in(maintainer)
end
@@ -171,14 +170,14 @@ RSpec.describe 'Group show page' do
it 'is enabled by default' do
visit path
- expect(page).to have_selector('.notifications-btn:not(.disabled)', visible: true)
+ expect(page).to have_selector('[data-testid="notification-dropdown"] button:not(.disabled)')
end
it 'is disabled if emails are disabled' do
group.update_attribute(:emails_disabled, true)
visit path
- expect(page).to have_selector('.notifications-btn.disabled', visible: true)
+ expect(page).to have_selector('[data-testid="notification-dropdown"] .disabled')
end
end
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index c9a0844932a..28b22860f0a 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -143,7 +143,7 @@ RSpec.describe 'Group' do
end
end
- describe 'create a nested group', :js do
+ describe 'create a nested group' do
let_it_be(:group) { create(:group, path: 'foo') }
context 'as admin' do
@@ -153,13 +153,21 @@ RSpec.describe 'Group' do
visit new_group_path(group, parent_id: group.id)
end
- it 'creates a nested group' do
- fill_in 'Group name', with: 'bar'
- fill_in 'Group URL', with: 'bar'
- click_button 'Create group'
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it 'creates a nested group' do
+ fill_in 'Group name', with: 'bar'
+ fill_in 'Group URL', with: 'bar'
+ click_button 'Create group'
- expect(current_path).to eq(group_path('foo/bar'))
- expect(page).to have_content("Group 'bar' was successfully created.")
+ expect(current_path).to eq(group_path('foo/bar'))
+ expect(page).to have_content("Group 'bar' was successfully created.")
+ end
+ end
+
+ context 'when admin mode is disabled' do
+ it 'is not allowed' do
+ expect(page).to have_gitlab_http_status(:not_found)
+ end
end
end
diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
index d773126e00c..a4e9df604a9 100644
--- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
+++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
@@ -89,6 +89,8 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j
before do
page.within '.mr-widget-body' do
page.click_link 'Resolve all threads in new issue', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
+
+ wait_for_all_requests
end
end
diff --git a/spec/features/issues/csv_spec.rb b/spec/features/issues/csv_spec.rb
index c93693ec40a..d41a41c4383 100644
--- a/spec/features/issues/csv_spec.rb
+++ b/spec/features/issues/csv_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Issues csv' do
+RSpec.describe 'Issues csv', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let(:milestone) { create(:milestone, title: 'v1.0', project: project) }
@@ -17,7 +17,7 @@ RSpec.describe 'Issues csv' do
def request_csv(params = {})
visit project_issues_path(project, params)
page.within('.nav-controls') do
- click_on 'Export as CSV'
+ find('[data-testid="export-csv-button"]').click
end
click_on 'Export issues'
end
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index e2087868035..e6ebc37ba59 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'GFM autocomplete', :js do
let_it_be(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
let_it_be(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
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) }
@@ -16,6 +17,7 @@ RSpec.describe 'GFM autocomplete', :js do
before_all do
project.add_maintainer(user)
project.add_maintainer(user_xss)
+ project.add_maintainer(user2)
end
describe 'when tribute_autocomplete feature flag is off' do
@@ -29,289 +31,218 @@ RSpec.describe 'GFM autocomplete', :js do
end
it 'updates issue description with GFM reference' do
- find('.js-issuable-edit').click
+ click_button 'Edit title and description'
wait_for_requests
- simulate_input('#issue-description', "@#{user.name[0...3]}")
+ fill_in 'Description', with: "@#{user.name[0...3]}"
wait_for_requests
- find('.atwho-view .cur').click
+ find_highlighted_autocomplete_item.click
click_button 'Save changes'
wait_for_requests
- expect(find('.description')).to have_content(user.to_reference)
+ expect(find('.description')).to have_text(user.to_reference)
end
it 'opens quick action autocomplete when updating description' do
- find('.js-issuable-edit').click
+ click_button 'Edit title and description'
- find('#issue-description').native.send_keys('/')
+ fill_in 'Description', with: '/'
- expect(page).to have_selector('.atwho-container')
+ expect(find_autocomplete_menu).to be_visible
end
it 'opens autocomplete menu when field starts with text' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@')
- end
+ fill_in 'Comment', with: '@'
- expect(page).to have_selector('.atwho-container')
+ expect(find_autocomplete_menu).to be_visible
end
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)
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('#')
- end
+ fill_in 'Comment', with: '#'
wait_for_requests
- expect(page).to have_selector('.atwho-container')
-
- page.within '.atwho-container #at-view-issues' do
- expect(page.all('li').first.text).to include(issue_xss_title)
- end
+ 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
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@ev')
- end
+ fill_in 'Comment', with: '@ev'
wait_for_requests
- expect(page).to have_selector('.atwho-container')
-
- page.within '.atwho-container #at-view-users' do
- expect(find('li').text).to have_content(user_xss.username)
- end
+ 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)
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('%')
- end
+ fill_in 'Comment', with: '%'
wait_for_requests
- expect(page).to have_selector('.atwho-container')
-
- page.within '.atwho-container #at-view-milestones' do
- expect(find('li').text).to have_content('alert milestone')
- end
+ expect(find_autocomplete_menu).to have_text('alert milestone')
end
it 'doesnt open autocomplete menu character is prefixed with text' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('testing')
- find('#note-body').native.send_keys('@')
- end
+ fill_in 'Comment', with: 'testing@'
- expect(page).not_to have_selector('.atwho-view')
+ expect(page).not_to have_css('.atwho-view')
end
it 'doesnt select the first item for non-assignee dropdowns' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys(':')
- end
-
- expect(page).to have_selector('.atwho-container')
+ fill_in 'Comment', with: ':'
wait_for_requests
- expect(find('#at-view-58')).not_to have_selector('.cur:first-of-type')
+ expect(find_autocomplete_menu).not_to have_css('.cur')
end
it 'does not open autocomplete menu when ":" is prefixed by a number and letters' do
- note = find('#note-body')
-
# Number.
- page.within '.timeline-content-form' do
- note.native.send_keys('7:')
- end
-
- expect(page).not_to have_selector('.atwho-view')
+ fill_in 'Comment', with: '7:'
+ expect(page).not_to have_css('.atwho-view')
# ASCII letter.
- page.within '.timeline-content-form' do
- note.set('')
- note.native.send_keys('w:')
- end
-
- expect(page).not_to have_selector('.atwho-view')
+ fill_in 'Comment', with: 'w:'
+ expect(page).not_to have_css('.atwho-view')
# Non-ASCII letter.
- page.within '.timeline-content-form' do
- note.set('')
- note.native.send_keys('Ё:')
- end
-
- expect(page).not_to have_selector('.atwho-view')
+ fill_in 'Comment', with: 'Ё:'
+ expect(page).not_to have_css('.atwho-view')
end
it 'selects the first item for assignee dropdowns' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@')
- end
-
- expect(page).to have_selector('.atwho-container')
+ fill_in 'Comment', with: '@'
wait_for_requests
- expect(find('#at-view-users')).to have_selector('.cur:first-of-type')
+ expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
end
it 'includes items for assignee dropdowns with non-ASCII characters in name' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('')
- simulate_input('#note-body', "@#{user.name[0...8]}")
- end
-
- expect(page).to have_selector('.atwho-container')
+ fill_in 'Comment', with: "@#{user.name[0...8]}"
wait_for_requests
- expect(find('#at-view-users')).to have_content(user.name)
+ expect(find_autocomplete_menu).to have_text(user.name)
end
it 'searches across full name for assignees' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@speciąlsome')
- end
+ fill_in 'Comment', with: '@speciąlsome'
wait_for_requests
- expect(find('.atwho-view li', visible: true)).to have_content(user.name)
+ expect(find_highlighted_autocomplete_item).to have_text(user.name)
end
- it 'selects the first item for non-assignee dropdowns if a query is entered' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys(':1')
- 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
- expect(page).to have_selector('.atwho-container')
+ 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 'selects the first item for non-assignee dropdowns if a query is entered' do
+ fill_in 'Comment', with: ':1'
wait_for_requests
- expect(find('#at-view-58')).to have_selector('.cur:first-of-type')
+ expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
end
context 'if a selected value has special characters' do
it 'wraps the result in double quotes' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('')
- simulate_input('#note-body', "~#{label.title[0]}")
- end
+ fill_in 'Comment', with: "~#{label.title[0]}"
- label_item = find('.atwho-view li', text: label.title)
+ find_highlighted_autocomplete_item.click
- expect_to_wrap(true, label_item, note, label.title)
+ expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
end
it "shows dropdown after a new line" do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('test')
- note.native.send_keys(:enter)
- note.native.send_keys(:enter)
- note.native.send_keys('@')
- end
+ fill_in 'Comment', with: "test\n\n@"
- expect(page).to have_selector('.atwho-container')
+ expect(find_autocomplete_menu).to be_visible
end
it "does not show dropdown when preceded with a special character" do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys("@")
- end
-
- expect(page).to have_selector('.atwho-container')
-
- page.within '.timeline-content-form' do
- note.native.send_keys("@")
- end
+ fill_in 'Comment', with: '@@'
- expect(page).to have_selector('.atwho-container', visible: false)
- end
-
- it "does not throw an error if no labels exist" do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('~')
- end
-
- expect(page).to have_selector('.atwho-container', visible: false)
+ expect(page).not_to have_css('.atwho-view')
end
it 'doesn\'t wrap for assignee values' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys("@#{user.username[0]}")
- end
+ fill_in 'Comment', with: "@#{user.username[0]}"
- user_item = find('.atwho-view li', text: user.username)
+ find_highlighted_autocomplete_item.click
- expect_to_wrap(false, user_item, note, user.username)
+ expect(find_field('Comment').value).to have_text("@#{user.username}")
end
it 'doesn\'t wrap for emoji values' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys(":cartwheel_")
- end
+ fill_in 'Comment', with: ':cartwheel_'
- emoji_item = find('.atwho-view li', text: 'cartwheel_tone1')
+ find_highlighted_autocomplete_item.click
- expect_to_wrap(false, emoji_item, note, 'cartwheel_tone1')
+ expect(find_field('Comment').value).to have_text('cartwheel_tone1')
end
it 'doesn\'t open autocomplete after non-word character' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys("@#{user.username[0..2]}!")
- end
+ fill_in 'Comment', with: "@#{user.username[0..2]}!"
- expect(page).not_to have_selector('.atwho-view')
+ expect(page).not_to have_css('.atwho-view')
end
it 'doesn\'t open autocomplete if there is no space before' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys("hello:#{user.username[0..2]}")
- end
+ fill_in 'Comment', with: "hello:#{user.username[0..2]}"
- expect(page).not_to have_selector('.atwho-view')
+ expect(page).not_to have_css('.atwho-view')
end
it 'triggers autocomplete after selecting a quick action' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('/as')
- end
+ fill_in 'Comment', with: '/as'
- find('.atwho-view li', text: '/assign')
- note.native.send_keys(:tab)
+ find_highlighted_autocomplete_item.click
- user_item = find('.atwho-view li', text: user.username)
- expect(user_item).to have_content(user.username)
+ expect(find_autocomplete_menu).to have_text(user.username)
end
it 'does not limit quick actions autocomplete list to 5' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('/')
- end
+ fill_in 'Comment', with: '/'
- expect(page).to have_selector('.atwho-view li', minimum: 6, visible: true)
+ expect(find_autocomplete_menu).to have_css('li', minimum: 6)
end
end
@@ -328,30 +259,23 @@ RSpec.describe 'GFM autocomplete', :js do
it 'lists users who are currently not assigned to the issue when using /assign' do
visit project_issue_path(project, issue_assignee)
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('/as')
- end
-
- find('.atwho-view li', text: '/assign')
- note.native.send_keys(:tab)
+ fill_in 'Comment', with: '/as'
- wait_for_requests
+ find_highlighted_autocomplete_item.click
- expect(find('#at-view-users .atwho-view-ul')).not_to have_content(user.username)
- expect(find('#at-view-users .atwho-view-ul')).to have_content(unassigned_user.username)
+ expect(find_autocomplete_menu).not_to have_text(user.username)
+ expect(find_autocomplete_menu).to have_text(unassigned_user.username)
end
it 'shows dropdown on new issue form' do
visit new_project_issue_path(project)
- textarea = find('#issue_description')
- textarea.native.send_keys('/ass')
- find('.atwho-view li', text: '/assign')
- textarea.native.send_keys(:tab)
+ fill_in 'Description', with: '/ass'
- expect(find('#at-view-users .atwho-view-ul')).to have_content(unassigned_user.username)
- expect(find('#at-view-users .atwho-view-ul')).to have_content(user.username)
+ find_highlighted_autocomplete_item.click
+
+ expect(find_autocomplete_menu).to have_text(unassigned_user.username)
+ expect(find_autocomplete_menu).to have_text(user.username)
end
end
@@ -360,80 +284,62 @@ RSpec.describe 'GFM autocomplete', :js do
label_xss_title = 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:label, project: project, title: label_xss_title)
- note = find('#note-body')
-
- # It should show all the labels on "~".
- type(note, '~')
+ fill_in 'Comment', with: '~'
wait_for_requests
- page.within '.atwho-container #at-view-labels' do
- expect(find('.atwho-view-ul').text).to have_content('alert label')
- end
+ expect(find_autocomplete_menu).to have_text('alert label')
end
it 'allows colons when autocompleting scoped labels' do
create(:label, project: project, title: 'scoped:label')
- note = find('#note-body')
- type(note, '~scoped:')
+ fill_in 'Comment', with: '~scoped:'
wait_for_requests
- page.within '.atwho-container #at-view-labels' do
- expect(find('.atwho-view-ul').text).to have_content('scoped:label')
- end
+ expect(find_autocomplete_menu).to have_text('scoped:label')
end
it 'allows colons when autocompleting scoped labels with double colons' do
create(:label, project: project, title: 'scoped::label')
- note = find('#note-body')
- type(note, '~scoped::')
+ fill_in 'Comment', with: '~scoped::'
wait_for_requests
- page.within '.atwho-container #at-view-labels' do
- expect(find('.atwho-view-ul').text).to have_content('scoped::label')
- end
+ expect(find_autocomplete_menu).to have_text('scoped::label')
end
it 'allows spaces when autocompleting multi-word labels' do
create(:label, project: project, title: 'Accepting merge requests')
- note = find('#note-body')
- type(note, '~Accepting merge')
+ fill_in 'Comment', with: '~Accepting merge'
wait_for_requests
- page.within '.atwho-container #at-view-labels' do
- expect(find('.atwho-view-ul').text).to have_content('Accepting merge requests')
- end
+ expect(find_autocomplete_menu).to have_text('Accepting merge requests')
end
it 'only autocompletes the latest label' do
create(:label, project: project, title: 'Accepting merge requests')
create(:label, project: project, title: 'Accepting job applicants')
- note = find('#note-body')
- type(note, '~Accepting merge requests foo bar ~Accepting job')
+ fill_in 'Comment', with: '~Accepting merge requests foo bar ~Accepting job'
wait_for_requests
- page.within '.atwho-container #at-view-labels' do
- expect(find('.atwho-view-ul').text).to have_content('Accepting job applicants')
- end
+ expect(find_autocomplete_menu).to have_text('Accepting job applicants')
end
it 'does not autocomplete labels if no tilde is typed' do
create(:label, project: project, title: 'Accepting merge requests')
- note = find('#note-body')
- type(note, 'Accepting merge')
+ fill_in 'Comment', with: 'Accepting merge'
wait_for_requests
- expect(page).not_to have_css('.atwho-container #at-view-labels')
+ expect(page).not_to have_css('.atwho-view')
end
end
@@ -443,7 +349,7 @@ RSpec.describe 'GFM autocomplete', :js do
# This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729
it 'keeps autocomplete key listeners' do
visit project_issue_path(project, issue)
- note = find('#note-body')
+ note = find_field('Comment')
start_comment_with_emoji(note, '.atwho-view li')
@@ -459,17 +365,11 @@ RSpec.describe 'GFM autocomplete', :js do
shared_examples 'autocomplete suggestions' do
it 'suggests objects correctly' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys(object.class.reference_prefix)
- end
-
- page.within '.atwho-container' do
- expect(page).to have_content(object.title)
+ fill_in 'Comment', with: object.class.reference_prefix
- find('ul li').click
- end
+ find_autocomplete_menu.find('li').click
- expect(find('.new-note #note-body').value).to include(expected_body)
+ expect(find_field('Comment').value).to have_text(expected_body)
end
end
@@ -502,10 +402,40 @@ RSpec.describe 'GFM autocomplete', :js do
end
context 'milestone' do
- let!(:object) { create(:milestone, project: project) }
- let(:expected_body) { object.to_reference }
+ 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_behaves_like 'autocomplete suggestions'
+ before do
+ fill_in 'Comment', with: '/milestone %'
+
+ wait_for_requests
+ 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
+
+ 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
+
+ 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
end
@@ -520,237 +450,160 @@ RSpec.describe 'GFM autocomplete', :js do
end
it 'updates issue description with GFM reference' do
- find('.js-issuable-edit').click
+ click_button 'Edit title and description'
wait_for_requests
- simulate_input('#issue-description', "@#{user.name[0...3]}")
+ fill_in 'Description', with: "@#{user.name[0...3]}"
wait_for_requests
- find('.tribute-container .highlight', visible: true).click
+ find_highlighted_tribute_autocomplete_menu.click
click_button 'Save changes'
wait_for_requests
- expect(find('.description')).to have_content(user.to_reference)
+ expect(find('.description')).to have_text(user.to_reference)
end
it 'opens autocomplete menu when field starts with text' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@')
- end
+ fill_in 'Comment', with: '@'
- expect(page).to have_selector('.tribute-container', visible: true)
+ expect(find_tribute_autocomplete_menu).to be_visible
end
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)
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('#')
- end
+ fill_in 'Comment', with: '#'
wait_for_requests
- expect(page).to have_selector('.tribute-container', visible: true)
-
- page.within '.tribute-container ul' do
- expect(page.all('li').first.text).to include(issue_xss_title)
- end
+ 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
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@ev')
- end
+ fill_in 'Comment', with: '@ev'
wait_for_requests
- expect(page).to have_selector('.tribute-container', visible: true)
-
- expect(find('.tribute-container ul', visible: true)).to have_text(user_xss.username)
+ 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)
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('%')
- end
+ fill_in 'Comment', with: '%'
wait_for_requests
- expect(page).to have_selector('.tribute-container', visible: true)
-
- expect(find('.tribute-container ul', visible: true)).to have_text('alert milestone')
+ expect(find_tribute_autocomplete_menu).to have_text('alert milestone')
end
it 'does not open autocomplete menu when trigger character is prefixed with text' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('testing')
- find('#note-body').native.send_keys('@')
- end
+ fill_in 'Comment', with: 'testing@'
- expect(page).not_to have_selector('.tribute-container', visible: true)
+ expect(page).not_to have_css('.tribute-container')
end
it 'does not open autocomplete menu when ":" is prefixed by a number and letters' do
- note = find('#note-body')
-
# Number.
- page.within '.timeline-content-form' do
- note.native.send_keys('7:')
- end
-
- expect(page).not_to have_selector('.tribute-container', visible: true)
+ fill_in 'Comment', with: '7:'
+ expect(page).not_to have_css('.tribute-container')
# ASCII letter.
- page.within '.timeline-content-form' do
- note.set('')
- note.native.send_keys('w:')
- end
-
- expect(page).not_to have_selector('.tribute-container', visible: true)
+ fill_in 'Comment', with: 'w:'
+ expect(page).not_to have_css('.tribute-container')
# Non-ASCII letter.
- page.within '.timeline-content-form' do
- note.set('')
- note.native.send_keys('Ё:')
- end
-
- expect(page).not_to have_selector('.tribute-container', visible: true)
+ fill_in 'Comment', with: 'Ё:'
+ expect(page).not_to have_css('.tribute-container')
end
it 'selects the first item for assignee dropdowns' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@')
- end
-
- expect(page).to have_selector('.tribute-container', visible: true)
+ fill_in 'Comment', with: '@'
wait_for_requests
- expect(find('.tribute-container ul', visible: true)).to have_selector('.highlight:first-of-type')
+ expect(find_tribute_autocomplete_menu).to have_css('.highlight:first-of-type')
end
it 'includes items for assignee dropdowns with non-ASCII characters in name' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('')
- simulate_input('#note-body', "@#{user.name[0...8]}")
- end
-
- expect(page).to have_selector('.tribute-container', visible: true)
+ fill_in 'Comment', with: "@#{user.name[0...8]}"
wait_for_requests
- expect(find('.tribute-container ul', visible: true)).to have_content(user.name)
+ expect(find_tribute_autocomplete_menu).to have_text(user.name)
end
it 'selects the first item for non-assignee dropdowns if a query is entered' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys(':1')
- end
+ fill_in 'Comment', with: ':1'
wait_for_requests
- expect(find('.tribute-container ul', visible: true)).to have_selector('.highlight:first-of-type')
+ expect(find_tribute_autocomplete_menu).to have_css('.highlight:first-of-type')
end
context 'when autocompleting for groups' do
it 'shows the group when searching for the name of the group' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@mygroup')
- end
+ fill_in 'Comment', with: '@mygroup'
- expect(find('.tribute-container ul', visible: true)).to have_text('My group')
+ expect(find_tribute_autocomplete_menu).to have_text('My group')
end
it 'does not show the group when searching for the name of the parent of the group' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@ancestor')
- end
+ fill_in 'Comment', with: '@ancestor'
- expect(find('.tribute-container ul', visible: true)).not_to have_text('My group')
+ expect(find_tribute_autocomplete_menu).not_to have_text('My group')
end
end
context 'if a selected value has special characters' do
it 'wraps the result in double quotes' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('')
- simulate_input('#note-body', "~#{label.title[0]}")
- end
+ fill_in 'Comment', with: "~#{label.title[0]}"
- label_item = find('.tribute-container ul', text: label.title, visible: true)
+ find_highlighted_tribute_autocomplete_menu.click
- expect_to_wrap(true, label_item, note, label.title)
+ expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
end
it "shows dropdown after a new line" do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('test')
- note.native.send_keys(:enter)
- note.native.send_keys(:enter)
- note.native.send_keys('@')
- end
-
- expect(page).to have_selector('.tribute-container', visible: true)
- end
-
- it "does not throw an error if no labels exist" do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('~')
- end
+ fill_in 'Comment', with: "test\n\n@"
- expect(page).to have_selector('.tribute-container', visible: false)
+ expect(find_tribute_autocomplete_menu).to be_visible
end
it 'doesn\'t wrap for assignee values' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys("@#{user.username[0]}")
- end
+ fill_in 'Comment', with: "@#{user.username[0..2]}"
- user_item = find('.tribute-container ul', text: user.username, visible: true)
+ find_highlighted_tribute_autocomplete_menu.click
- expect_to_wrap(false, user_item, note, user.username)
+ expect(find_field('Comment').value).to have_text("@#{user.username}")
end
it 'does not wrap for emoji values' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys(":cartwheel_")
- end
+ fill_in 'Comment', with: ':cartwheel_'
- emoji_item = first('.tribute-container li', text: 'cartwheel_tone1', visible: true)
+ find_highlighted_tribute_autocomplete_menu.click
- expect_to_wrap(false, emoji_item, note, 'cartwheel_tone1')
+ expect(find_field('Comment').value).to have_text('cartwheel_tone1')
end
it 'does not open autocomplete if there is no space before' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys("hello:#{user.username[0..2]}")
- end
+ fill_in 'Comment', with: "hello:#{user.username[0..2]}"
- expect(page).not_to have_selector('.tribute-container')
+ expect(page).not_to have_css('.tribute-container')
end
it 'autocompletes for quick actions' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('/as')
- wait_for_requests
- note.native.send_keys(:tab)
- end
+ fill_in 'Comment', with: '/as'
+
+ find_highlighted_tribute_autocomplete_menu.click
- expect(note.value).to have_text('/assign')
+ expect(find_field('Comment').value).to have_text('/assign')
end
end
@@ -767,37 +620,33 @@ RSpec.describe 'GFM autocomplete', :js do
it 'lists users who are currently not assigned to the issue when using /assign' do
visit project_issue_path(project, issue_assignee)
- note = find('#note-body')
- page.within '.timeline-content-form' do
- 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
- end
+ 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-container ul', visible: true)).not_to have_content(user.username)
- expect(find('.tribute-container ul', visible: true)).to have_content(unassigned_user.username)
+ expect(find_tribute_autocomplete_menu).not_to have_text(user.username)
+ expect(find_tribute_autocomplete_menu).to have_text(unassigned_user.username)
end
it 'lists users who are currently not assigned to the issue when using /assign on the second line' do
visit project_issue_path(project, issue_assignee)
- note = find('#note-body')
- page.within '.timeline-content-form' do
- 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
- end
+ 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-container ul', visible: true)).not_to have_content(user.username)
- expect(find('.tribute-container ul', visible: true)).to have_content(unassigned_user.username)
+ expect(find_tribute_autocomplete_menu).not_to have_text(user.username)
+ expect(find_tribute_autocomplete_menu).to have_text(unassigned_user.username)
end
end
@@ -806,72 +655,65 @@ RSpec.describe 'GFM autocomplete', :js do
label_xss_title = 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:label, project: project, title: label_xss_title)
- note = find('#note-body')
-
- # It should show all the labels on "~".
- type(note, '~')
+ fill_in 'Comment', with: '~'
wait_for_requests
- expect(find('.tribute-container ul', visible: true).text).to have_content('alert label')
+ expect(find_tribute_autocomplete_menu).to have_text('alert label')
end
it 'allows colons when autocompleting scoped labels' do
create(:label, project: project, title: 'scoped:label')
- note = find('#note-body')
- type(note, '~scoped:')
+ fill_in 'Comment', with: '~scoped:'
wait_for_requests
- expect(find('.tribute-container ul', visible: true).text).to have_content('scoped:label')
+ expect(find_tribute_autocomplete_menu).to have_text('scoped:label')
end
it 'allows colons when autocompleting scoped labels with double colons' do
create(:label, project: project, title: 'scoped::label')
- note = find('#note-body')
- type(note, '~scoped::')
+ fill_in 'Comment', with: '~scoped::'
wait_for_requests
- expect(find('.tribute-container ul', visible: true).text).to have_content('scoped::label')
+ expect(find_tribute_autocomplete_menu).to have_text('scoped::label')
end
it 'autocompletes multi-word labels' do
create(:label, project: project, title: 'Accepting merge requests')
- note = find('#note-body')
- type(note, '~Acceptingmerge')
+ fill_in 'Comment', with: '~Acceptingmerge'
wait_for_requests
- expect(find('.tribute-container ul', visible: true).text).to have_content('Accepting merge requests')
+ expect(find_tribute_autocomplete_menu).to have_text('Accepting merge requests')
end
it 'only autocompletes the latest label' do
create(:label, project: project, title: 'documentation')
create(:label, project: project, title: 'feature')
- note = find('#note-body')
- type(note, '~documentation foo bar ~feat')
- note.native.send_keys(:right)
+ fill_in 'Comment', with: '~documentation foo bar ~feat'
+ # Invoke autocompletion
+ find_field('Comment').native.send_keys(:right)
wait_for_requests
- expect(find('.tribute-container ul', visible: true).text).to have_content('feature')
- expect(find('.tribute-container ul', visible: true).text).not_to have_content('documentation')
+ expect(find_tribute_autocomplete_menu).to have_text('feature')
+ expect(find_tribute_autocomplete_menu).not_to have_text('documentation')
end
it 'does not autocomplete labels if no tilde is typed' do
create(:label, project: project, title: 'documentation')
- note = find('#note-body')
- type(note, 'document')
+ fill_in 'Comment', with: 'document'
wait_for_requests
- expect(page).not_to have_selector('.tribute-container')
+ expect(page).not_to have_css('.tribute-container')
end
end
@@ -881,7 +723,7 @@ RSpec.describe 'GFM autocomplete', :js do
# This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729
it 'keeps autocomplete key listeners' do
visit project_issue_path(project, issue)
- note = find('#note-body')
+ note = find_field('Comment')
start_comment_with_emoji(note, '.tribute-container li')
@@ -897,17 +739,11 @@ RSpec.describe 'GFM autocomplete', :js do
shared_examples 'autocomplete suggestions' do
it 'suggests objects correctly' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys(object.class.reference_prefix)
- end
-
- page.within '.tribute-container' do
- expect(page).to have_content(object.title)
+ fill_in 'Comment', with: object.class.reference_prefix
- find('ul li').click
- end
+ find_tribute_autocomplete_menu.find('li').click
- expect(find('.new-note #note-body').value).to include(expected_body)
+ expect(find_field('Comment').value).to have_text(expected_body)
end
end
@@ -949,42 +785,6 @@ RSpec.describe 'GFM autocomplete', :js do
private
- def expect_to_wrap(should_wrap, item, note, value)
- expect(item).to have_content(value)
- expect(item).not_to have_content("\"#{value}\"")
-
- item.click
-
- if should_wrap
- expect(note.value).to include("\"#{value}\"")
- else
- expect(note.value).not_to include("\"#{value}\"")
- end
- end
-
- def expect_labels(shown: nil, not_shown: nil)
- page.within('.atwho-container') do
- if shown
- expect(page).to have_selector('.atwho-view li', count: shown.size)
- shown.each { |label| expect(page).to have_content(label.title) }
- end
-
- if not_shown
- expect(page).not_to have_selector('.atwho-view li') unless shown
- not_shown.each { |label| expect(page).not_to have_content(label.title) }
- end
- end
- end
-
- # `note` is a textarea where the given text should be typed.
- # We don't want to find it each time this function gets called.
- def type(note, text)
- page.within('.timeline-content-form') do
- note.set('')
- note.native.send_keys(text)
- end
- end
-
def start_comment_with_emoji(note, selector)
note.native.send_keys('Hello :10')
@@ -994,9 +794,7 @@ RSpec.describe 'GFM autocomplete', :js do
end
def start_and_cancel_discussion
- click_button('Reply...')
-
- fill_in('note_note', with: 'Whoops!')
+ fill_in('Reply to comment', with: 'Whoops!')
page.accept_alert 'Are you sure you want to cancel creating this comment?' do
click_button('Cancel')
@@ -1004,4 +802,20 @@ RSpec.describe 'GFM autocomplete', :js do
wait_for_requests
end
+
+ def find_autocomplete_menu
+ find('.atwho-view ul', visible: true)
+ end
+
+ 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/issue_state_spec.rb b/spec/features/issues/issue_state_spec.rb
index 409f498798b..d5a115433aa 100644
--- a/spec/features/issues/issue_state_spec.rb
+++ b/spec/features/issues/issue_state_spec.rb
@@ -42,15 +42,9 @@ RSpec.describe 'issue state', :js do
end
describe 'when open', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/297348' do
- let(:open_issue) { create(:issue, project: project) }
-
- it_behaves_like 'page with comment and close button', 'Close issue' do
- def setup
- visit project_issue_path(project, open_issue)
- end
- end
-
context 'when clicking the top `Close issue` button', :aggregate_failures do
+ let(:open_issue) { create(:issue, project: project) }
+
before do
visit project_issue_path(project, open_issue)
end
@@ -59,8 +53,9 @@ RSpec.describe 'issue state', :js do
end
context 'when clicking the bottom `Close issue` button', :aggregate_failures do
+ let(:open_issue) { create(:issue, project: project) }
+
before do
- stub_feature_flags(remove_comment_close_reopen: false)
visit project_issue_path(project, open_issue)
end
@@ -69,15 +64,9 @@ RSpec.describe 'issue state', :js do
end
describe 'when closed', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/297201' do
- let(:closed_issue) { create(:issue, project: project, state: 'closed') }
-
- it_behaves_like 'page with comment and close button', 'Reopen issue' do
- def setup
- visit project_issue_path(project, closed_issue)
- end
- end
-
context 'when clicking the top `Reopen issue` button', :aggregate_failures do
+ let(:closed_issue) { create(:issue, project: project, state: 'closed') }
+
before do
visit project_issue_path(project, closed_issue)
end
@@ -86,8 +75,9 @@ RSpec.describe 'issue state', :js do
end
context 'when clicking the bottom `Reopen issue` button', :aggregate_failures do
+ let(:closed_issue) { create(:issue, project: project, state: 'closed') }
+
before do
- stub_feature_flags(remove_comment_close_reopen: false)
visit project_issue_path(project, closed_issue)
end
diff --git a/spec/features/issues/service_desk_spec.rb b/spec/features/issues/service_desk_spec.rb
index 02804d84a21..75ea8c14f7f 100644
--- a/spec/features/issues/service_desk_spec.rb
+++ b/spec/features/issues/service_desk_spec.rb
@@ -49,8 +49,8 @@ RSpec.describe 'Service Desk Issue Tracker', :js do
aggregate_failures do
expect(page).to have_css('.empty-state')
expect(page).to have_text('Use Service Desk to connect with your users')
- expect(page).to have_link('Read more', href: help_page_path('user/project/service_desk'))
- expect(page).not_to have_link('Turn on Service Desk')
+ expect(page).to have_link('Learn more.', href: help_page_path('user/project/service_desk'))
+ expect(page).not_to have_link('Enable Service Desk')
expect(page).to have_content(project.service_desk_address)
end
end
@@ -68,8 +68,8 @@ RSpec.describe 'Service Desk Issue Tracker', :js do
aggregate_failures do
expect(page).to have_css('.empty-state')
expect(page).to have_text('Use Service Desk to connect with your users')
- expect(page).to have_link('Read more', href: help_page_path('user/project/service_desk'))
- expect(page).not_to have_link('Turn on Service Desk')
+ expect(page).to have_link('Learn more.', href: help_page_path('user/project/service_desk'))
+ expect(page).not_to have_link('Enable Service Desk')
expect(page).not_to have_content(project.service_desk_address)
end
end
@@ -91,8 +91,8 @@ RSpec.describe 'Service Desk Issue Tracker', :js do
it 'displays the small info box, documentation, a button to configure service desk, and the address' do
aggregate_failures do
expect(page).to have_css('.non-empty-state')
- expect(page).to have_link('Read more', href: help_page_path('user/project/service_desk'))
- expect(page).not_to have_link('Turn on Service Desk')
+ expect(page).to have_link('Learn more.', href: help_page_path('user/project/service_desk'))
+ expect(page).not_to have_link('Enable Service Desk')
expect(page).to have_content(project.service_desk_address)
end
end
@@ -156,8 +156,8 @@ RSpec.describe 'Service Desk Issue Tracker', :js do
aggregate_failures do
expect(page).to have_css('.empty-state')
expect(page).to have_text('Service Desk is not supported')
- expect(page).to have_text('In order to enable Service Desk for your instance, you must first set up incoming email.')
- expect(page).to have_link('More information', href: help_page_path('administration/incoming_email', anchor: 'set-it-up'))
+ expect(page).to have_text('To enable Service Desk on this instance, an instance administrator must first set up incoming email.')
+ expect(page).to have_link('Learn more.', href: help_page_path('administration/incoming_email', anchor: 'set-it-up'))
end
end
end
diff --git a/spec/features/issues/user_interacts_with_awards_spec.rb b/spec/features/issues/user_interacts_with_awards_spec.rb
index fec603e466a..1c7bc5f239f 100644
--- a/spec/features/issues/user_interacts_with_awards_spec.rb
+++ b/spec/features/issues/user_interacts_with_awards_spec.rb
@@ -135,11 +135,9 @@ RSpec.describe 'User interacts with awards' do
it 'allows adding a new emoji' do
page.within('.note-actions') do
- find('a.js-add-award').click
- end
- page.within('.emoji-menu-content') do
- find('gl-emoji[data-name="8ball"]').click
+ find('.note-emoji-button').click
end
+ find('gl-emoji[data-name="8ball"]').click
wait_for_requests
page.within('.note-awards') do
@@ -157,7 +155,7 @@ RSpec.describe 'User interacts with awards' do
end
page.within('.note-actions') do
- expect(page).not_to have_css('a.js-add-award')
+ expect(page).not_to have_css('.btn.js-add-award')
end
end
diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb
index aeb42cc2edb..0a2f81986be 100644
--- a/spec/features/labels_hierarchy_spec.rb
+++ b/spec/features/labels_hierarchy_spec.rb
@@ -160,7 +160,7 @@ RSpec.describe 'Labels Hierarchy', :js do
find('a.label-item', text: parent_group_label.title).click
find('a.label-item', text: project_label_1.title).click
- find('.btn-success').click
+ find('.btn-confirm').click
expect(page.find('.issue-details h2.title')).to have_content('new created issue')
expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title)
diff --git a/spec/features/markdown/markdown_spec.rb b/spec/features/markdown/markdown_spec.rb
index 8e28f89f49e..e84b300a748 100644
--- a/spec/features/markdown/markdown_spec.rb
+++ b/spec/features/markdown/markdown_spec.rb
@@ -290,7 +290,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures do
path = 'images/example.jpg'
gitaly_wiki_file = Gitlab::GitalyClient::WikiFile.new(path: path)
- expect(@wiki).to receive(:find_file).with(path).and_return(Gitlab::Git::WikiFile.new(gitaly_wiki_file))
+ expect(@wiki).to receive(:find_file).with(path, load_content: false).and_return(Gitlab::Git::WikiFile.new(gitaly_wiki_file))
allow(@wiki).to receive(:wiki_base_path) { '/namespace1/gitlabhq/wikis' }
@html = markdown(@feat.raw_markdown, { pipeline: :wiki, wiki: @wiki, page_slug: @wiki_page.slug })
diff --git a/spec/features/markdown/math_spec.rb b/spec/features/markdown/math_spec.rb
index e5fb9131ce0..441cff7045f 100644
--- a/spec/features/markdown/math_spec.rb
+++ b/spec/features/markdown/math_spec.rb
@@ -39,4 +39,20 @@ RSpec.describe 'Math rendering', :js do
expect(page).to have_selector('.katex-html a', text: 'Gitlab')
end
end
+
+ it 'renders lazy load button' do
+ description = <<~MATH
+ ```math
+ \Huge \sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+ ```
+ MATH
+
+ issue = create(:issue, project: project, description: description)
+
+ visit project_issue_path(project, issue)
+
+ page.within '.description > .md' do
+ expect(page).to have_selector('.js-lazy-render-math')
+ end
+ end
end
diff --git a/spec/features/merge_request/batch_comments_spec.rb b/spec/features/merge_request/batch_comments_spec.rb
index c8fc23bebf9..25f2707146d 100644
--- a/spec/features/merge_request/batch_comments_spec.rb
+++ b/spec/features/merge_request/batch_comments_spec.rb
@@ -223,7 +223,7 @@ end
def write_reply_to_discussion(button_text: 'Start a review', text: 'Line is wrong', resolve: false, unresolve: false)
page.within(first('.diff-files-holder .discussion-reply-holder')) do
- click_button('Reply...')
+ find_field('Reply…', match: :first).click
fill_in('note_note', with: text)
diff --git a/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb b/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb
index ab3ef7c1ac0..70951982c22 100644
--- a/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb
+++ b/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb
@@ -12,15 +12,9 @@ RSpec.describe 'User closes/reopens a merge request', :js, quarantine: 'https://
end
describe 'when open' do
- let(:open_merge_request) { create(:merge_request, source_project: project, target_project: project) }
-
- it_behaves_like 'page with comment and close button', 'Close merge request' do
- def setup
- visit merge_request_path(open_merge_request)
- end
- end
-
context 'when clicking the top `Close merge request` link', :aggregate_failures do
+ let(:open_merge_request) { create(:merge_request, source_project: project, target_project: project) }
+
before do
visit merge_request_path(open_merge_request)
end
@@ -40,8 +34,9 @@ RSpec.describe 'User closes/reopens a merge request', :js, quarantine: 'https://
end
context 'when clicking the bottom `Close merge request` button', :aggregate_failures do
+ let(:open_merge_request) { create(:merge_request, source_project: project, target_project: project) }
+
before do
- stub_feature_flags(remove_comment_close_reopen: false)
visit merge_request_path(open_merge_request)
end
@@ -61,22 +56,9 @@ RSpec.describe 'User closes/reopens a merge request', :js, quarantine: 'https://
end
describe 'when closed' do
- let(:closed_merge_request) { create(:merge_request, source_project: project, target_project: project, state: 'closed') }
-
- it_behaves_like 'page with comment and close button', 'Close merge request' do
- def setup
- visit merge_request_path(closed_merge_request)
-
- within '.detail-page-header' do
- click_button 'Toggle dropdown'
- click_link 'Reopen merge request'
- end
-
- wait_for_requests
- end
- end
-
context 'when clicking the top `Reopen merge request` link', :aggregate_failures do
+ let(:closed_merge_request) { create(:merge_request, source_project: project, target_project: project, state: 'closed') }
+
before do
visit merge_request_path(closed_merge_request)
end
@@ -96,8 +78,9 @@ RSpec.describe 'User closes/reopens a merge request', :js, quarantine: 'https://
end
context 'when clicking the bottom `Reopen merge request` button', :aggregate_failures do
+ let(:closed_merge_request) { create(:merge_request, source_project: project, target_project: project, state: 'closed') }
+
before do
- stub_feature_flags(remove_comment_close_reopen: false)
visit merge_request_path(closed_merge_request)
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 794dfd7c8da..163ce10132e 100644
--- a/spec/features/merge_request/user_posts_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb
@@ -192,7 +192,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
it 'adds as discussion' do
should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'), asset_form_reset: false)
expect(page).to have_css('.notes_holder .note.note-discussion', count: 1)
- expect(page).to have_button('Reply...')
+ expect(page).to have_field('Reply…')
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 e629bc0dc53..3099a893dc2 100644
--- a/spec/features/merge_request/user_posts_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_notes_spec.rb
@@ -44,7 +44,10 @@ RSpec.describe 'Merge request > User posts notes', :js do
it 'has enable submit button, preview button and saves content to local storage' do
page.within('.js-main-target-form') do
- expect(page).not_to have_css('.js-comment-button[disabled]')
+ page.within('[data-testid="comment-button"]') do
+ expect(page).to have_css('.split-content-button')
+ expect(page).not_to have_css('.split-content-button[disabled]')
+ end
expect(page).to have_css('.js-md-preview-button', visible: true)
end
diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
index b86586d53e2..caa04059469 100644
--- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
+++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
@@ -149,7 +149,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
it 'allows user to comment' do
page.within '.diff-content' do
- click_button 'Reply...'
+ find_field('Reply…').click
find(".js-unresolve-checkbox").set false
find('.js-note-text').set 'testing'
@@ -179,7 +179,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
it 'allows user to comment & unresolve thread' do
page.within '.diff-content' do
- click_button 'Reply...'
+ find_field('Reply…').click
find('.js-note-text').set 'testing'
@@ -208,7 +208,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
it 'allows user to comment & resolve thread' do
page.within '.diff-content' do
- click_button 'Reply...'
+ find_field('Reply…').click
find('.js-note-text').set 'testing'
@@ -442,7 +442,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
it 'allows user to comment & resolve thread' do
page.within '.diff-content' do
- click_button 'Reply...'
+ find_field('Reply…').click
find('.js-note-text').set 'testing'
@@ -461,7 +461,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
page.within '.diff-content' do
click_button 'Resolve thread'
- click_button 'Reply...'
+ find_field('Reply…').click
find('.js-note-text').set 'testing'
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 d15d5b3bc73..90cdc28d1bd 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
@@ -37,7 +37,7 @@ RSpec.describe 'Merge request > User sees avatars on diff notes', :js do
end
it 'does not render avatars after commenting on discussion tab' do
- click_button 'Reply...'
+ find_field('Reply…').click
page.within('.js-discussion-note-form') do
find('.note-textarea').native.send_keys('Test comment')
@@ -132,7 +132,7 @@ RSpec.describe 'Merge request > User sees avatars on diff notes', :js do
end
it 'adds avatar when commenting' do
- click_button 'Reply...'
+ find_field('Reply…', match: :first).click
page.within '.js-discussion-note-form' do
find('.js-note-text').native.send_keys('Test')
@@ -151,7 +151,7 @@ RSpec.describe 'Merge request > User sees avatars on diff notes', :js do
it 'adds multiple comments' do
3.times do
- click_button 'Reply...'
+ find_field('Reply…', match: :first).click
page.within '.js-discussion-note-form' do
find('.js-note-text').native.send_keys('Test')
diff --git a/spec/features/merge_request/user_sees_discussions_spec.rb b/spec/features/merge_request/user_sees_discussions_spec.rb
index 289c861739f..d79763ba5e0 100644
--- a/spec/features/merge_request/user_sees_discussions_spec.rb
+++ b/spec/features/merge_request/user_sees_discussions_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe 'Merge request > User sees threads', :js do
it 'can be replied to' do
within(".discussion[data-discussion-id='#{discussion_id}']") do
- click_button 'Reply...'
+ find_field('Reply…').click
fill_in 'note[note]', with: 'Test!'
click_button 'Comment'
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 708ce53b4fe..ad0e9b48903 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
@@ -26,6 +26,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
end
before do
+ stub_feature_flags(new_pipelines_table: false)
stub_application_setting(auto_devops_enabled: false)
stub_ci_pipeline_yaml_file(YAML.dump(config))
project.add_maintainer(user)
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 0854a8b9fb7..05fa5459e06 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -651,7 +651,6 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
within(".js-report-section-container") do
expect(page).to have_content('rspec found 1 failed out of 1 total test')
expect(page).to have_content('junit found no changed test results out of 1 total test')
- expect(page).not_to have_content('New')
expect(page).to have_content('Test#sum when a is 1 and b is 3 returns summary')
end
end
@@ -792,7 +791,6 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
within(".js-report-section-container") do
expect(page).to have_content('rspec found 1 error out of 1 total test')
expect(page).to have_content('junit found no changed test results out of 1 total test')
- expect(page).not_to have_content('New')
expect(page).to have_content('Test#sum when a is 4 and b is 4 returns summary')
end
end
diff --git a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
index 1ef6d2a1068..c0dc2ec3baf 100644
--- a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
+++ b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
@@ -9,166 +9,149 @@ RSpec.describe 'Merge request < User sees mini pipeline graph', :js do
let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: 'master', status: 'running', sha: project.commit.id) }
let(:build) { create(:ci_build, pipeline: pipeline, stage: 'test') }
- shared_examples 'mini pipeline renders' do |ci_mini_pipeline_gl_dropdown_enabled|
- before do
- build.run
- build.trace.set('hello')
- sign_in(user)
- stub_feature_flags(ci_mini_pipeline_gl_dropdown: ci_mini_pipeline_gl_dropdown_enabled)
- visit_merge_request
- end
+ dropdown_selector = '[data-testid="mini-pipeline-graph-dropdown"]'
- let_it_be(:dropdown_toggle_selector) do
- if ci_mini_pipeline_gl_dropdown_enabled
- '[data-testid="mini-pipeline-graph-dropdown"] .dropdown-toggle'
- else
- '[data-testid="mini-pipeline-graph-dropdown-toggle"]'
- end
- end
+ before do
+ build.run
+ build.trace.set('hello')
+ sign_in(user)
+ visit_merge_request
+ end
- def visit_merge_request(format: :html, serializer: nil)
- visit project_merge_request_path(project, merge_request, format: format, serializer: serializer)
- end
+ def visit_merge_request(format: :html, serializer: nil)
+ visit project_merge_request_path(project, merge_request, format: format, serializer: serializer)
+ end
- it 'displays a mini pipeline graph' do
- expect(page).to have_selector('.mr-widget-pipeline-graph')
- end
+ it 'displays a mini pipeline graph' do
+ expect(page).to have_selector('.mr-widget-pipeline-graph')
+ end
- context 'as json' do
- let(:artifacts_file1) { fixture_file_upload(File.join('spec/fixtures/banana_sample.gif'), 'image/gif') }
- let(:artifacts_file2) { fixture_file_upload(File.join('spec/fixtures/dk.png'), 'image/png') }
+ context 'as json' do
+ let(:artifacts_file1) { fixture_file_upload(File.join('spec/fixtures/banana_sample.gif'), 'image/gif') }
+ let(:artifacts_file2) { fixture_file_upload(File.join('spec/fixtures/dk.png'), 'image/png') }
- before do
- job = create(:ci_build, :success, :trace_artifact, pipeline: pipeline)
- create(:ci_job_artifact, :archive, file: artifacts_file1, job: job)
- create(:ci_build, :manual, pipeline: pipeline, when: 'manual')
- end
+ before do
+ job = create(:ci_build, :success, :trace_artifact, pipeline: pipeline)
+ create(:ci_job_artifact, :archive, file: artifacts_file1, job: job)
+ create(:ci_build, :manual, pipeline: pipeline, when: 'manual')
+ end
- # TODO: https://gitlab.com/gitlab-org/gitlab-foss/issues/48034
- xit 'avoids repeated database queries' do
- before = ActiveRecord::QueryRecorder.new { visit_merge_request(format: :json, serializer: 'widget') }
+ # TODO: https://gitlab.com/gitlab-org/gitlab-foss/issues/48034
+ xit 'avoids repeated database queries' do
+ before = ActiveRecord::QueryRecorder.new { visit_merge_request(format: :json, serializer: 'widget') }
- job = create(:ci_build, :success, :trace_artifact, pipeline: pipeline)
- create(:ci_job_artifact, :archive, file: artifacts_file2, job: job)
- create(:ci_build, :manual, pipeline: pipeline, when: 'manual')
+ job = create(:ci_build, :success, :trace_artifact, pipeline: pipeline)
+ create(:ci_job_artifact, :archive, file: artifacts_file2, job: job)
+ create(:ci_build, :manual, pipeline: pipeline, when: 'manual')
- after = ActiveRecord::QueryRecorder.new { visit_merge_request(format: :json, serializer: 'widget') }
+ after = ActiveRecord::QueryRecorder.new { visit_merge_request(format: :json, serializer: 'widget') }
- expect(before.count).to eq(after.count)
- expect(before.cached_count).to eq(after.cached_count)
- end
+ expect(before.count).to eq(after.count)
+ expect(before.cached_count).to eq(after.cached_count)
end
+ end
- describe 'build list toggle' do
- let(:toggle) do
- find(dropdown_toggle_selector)
- first(dropdown_toggle_selector)
- end
+ describe 'build list toggle' do
+ let(:toggle) do
+ find(dropdown_selector)
+ first(dropdown_selector)
+ end
- # Status icon button styles should update as described in
- # https://gitlab.com/gitlab-org/gitlab-foss/issues/42769
- it 'has unique styles for default, :hover, :active, and :focus states' do
- default_background_color, default_foreground_color, default_box_shadow = get_toggle_colors(dropdown_toggle_selector)
+ # Status icon button styles should update as described in
+ # https://gitlab.com/gitlab-org/gitlab-foss/issues/42769
+ it 'has unique styles for default, :hover, :active, and :focus states' do
+ default_background_color, default_foreground_color, default_box_shadow = get_toggle_colors(dropdown_selector)
- toggle.hover
- hover_background_color, hover_foreground_color, hover_box_shadow = get_toggle_colors(dropdown_toggle_selector)
+ toggle.hover
+ hover_background_color, hover_foreground_color, hover_box_shadow = get_toggle_colors(dropdown_selector)
- page.driver.browser.action.click_and_hold(toggle.native).perform
- active_background_color, active_foreground_color, active_box_shadow = get_toggle_colors(dropdown_toggle_selector)
- page.driver.browser.action.release(toggle.native).perform
+ page.driver.browser.action.click_and_hold(toggle.native).perform
+ active_background_color, active_foreground_color, active_box_shadow = get_toggle_colors(dropdown_selector)
+ page.driver.browser.action.release(toggle.native).perform
- page.driver.browser.action.click(toggle.native).move_by(100, 100).perform
- focus_background_color, focus_foreground_color, focus_box_shadow = get_toggle_colors(dropdown_toggle_selector)
+ page.driver.browser.action.click(toggle.native).move_by(100, 100).perform
+ focus_background_color, focus_foreground_color, focus_box_shadow = get_toggle_colors(dropdown_selector)
- expect(default_background_color).not_to eq(hover_background_color)
- expect(hover_background_color).not_to eq(active_background_color)
- expect(default_background_color).not_to eq(active_background_color)
+ expect(default_background_color).not_to eq(hover_background_color)
+ expect(hover_background_color).not_to eq(active_background_color)
+ expect(default_background_color).not_to eq(active_background_color)
- expect(default_foreground_color).not_to eq(hover_foreground_color)
- expect(hover_foreground_color).not_to eq(active_foreground_color)
- expect(default_foreground_color).not_to eq(active_foreground_color)
+ expect(default_foreground_color).not_to eq(hover_foreground_color)
+ expect(hover_foreground_color).not_to eq(active_foreground_color)
+ expect(default_foreground_color).not_to eq(active_foreground_color)
- expect(focus_background_color).to eq(hover_background_color)
- expect(focus_foreground_color).to eq(hover_foreground_color)
+ expect(focus_background_color).to eq(hover_background_color)
+ expect(focus_foreground_color).to eq(hover_foreground_color)
- expect(default_box_shadow).to eq('none')
- expect(hover_box_shadow).to eq('none')
- expect(active_box_shadow).not_to eq('none')
- expect(focus_box_shadow).not_to eq('none')
- end
+ expect(default_box_shadow).to eq('none')
+ expect(hover_box_shadow).to eq('none')
+ expect(active_box_shadow).not_to eq('none')
+ expect(focus_box_shadow).not_to eq('none')
+ end
- it 'shows tooltip when hovered' do
- toggle.hover
+ it 'shows tooltip when hovered' do
+ toggle.hover
- expect(page).to have_selector('.tooltip')
- end
+ expect(page).to have_selector('.tooltip')
end
+ end
- describe 'builds list menu' do
- let(:toggle) do
- find(dropdown_toggle_selector)
- first(dropdown_toggle_selector)
- end
+ describe 'builds list menu' do
+ let(:toggle) do
+ find(dropdown_selector)
+ first(dropdown_selector)
+ end
- before do
- toggle.click
- wait_for_requests
- end
+ before do
+ toggle.click
+ wait_for_requests
+ end
- it 'pens when toggle is clicked' do
- expect(toggle.find(:xpath, '..')).to have_selector('.mini-pipeline-graph-dropdown-menu')
- end
+ it 'pens when toggle is clicked' do
+ expect(toggle.find(:xpath, '..')).to have_selector('.mini-pipeline-graph-dropdown-menu')
+ end
- it 'closes when toggle is clicked again' do
- toggle.click
+ it 'closes when toggle is clicked again' do
+ toggle.click
- expect(toggle.find(:xpath, '..')).not_to have_selector('.mini-pipeline-graph-dropdown-menu')
- end
+ expect(toggle.find(:xpath, '..')).not_to have_selector('.mini-pipeline-graph-dropdown-menu')
+ end
- it 'closes when clicking somewhere else' do
- find('body').click
+ it 'closes when clicking somewhere else' do
+ find('body').click
- expect(toggle.find(:xpath, '..')).not_to have_selector('.mini-pipeline-graph-dropdown-menu')
- end
+ expect(toggle.find(:xpath, '..')).not_to have_selector('.mini-pipeline-graph-dropdown-menu')
+ end
- describe 'build list build item' do
- let(:build_item) do
- find('.mini-pipeline-graph-dropdown-item')
- first('.mini-pipeline-graph-dropdown-item')
- end
+ describe 'build list build item' do
+ let(:build_item) do
+ find('.mini-pipeline-graph-dropdown-item')
+ first('.mini-pipeline-graph-dropdown-item')
+ end
- it 'visits the build page when clicked' do
- build_item.click
- find('.build-page')
+ it 'visits the build page when clicked' do
+ build_item.click
+ find('.build-page')
- expect(current_path).to eql(project_job_path(project, build))
- end
+ expect(current_path).to eql(project_job_path(project, build))
+ end
- it 'shows tooltip when hovered' do
- build_item.hover
+ it 'shows tooltip when hovered' do
+ build_item.hover
- expect(page).to have_selector('.tooltip')
- end
+ expect(page).to have_selector('.tooltip')
end
end
end
- context 'with ci_mini_pipeline_gl_dropdown disabled' do
- it_behaves_like "mini pipeline renders", false
- end
-
- context 'with ci_mini_pipeline_gl_dropdown enabled' do
- it_behaves_like "mini pipeline renders", true
- end
-
private
def get_toggle_colors(selector)
find(selector)
[
- evaluate_script("$('#{selector}:visible').css('background-color');"),
- evaluate_script("$('#{selector}:visible svg').css('fill');"),
- evaluate_script("$('#{selector}:visible').css('box-shadow');")
+ evaluate_script("$('#{selector} button:visible').css('background-color');"),
+ evaluate_script("$('#{selector} button:visible svg').css('fill');"),
+ evaluate_script("$('#{selector} button:visible').css('box-shadow');")
]
end
end
diff --git a/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb b/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb
index 20c45a1d652..ea46ae06329 100644
--- a/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb
+++ b/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe 'Merge request > User sees notes from forked project', :js do
expect(page).to have_content('A commit comment')
page.within('.discussion-notes') do
- find('.btn-text-field').click
+ find_field('Reply…').click
scroll_to(page.find('#note_note', visible: false))
find('#note_note').send_keys('A reply comment')
find('.js-comment-button').click
diff --git a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
index bf445de44ba..9850ca3f173 100644
--- a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
+++ b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
@@ -121,14 +121,14 @@ RSpec.describe 'Merge request > User selects branches for new MR', :js do
click_link 'Changes'
- expect(page).to have_css('a.btn.active', text: 'Inline')
- expect(page).not_to have_css('a.btn.active', text: 'Side-by-side')
+ expect(page).to have_css('a.btn.selected', text: 'Inline')
+ expect(page).not_to have_css('a.btn.selected', text: 'Side-by-side')
click_link 'Side-by-side'
within '.merge-request' do
- expect(page).not_to have_css('a.btn.active', text: 'Inline')
- expect(page).to have_css('a.btn.active', text: 'Side-by-side')
+ expect(page).not_to have_css('a.btn.selected', text: 'Inline')
+ expect(page).to have_css('a.btn.selected', text: 'Side-by-side')
end
end
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 bbeb91bbd19..dbc88d0cce2 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
@@ -83,7 +83,7 @@ RSpec.describe 'User comments on a diff', :js do
wait_for_requests
- click_button 'Reply...'
+ find_field('Reply…', match: :first).click
find('.js-suggestion-btn').click
diff --git a/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb b/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb
index 05f4c16ef60..b72ac071ecb 100644
--- a/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb
+++ b/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb
@@ -21,13 +21,13 @@ RSpec.describe 'Merge request > User toggles whitespace changes', :js do
describe 'clicking "Hide whitespace changes" button' do
it 'toggles the "Hide whitespace changes" button' do
- find('#show-whitespace').click
+ find('[data-testid="show-whitespace"]').click
visit diffs_project_merge_request_path(project, merge_request)
find('.js-show-diff-settings').click
- expect(find('#show-whitespace')).not_to be_checked
+ expect(find('[data-testid="show-whitespace"]')).not_to be_checked
end
end
end
diff --git a/spec/features/merge_requests/user_exports_as_csv_spec.rb b/spec/features/merge_requests/user_exports_as_csv_spec.rb
index a86ff9d7335..725b8366d04 100644
--- a/spec/features/merge_requests/user_exports_as_csv_spec.rb
+++ b/spec/features/merge_requests/user_exports_as_csv_spec.rb
@@ -14,11 +14,13 @@ RSpec.describe 'Merge Requests > Exports as CSV', :js do
subject { page.find('.nav-controls') }
- it { is_expected.to have_button('Export as CSV') }
+ it { is_expected.to have_selector '[data-testid="export-csv-button"]' }
context 'button is clicked' do
before do
- click_button('Export as CSV')
+ page.within('.nav-controls') do
+ find('[data-testid="export-csv-button"]').click
+ end
end
it 'shows a success message' do
diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb
index d6f23b21d65..b22778012a8 100644
--- a/spec/features/participants_autocomplete_spec.rb
+++ b/spec/features/participants_autocomplete_spec.rb
@@ -85,6 +85,7 @@ RSpec.describe 'Member autocomplete', :js do
let(:note) { create(:note_on_commit, project: project, commit_id: project.commit.id) }
before do
+ allow(User).to receive(:find_by_any_email).and_call_original
allow(User).to receive(:find_by_any_email)
.with(noteable.author_email.downcase, confirmed: true).and_return(author)
diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb
index 88bfc71cfbe..9e56ef087ae 100644
--- a/spec/features/profiles/personal_access_tokens_spec.rb
+++ b/spec/features/profiles/personal_access_tokens_spec.rb
@@ -138,4 +138,10 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
end
end
end
+
+ it 'pushes `personal_access_tokens_scoped_to_projects` feature flag to the frontend' do
+ visit profile_personal_access_tokens_path
+
+ expect(page).to have_pushed_frontend_feature_flags(personalAccessTokensScopedToProjects: true)
+ end
end
diff --git a/spec/features/profiles/user_visits_notifications_tab_spec.rb b/spec/features/profiles/user_visits_notifications_tab_spec.rb
index 289fbff0404..939e791c75d 100644
--- a/spec/features/profiles/user_visits_notifications_tab_spec.rb
+++ b/spec/features/profiles/user_visits_notifications_tab_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe 'User visits the notifications tab', :js do
let(:user) { create(:user) }
before do
- stub_feature_flags(vue_notification_dropdown: false)
project.add_maintainer(user)
sign_in(user)
visit(profile_notifications_path)
@@ -16,17 +15,17 @@ RSpec.describe 'User visits the notifications tab', :js do
it 'changes the project notifications setting' do
expect(page).to have_content('Notifications')
- first('#notifications-button').click
- click_link('On mention')
+ first('[data-testid="notification-dropdown"]').click
+ click_button('On mention')
- expect(page).to have_selector('#notifications-button', text: 'On mention')
+ expect(page).to have_selector('[data-testid="notification-dropdown"]', text: 'On mention')
end
context 'when project emails are disabled' do
let(:project) { create(:project, emails_disabled: true) }
it 'notification button is disabled' do
- expect(page).to have_selector('.notifications-btn.disabled', visible: true)
+ expect(page).to have_selector('[data-testid="notification-dropdown"] .disabled')
end
end
end
diff --git a/spec/features/project_group_variables_spec.rb b/spec/features/project_group_variables_spec.rb
index d8eba20ac18..fc482261fb1 100644
--- a/spec/features/project_group_variables_spec.rb
+++ b/spec/features/project_group_variables_spec.rb
@@ -57,7 +57,7 @@ RSpec.describe 'Project group variables', :js do
wait_for_requests
- page.within('.ci-variable-table') do
+ page.within('[data-testid="ci-variable-table"]') do
expect(find('.js-ci-variable-row:nth-child(1) [data-label="Key"]').text).to eq(key1)
end
end
diff --git a/spec/features/project_variables_spec.rb b/spec/features/project_variables_spec.rb
index a7f94f38d85..327d8133411 100644
--- a/spec/features/project_variables_spec.rb
+++ b/spec/features/project_variables_spec.rb
@@ -24,7 +24,6 @@ RSpec.describe 'Project variables', :js do
find('[data-qa-selector="ci_variable_key_field"] input').set('akey')
find('#ci-variable-value').set('akey_value')
find('[data-testid="environment-scope"]').click
- find_button('clear').click
find('[data-testid="ci-environment-search"]').set('review/*')
find('[data-testid="create-wildcard-button"]').click
@@ -33,7 +32,7 @@ RSpec.describe 'Project variables', :js do
wait_for_requests
- page.within('.ci-variable-table') do
+ page.within('[data-testid="ci-variable-table"]') do
expect(find('.js-ci-variable-row:first-child [data-label="Environments"]').text).to eq('review/*')
end
end
diff --git a/spec/features/projects/active_tabs_spec.rb b/spec/features/projects/active_tabs_spec.rb
index 8001ce0f454..86fe59f003f 100644
--- a/spec/features/projects/active_tabs_spec.rb
+++ b/spec/features/projects/active_tabs_spec.rb
@@ -132,13 +132,13 @@ RSpec.describe 'Project active tab' do
it_behaves_like 'page has active sub tab', _('Value Stream')
end
- context 'on project Analytics/"CI / CD"' do
+ context 'on project Analytics/"CI/CD"' do
before do
- click_tab(_('CI / CD'))
+ click_tab(_('CI/CD'))
end
it_behaves_like 'page has active tab', _('Analytics')
- it_behaves_like 'page has active sub tab', _('CI / CD')
+ it_behaves_like 'page has active sub tab', _('CI/CD')
end
end
end
diff --git a/spec/features/projects/ci/lint_spec.rb b/spec/features/projects/ci/lint_spec.rb
index ccffe25f45e..353c8558185 100644
--- a/spec/features/projects/ci/lint_spec.rb
+++ b/spec/features/projects/ci/lint_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'CI Lint', :js do
+RSpec.describe 'CI Lint', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/297782' do
include Spec::Support::Helpers::Features::EditorLiteSpecHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/features/projects/commit/mini_pipeline_graph_spec.rb b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
index cf9b86f16bb..7d206f76031 100644
--- a/spec/features/projects/commit/mini_pipeline_graph_spec.rb
+++ b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
@@ -7,37 +7,55 @@ RSpec.describe 'Mini Pipeline Graph in Commit View', :js do
context 'when commit has pipelines' do
let(:pipeline) do
- create(:ci_empty_pipeline,
+ create(:ci_pipeline,
+ status: :running,
project: project,
ref: project.default_branch,
sha: project.commit.sha)
end
- let(:build) { create(:ci_build, pipeline: pipeline) }
+ let(:build) { create(:ci_build, pipeline: pipeline, status: :running) }
- it 'display icon with status' do
- build.run
- visit project_commit_path(project, project.commit.id)
+ shared_examples 'shows ci icon and mini pipeline' do
+ before do
+ build.run
+ visit project_commit_path(project, project.commit.id)
+ end
- expect(page).to have_selector('.ci-status-icon-running')
- end
+ it 'display icon with status' do
+ expect(page).to have_selector('.ci-status-icon-running')
+ end
- it 'displays a mini pipeline graph' do
- build.run
- visit project_commit_path(project, project.commit.id)
+ it 'displays a mini pipeline graph' do
+ expect(page).to have_selector('.mr-widget-pipeline-graph')
- expect(page).to have_selector('.mr-widget-pipeline-graph')
+ first('.mini-pipeline-graph-dropdown-toggle').click
- first('.mini-pipeline-graph-dropdown-toggle').click
+ wait_for_requests
- wait_for_requests
+ page.within '.js-builds-dropdown-list' do
+ expect(page).to have_selector('.ci-status-icon-running')
+ expect(page).to have_content(build.stage)
+ end
- page.within '.js-builds-dropdown-list' do
- expect(page).to have_selector('.ci-status-icon-running')
- expect(page).to have_content(build.stage)
+ build.drop
+ end
+ end
+
+ context 'when ci_commit_pipeline_mini_graph_vue is disabled' do
+ before do
+ stub_feature_flags(ci_commit_pipeline_mini_graph_vue: false)
+ end
+
+ it_behaves_like 'shows ci icon and mini pipeline'
+ end
+
+ context 'when ci_commit_pipeline_mini_graph_vue is enabled' do
+ before do
+ stub_feature_flags(ci_commit_pipeline_mini_graph_vue: true)
end
- build.drop
+ it_behaves_like 'shows ci icon and mini pipeline'
end
end
diff --git a/spec/features/projects/container_registry_spec.rb b/spec/features/projects/container_registry_spec.rb
index d0ad6668c07..40d0260eafd 100644
--- a/spec/features/projects/container_registry_spec.rb
+++ b/spec/features/projects/container_registry_spec.rb
@@ -82,7 +82,13 @@ RSpec.describe 'Container Registry', :js do
end
it 'shows the image title' do
- expect(page).to have_content 'my/image tags'
+ expect(page).to have_content 'my/image'
+ end
+
+ it 'shows the image tags' do
+ expect(page).to have_content 'Image tags'
+ first_tag = first('[data-testid="name"]')
+ expect(first_tag).to have_content '1'
end
it 'user removes a specific tag from container repository' do
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 27167f95104..de7ff1c473d 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -429,37 +429,67 @@ RSpec.describe 'Environments page', :js do
end
describe 'environments folders' do
- before do
- create(:environment, :will_auto_stop,
- project: project,
- name: 'staging/review-1',
- state: :available)
- create(:environment, :will_auto_stop,
- project: project,
- name: 'staging/review-2',
- state: :available)
- end
+ describe 'available environments' do
+ before do
+ create(:environment, :will_auto_stop,
+ project: project,
+ name: 'staging/review-1',
+ state: :available)
+ create(:environment, :will_auto_stop,
+ project: project,
+ name: 'staging/review-2',
+ state: :available)
+ end
- it 'users unfurls an environment folder' do
- visit_environments(project)
+ it 'users unfurls an environment folder' do
+ visit_environments(project)
- expect(page).not_to have_content 'review-1'
- expect(page).not_to have_content 'review-2'
- expect(page).to have_content 'staging 2'
+ expect(page).not_to have_content 'review-1'
+ expect(page).not_to have_content 'review-2'
+ expect(page).to have_content 'staging 2'
- within('.folder-row') do
- find('.folder-name', text: 'staging').click
- end
+ within('.folder-row') do
+ find('.folder-name', text: 'staging').click
+ end
- expect(page).to have_content 'review-1'
- expect(page).to have_content 'review-2'
- within('.ci-table') do
- within('[data-qa-selector="environment_item"]', text: 'review-1') do
- expect(find('.js-auto-stop').text).not_to be_empty
+ expect(page).to have_content 'review-1'
+ expect(page).to have_content 'review-2'
+ within('.ci-table') do
+ within('[data-qa-selector="environment_item"]', text: 'review-1') do
+ expect(find('.js-auto-stop').text).not_to be_empty
+ end
+ within('[data-qa-selector="environment_item"]', text: 'review-2') do
+ expect(find('.js-auto-stop').text).not_to be_empty
+ end
end
- within('[data-qa-selector="environment_item"]', text: 'review-2') do
- expect(find('.js-auto-stop').text).not_to be_empty
+ end
+ end
+
+ describe 'stopped environments' do
+ before do
+ create(:environment, :will_auto_stop,
+ project: project,
+ name: 'staging/review-1',
+ state: :stopped)
+ create(:environment, :will_auto_stop,
+ project: project,
+ name: 'staging/review-2',
+ state: :stopped)
+ end
+
+ it 'users unfurls an environment folder' do
+ visit_environments(project, scope: 'stopped')
+
+ expect(page).not_to have_content 'review-1'
+ expect(page).not_to have_content 'review-2'
+ expect(page).to have_content 'staging 2'
+
+ within('.folder-row') do
+ find('.folder-name', text: 'staging').click
end
+
+ expect(page).to have_content 'review-1'
+ expect(page).to have_content 'review-2'
end
end
end
diff --git a/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb b/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb
index f5941d0ff15..50fc7bb0753 100644
--- a/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb
+++ b/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb
@@ -104,7 +104,7 @@ RSpec.describe 'User sees feature flag list', :js do
it 'shows empty page' do
expect(page).to have_text 'Get started with feature flags'
- expect(page).to have_selector('.btn-success', text: 'New feature flag')
+ expect(page).to have_selector('.btn-confirm', text: 'New feature flag')
expect(page).to have_selector('[data-qa-selector="configure_feature_flags_button"]', text: 'Configure')
end
end
diff --git a/spec/features/projects/files/gitlab_ci_syntax_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_syntax_yml_dropdown_spec.rb
index ca6f03472dd..cd796d45aba 100644
--- a/spec/features/projects/files/gitlab_ci_syntax_yml_dropdown_spec.rb
+++ b/spec/features/projects/files/gitlab_ci_syntax_yml_dropdown_spec.rb
@@ -5,11 +5,13 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file' do
include Spec::Support::Helpers::Features::EditorLiteSpecHelpers
+ let_it_be(:namespace) { create(:namespace) }
+ let(:project) { create(:project, :repository, namespace: namespace) }
+
before do
- project = create(:project, :repository)
sign_in project.owner
- stub_experiment(ci_syntax_templates: experiment_active)
- stub_experiment_for_subject(ci_syntax_templates: in_experiment_group)
+ stub_experiment(ci_syntax_templates_b: experiment_active)
+ stub_experiment_for_subject(ci_syntax_templates_b: in_experiment_group)
visit project_new_blob_path(project, 'master', file_name: '.gitlab-ci.yml')
end
@@ -23,35 +25,45 @@ RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file' do
end
end
- context 'when experiment is active and the user is in the control group' do
+ context 'when experiment is active' do
let(:experiment_active) { true }
- let(:in_experiment_group) { false }
- it 'does not show the "Learn CI/CD syntax" template dropdown' do
- expect(page).not_to have_css('.gitlab-ci-syntax-yml-selector')
+ context 'when the user is in the control group' do
+ let(:in_experiment_group) { false }
+
+ it 'does not show the "Learn CI/CD syntax" template dropdown' do
+ expect(page).not_to have_css('.gitlab-ci-syntax-yml-selector')
+ end
end
- end
- context 'when experiment is active and the user is in the experimental group' do
- let(:experiment_active) { true }
- let(:in_experiment_group) { true }
+ context 'when the user is in the experimental group' do
+ let(:in_experiment_group) { true }
+
+ it 'allows the user to pick a "Learn CI/CD syntax" template from the dropdown', :js do
+ expect(page).to have_css('.gitlab-ci-syntax-yml-selector')
- it 'allows the user to pick a "Learn CI/CD syntax" template from the dropdown', :js do
- expect(page).to have_css('.gitlab-ci-syntax-yml-selector')
+ find('.js-gitlab-ci-syntax-yml-selector').click
- find('.js-gitlab-ci-syntax-yml-selector').click
+ wait_for_requests
- wait_for_requests
+ within '.gitlab-ci-syntax-yml-selector' do
+ find('.dropdown-input-field').set('Artifacts example')
+ find('.dropdown-content .is-focused', text: 'Artifacts example').click
+ end
- within '.gitlab-ci-syntax-yml-selector' do
- find('.dropdown-input-field').set('Artifacts example')
- find('.dropdown-content .is-focused', text: 'Artifacts example').click
+ wait_for_requests
+
+ expect(page).to have_css('.gitlab-ci-syntax-yml-selector .dropdown-toggle-text', text: 'Learn CI/CD syntax')
+ expect(editor_get_value).to have_content('You can use artifacts to pass data to jobs in later stages.')
end
- wait_for_requests
+ context 'when the group is created longer than 90 days ago' do
+ let(:namespace) { create(:namespace, created_at: 91.days.ago) }
- expect(page).to have_css('.gitlab-ci-syntax-yml-selector .dropdown-toggle-text', text: 'Learn CI/CD syntax')
- expect(editor_get_value).to have_content('You can use artifacts to pass data to jobs in later stages.')
+ it 'does not show the "Learn CI/CD syntax" template dropdown' do
+ expect(page).not_to have_css('.gitlab-ci-syntax-yml-selector')
+ end
+ end
end
end
end
diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb
index 8d0500f5e13..7abbd207b24 100644
--- a/spec/features/projects/fork_spec.rb
+++ b/spec/features/projects/fork_spec.rb
@@ -12,45 +12,27 @@ RSpec.describe 'Project fork' do
sign_in(user)
end
- it 'allows user to fork project from the project page' do
- visit project_path(project)
-
- expect(page).not_to have_css('a.disabled', text: 'Fork')
- end
-
- context 'user has exceeded personal project limit' do
- before do
- user.update!(projects_limit: 0)
- end
-
- it 'disables fork button on project page' do
+ shared_examples 'fork button on project page' do
+ it 'allows user to fork project from the project page' do
visit project_path(project)
- expect(page).to have_css('a.disabled', text: 'Fork')
+ expect(page).not_to have_css('a.disabled', text: 'Fork')
end
- context 'with a group to fork to' do
- let!(:group) { create(:group).tap { |group| group.add_owner(user) } }
-
- it 'enables fork button on project page' do
- visit project_path(project)
-
- expect(page).not_to have_css('a.disabled', text: 'Fork')
+ context 'user has exceeded personal project limit' do
+ before do
+ user.update!(projects_limit: 0)
end
- it 'allows user to fork only to the group on fork page', :js do
- visit new_project_fork_path(project)
-
- to_personal_namespace = find('[data-qa-selector=fork_namespace_button].disabled')
- to_group = find(".fork-groups button[data-qa-name=#{group.name}]")
+ it 'disables fork button on project page' do
+ visit project_path(project)
- expect(to_personal_namespace).not_to be_nil
- expect(to_group).not_to be_disabled
+ expect(page).to have_css('a.disabled', text: 'Fork')
end
end
end
- context 'forking enabled / disabled in project settings' do
+ shared_examples 'create fork page' do |fork_page_text|
before do
project.project_feature.update_attribute(
:forking_access_level, forking_access_level)
@@ -70,7 +52,7 @@ RSpec.describe 'Project fork' do
visit new_project_fork_path(project)
expect(page.status_code).to eq(200)
- expect(page).to have_text(' Select a namespace to fork the project ')
+ expect(page).to have_text(fork_page_text)
end
end
@@ -127,92 +109,88 @@ RSpec.describe 'Project fork' do
visit new_project_fork_path(project)
expect(page.status_code).to eq(200)
- expect(page).to have_text(' Select a namespace to fork the project ')
+ expect(page).to have_text(fork_page_text)
end
end
end
end
- it 'forks the project', :sidekiq_might_not_need_inline do
- visit project_path(project)
-
- click_link 'Fork'
+ it_behaves_like 'fork button on project page'
+ it_behaves_like 'create fork page', 'Fork project'
- page.within '.fork-thumbnail-container' do
- click_link 'Select'
+ context 'with fork_project_form feature flag disabled' do
+ before do
+ stub_feature_flags(fork_project_form: false)
+ sign_in(user)
end
- expect(page).to have_content 'Forked from'
+ it_behaves_like 'fork button on project page'
- visit project_path(project)
+ context 'user has exceeded personal project limit' do
+ before do
+ user.update!(projects_limit: 0)
+ end
- expect(page).to have_content(/new merge request/i)
+ context 'with a group to fork to' do
+ let!(:group) { create(:group).tap { |group| group.add_owner(user) } }
- page.within '.nav-sidebar' do
- first(:link, 'Merge Requests').click
- end
+ it 'allows user to fork only to the group on fork page', :js do
+ visit new_project_fork_path(project)
- expect(page).to have_content(/new merge request/i)
+ to_personal_namespace = find('[data-qa-selector=fork_namespace_button].disabled')
+ to_group = find(".fork-groups button[data-qa-name=#{group.name}]")
- page.within '#content-body' do
- click_link('New merge request')
+ expect(to_personal_namespace).not_to be_nil
+ expect(to_group).not_to be_disabled
+ end
+ end
end
- expect(current_path).to have_content(/#{user.namespace.path}/i)
- end
+ it_behaves_like 'create fork page', ' Select a namespace to fork the project '
- it 'shows avatars when Gravatar is disabled' do
- stub_application_setting(gravatar_enabled: false)
+ it 'forks the project', :sidekiq_might_not_need_inline do
+ visit project_path(project)
- visit project_path(project)
+ click_link 'Fork'
- click_link 'Fork'
+ page.within '.fork-thumbnail-container' do
+ click_link 'Select'
+ end
- page.within('.fork-thumbnail-container') do
- expect(page).to have_css('div.identicon')
- end
- end
+ expect(page).to have_content 'Forked from'
- it 'shows the forked project on the list' do
- visit project_path(project)
+ visit project_path(project)
- click_link 'Fork'
+ expect(page).to have_content(/new merge request/i)
- page.within '.fork-thumbnail-container' do
- click_link 'Select'
- end
+ page.within '.nav-sidebar' do
+ first(:link, 'Merge Requests').click
+ end
- visit project_forks_path(project)
+ expect(page).to have_content(/new merge request/i)
- forked_project = user.fork_of(project.reload)
+ page.within '#content-body' do
+ click_link('New merge request')
+ end
- page.within('.js-projects-list-holder') do
- expect(page).to have_content("#{forked_project.namespace.human_name} / #{forked_project.name}")
+ expect(current_path).to have_content(/#{user.namespace.path}/i)
end
- forked_project.update!(path: 'test-crappy-path')
-
- visit project_forks_path(project)
+ it 'shows avatars when Gravatar is disabled' do
+ stub_application_setting(gravatar_enabled: false)
- page.within('.js-projects-list-holder') do
- expect(page).to have_content("#{forked_project.namespace.human_name} / #{forked_project.name}")
- end
- end
+ visit project_path(project)
- context 'when the project is private' do
- let(:project) { create(:project, :repository) }
- let(:another_user) { create(:user, name: 'Mike') }
+ click_link 'Fork'
- before do
- project.add_reporter(user)
- project.add_reporter(another_user)
+ page.within('.fork-thumbnail-container') do
+ expect(page).to have_css('div.identicon')
+ end
end
- it 'renders private forks of the project' do
+ it 'shows the forked project on the list' do
visit project_path(project)
- another_project_fork = Projects::ForkService.new(project, another_user).execute
-
click_link 'Fork'
page.within '.fork-thumbnail-container' do
@@ -221,79 +199,117 @@ RSpec.describe 'Project fork' do
visit project_forks_path(project)
+ forked_project = user.fork_of(project.reload)
+
page.within('.js-projects-list-holder') do
- user_project_fork = user.fork_of(project.reload)
- expect(page).to have_content("#{user_project_fork.namespace.human_name} / #{user_project_fork.name}")
+ expect(page).to have_content("#{forked_project.namespace.human_name} / #{forked_project.name}")
end
- expect(page).not_to have_content("#{another_project_fork.namespace.human_name} / #{another_project_fork.name}")
- end
- end
+ forked_project.update!(path: 'test-crappy-path')
- context 'when the user already forked the project' do
- before do
- create(:project, :repository, name: project.name, namespace: user.namespace)
- end
+ visit project_forks_path(project)
- it 'renders error' do
- visit project_path(project)
+ page.within('.js-projects-list-holder') do
+ expect(page).to have_content("#{forked_project.namespace.human_name} / #{forked_project.name}")
+ end
+ end
- click_link 'Fork'
+ context 'when the project is private' do
+ let(:project) { create(:project, :repository) }
+ let(:another_user) { create(:user, name: 'Mike') }
- page.within '.fork-thumbnail-container' do
- click_link 'Select'
+ before do
+ project.add_reporter(user)
+ project.add_reporter(another_user)
end
- expect(page).to have_content "Name has already been taken"
- end
- end
+ it 'renders private forks of the project' do
+ visit project_path(project)
- context 'maintainer in group' do
- let(:group) { create(:group) }
+ another_project_fork = Projects::ForkService.new(project, another_user).execute
- before do
- group.add_maintainer(user)
- end
+ click_link 'Fork'
- it 'allows user to fork project to group or to user namespace', :js do
- visit project_path(project)
- wait_for_requests
+ page.within '.fork-thumbnail-container' do
+ click_link 'Select'
+ end
- expect(page).not_to have_css('a.disabled', text: 'Fork')
+ visit project_forks_path(project)
- click_link 'Fork'
+ page.within('.js-projects-list-holder') do
+ user_project_fork = user.fork_of(project.reload)
+ expect(page).to have_content("#{user_project_fork.namespace.human_name} / #{user_project_fork.name}")
+ end
- expect(page).to have_css('.fork-thumbnail')
- expect(page).to have_css('.group-row')
- expect(page).not_to have_css('.fork-thumbnail.disabled')
+ expect(page).not_to have_content("#{another_project_fork.namespace.human_name} / #{another_project_fork.name}")
+ end
end
- it 'allows user to fork project to group and not user when exceeded project limit', :js do
- user.projects_limit = 0
- user.save!
+ context 'when the user already forked the project' do
+ before do
+ create(:project, :repository, name: project.name, namespace: user.namespace)
+ end
- visit project_path(project)
- wait_for_requests
+ it 'renders error' do
+ visit project_path(project)
- expect(page).not_to have_css('a.disabled', text: 'Fork')
+ click_link 'Fork'
- click_link 'Fork'
+ page.within '.fork-thumbnail-container' do
+ click_link 'Select'
+ end
- expect(page).to have_css('.fork-thumbnail.disabled')
- expect(page).to have_css('.group-row')
+ expect(page).to have_content "Name has already been taken"
+ end
end
- it 'links to the fork if the project was already forked within that namespace', :sidekiq_might_not_need_inline, :js do
- forked_project = fork_project(project, user, namespace: group, repository: true)
+ context 'maintainer in group' do
+ let(:group) { create(:group) }
+
+ before do
+ group.add_maintainer(user)
+ end
+
+ it 'allows user to fork project to group or to user namespace', :js do
+ visit project_path(project)
+ wait_for_requests
+
+ expect(page).not_to have_css('a.disabled', text: 'Fork')
+
+ click_link 'Fork'
+
+ expect(page).to have_css('.fork-thumbnail')
+ expect(page).to have_css('.group-row')
+ expect(page).not_to have_css('.fork-thumbnail.disabled')
+ end
+
+ it 'allows user to fork project to group and not user when exceeded project limit', :js do
+ user.projects_limit = 0
+ user.save!
+
+ visit project_path(project)
+ wait_for_requests
+
+ expect(page).not_to have_css('a.disabled', text: 'Fork')
- visit new_project_fork_path(project)
- wait_for_requests
+ click_link 'Fork'
- expect(page).to have_css('.group-row a.btn', text: 'Go to fork')
+ expect(page).to have_css('.fork-thumbnail.disabled')
+ expect(page).to have_css('.group-row')
+ end
+
+ it 'links to the fork if the project was already forked within that namespace', :sidekiq_might_not_need_inline, :js do
+ forked_project = fork_project(project, user, namespace: group, repository: true)
+
+ visit new_project_fork_path(project)
+ wait_for_requests
+
+ expect(page).to have_css('.group-row a.btn', text: 'Go to fork')
- click_link 'Go to fork'
+ click_link 'Go to fork'
- expect(current_path).to eq(project_path(forked_project))
+ expect(current_path).to eq(project_path(forked_project))
+ end
end
end
end
diff --git a/spec/features/projects/members/anonymous_user_sees_members_spec.rb b/spec/features/projects/members/anonymous_user_sees_members_spec.rb
index d710ecf6c88..6b92581d704 100644
--- a/spec/features/projects/members/anonymous_user_sees_members_spec.rb
+++ b/spec/features/projects/members/anonymous_user_sees_members_spec.rb
@@ -14,25 +14,9 @@ RSpec.describe 'Projects > Members > Anonymous user sees members' do
create(:project_group_link, project: project, group: group)
end
- context 'when `vue_project_members_list` feature flag is enabled', :js do
- it "anonymous user visits the project's members page and sees the list of members" do
- visit project_project_members_path(project)
+ it "anonymous user visits the project's members page and sees the list of members", :js do
+ visit project_project_members_path(project)
- expect(find_member_row(user)).to have_content(user.name)
- end
- end
-
- context 'when `vue_project_members_list` feature flag is disabled' do
- before do
- stub_feature_flags(vue_project_members_list: false)
- end
-
- it "anonymous user visits the project's members page and sees the list of members" do
- visit project_project_members_path(project)
-
- expect(current_path).to eq(
- project_project_members_path(project))
- expect(page).to have_content(user.name)
- end
+ expect(find_member_row(user)).to have_content(user.name)
end
end
diff --git a/spec/features/projects/members/group_members_spec.rb b/spec/features/projects/members/group_members_spec.rb
index 1abd00421ec..94ce18fef93 100644
--- a/spec/features/projects/members/group_members_spec.rb
+++ b/spec/features/projects/members/group_members_spec.rb
@@ -20,218 +20,96 @@ RSpec.describe 'Projects members', :js do
sign_in(user)
end
- context 'when `vue_project_members_list` feature flag is enabled' do
- context 'with a group invitee' do
- before do
- group_invitee
- visit project_project_members_path(project)
- end
-
- it 'does not appear in the project members page' do
- expect(members_table).not_to have_content('test2@abc.com')
- end
+ context 'with a group invitee' do
+ before do
+ group_invitee
+ visit project_project_members_path(project)
end
- context 'with a group' do
- it 'shows group and project members by default' do
- visit project_project_members_path(project)
-
- expect(members_table).to have_content(developer.name)
- expect(members_table).to have_content(user.name)
- expect(members_table).to have_content(group.name)
- end
-
- it 'shows project members only if requested' do
- visit project_project_members_path(project, with_inherited_permissions: 'exclude')
-
- expect(members_table).to have_content(developer.name)
- expect(members_table).not_to have_content(user.name)
- expect(members_table).not_to have_content(group.name)
- end
+ it 'does not appear in the project members page' do
+ expect(members_table).not_to have_content('test2@abc.com')
+ end
+ end
- it 'shows group members only if requested' do
- visit project_project_members_path(project, with_inherited_permissions: 'only')
+ context 'with a group' do
+ it 'shows group and project members by default' do
+ visit project_project_members_path(project)
- expect(members_table).not_to have_content(developer.name)
- expect(members_table).to have_content(user.name)
- expect(members_table).to have_content(group.name)
- end
+ expect(members_table).to have_content(developer.name)
+ expect(members_table).to have_content(user.name)
+ expect(members_table).to have_content(group.name)
end
- context 'with a group, a project invitee, and a project requester' do
- before do
- group.request_access(group_requester)
- project.request_access(project_requester)
- group_invitee
- project_invitee
- visit project_project_members_path(project)
- end
-
- it 'shows the group owner' do
- expect(members_table).to have_content(user.name)
- expect(members_table).to have_content(group.name)
- end
-
- it 'shows the project developer' do
- expect(members_table).to have_content(developer.name)
- end
-
- it 'shows the project invitee' do
- click_link 'Invited'
-
- expect(members_table).to have_content('test1@abc.com')
- expect(members_table).not_to have_content('test2@abc.com')
- end
-
- it 'shows the project requester' do
- click_link 'Access requests'
-
- expect(members_table).to have_content(project_requester.name)
- expect(members_table).not_to have_content(group_requester.name)
- end
- end
+ it 'shows project members only if requested' do
+ visit project_project_members_path(project, with_inherited_permissions: 'exclude')
- context 'with a group requester' do
- before do
- stub_feature_flags(invite_members_group_modal: false)
- group.request_access(group_requester)
- visit project_project_members_path(project)
- end
-
- it 'does not appear in the project members page' do
- expect(page).not_to have_link('Access requests')
- expect(members_table).not_to have_content(group_requester.name)
- end
+ expect(members_table).to have_content(developer.name)
+ expect(members_table).not_to have_content(user.name)
+ expect(members_table).not_to have_content(group.name)
end
- context 'showing status of members' do
- it 'shows the status' do
- create(:user_status, user: user, emoji: 'smirk', message: 'Authoring this object')
+ it 'shows group members only if requested' do
+ visit project_project_members_path(project, with_inherited_permissions: 'only')
- visit project_project_members_path(project)
-
- expect(first_row).to have_selector('gl-emoji[data-name="smirk"]')
- end
+ expect(members_table).not_to have_content(developer.name)
+ expect(members_table).to have_content(user.name)
+ expect(members_table).to have_content(group.name)
end
end
- context 'when `vue_project_members_list` feature flag is disabled' do
+ context 'with a group, a project invitee, and a project requester' do
before do
- stub_feature_flags(vue_project_members_list: false)
+ group.request_access(group_requester)
+ project.request_access(project_requester)
+ group_invitee
+ project_invitee
+ visit project_project_members_path(project)
end
- context 'with a group invitee' do
- before do
- group_invitee
- visit project_project_members_path(project)
- end
-
- it 'does not appear in the project members page' do
- page.within first('.content-list') do
- expect(page).not_to have_content('test2@abc.com')
- end
- end
+ it 'shows the group owner' do
+ expect(members_table).to have_content(user.name)
+ expect(members_table).to have_content(group.name)
end
- context 'with a group' do
- it 'shows group and project members by default' do
- visit project_project_members_path(project)
-
- page.within first('.content-list') do
- expect(page).to have_content(developer.name)
-
- expect(page).to have_content(user.name)
- expect(page).to have_content(group.name)
- end
- end
-
- it 'shows project members only if requested' do
- visit project_project_members_path(project, with_inherited_permissions: 'exclude')
-
- page.within first('.content-list') do
- expect(page).to have_content(developer.name)
+ it 'shows the project developer' do
+ expect(members_table).to have_content(developer.name)
+ end
- expect(page).not_to have_content(user.name)
- expect(page).not_to have_content(group.name)
- end
- end
+ it 'shows the project invitee' do
+ click_link 'Invited'
- it 'shows group members only if requested' do
- visit project_project_members_path(project, with_inherited_permissions: 'only')
+ expect(members_table).to have_content('test1@abc.com')
+ expect(members_table).not_to have_content('test2@abc.com')
+ end
- page.within first('.content-list') do
- expect(page).not_to have_content(developer.name)
+ it 'shows the project requester' do
+ click_link 'Access requests'
- expect(page).to have_content(user.name)
- expect(page).to have_content(group.name)
- end
- end
+ expect(members_table).to have_content(project_requester.name)
+ expect(members_table).not_to have_content(group_requester.name)
end
+ end
- context 'with a group, a project invitee, and a project requester' do
- before do
- group.request_access(group_requester)
- project.request_access(project_requester)
- group_invitee
- project_invitee
- visit project_project_members_path(project)
- end
-
- it 'shows the group owner' do
- page.within first('.content-list') do
- # Group owner
- expect(page).to have_content(user.name)
- expect(page).to have_content(group.name)
- end
- end
-
- it 'shows the project developer' do
- page.within first('.content-list') do
- # Project developer
- expect(page).to have_content(developer.name)
- end
- end
-
- it 'shows the project invitee' do
- click_link 'Invited'
-
- page.within first('.content-list') do
- expect(page).to have_content('test1@abc.com')
- expect(page).not_to have_content('test2@abc.com')
- end
- end
-
- it 'shows the project requester' do
- click_link 'Access requests'
-
- page.within first('.content-list') do
- expect(page).to have_content(project_requester.name)
- expect(page).not_to have_content(group_requester.name)
- end
- end
+ context 'with a group requester' do
+ before do
+ stub_feature_flags(invite_members_group_modal: false)
+ group.request_access(group_requester)
+ visit project_project_members_path(project)
end
- context 'with a group requester' do
- before do
- stub_feature_flags(invite_members_group_modal: false)
- group.request_access(group_requester)
- visit project_project_members_path(project)
- end
-
- it 'does not appear in the project members page' do
- expect(page).not_to have_link('Access requests')
- page.within first('.content-list') do
- expect(page).not_to have_content(group_requester.name)
- end
- end
+ it 'does not appear in the project members page' do
+ expect(page).not_to have_link('Access requests')
+ expect(members_table).not_to have_content(group_requester.name)
end
+ end
+
+ context 'showing status of members' do
+ it 'shows the status' do
+ create(:user_status, user: user, emoji: 'smirk', message: 'Authoring this object')
- context 'showing status of members' do
- it_behaves_like 'showing user status' do
- let(:user_with_status) { developer }
+ visit project_project_members_path(project)
- subject { visit project_project_members_path(project) }
- end
+ expect(first_row).to have_selector('gl-emoji[data-name="smirk"]')
end
end
end
diff --git a/spec/features/projects/members/groups_with_access_list_spec.rb b/spec/features/projects/members/groups_with_access_list_spec.rb
index 9d087dfd5f6..6a1d26983b5 100644
--- a/spec/features/projects/members/groups_with_access_list_spec.rb
+++ b/spec/features/projects/members/groups_with_access_list_spec.rb
@@ -17,172 +17,80 @@ RSpec.describe 'Projects > Members > Groups with access list', :js do
project.add_maintainer(user)
sign_in(user)
- end
-
- context 'when `vue_project_members_list` feature flag is enabled' do
- before do
- visit project_project_members_path(project)
- click_groups_tab
- end
-
- it 'updates group access level' do
- click_button group_link.human_access
- click_button 'Guest'
-
- wait_for_requests
-
- visit project_project_members_path(project)
- click_groups_tab
-
- expect(find_group_row(group)).to have_content('Guest')
- end
+ visit project_project_members_path(project)
+ click_groups_tab
+ end
- it 'updates expiry date' do
- page.within find_group_row(group) do
- fill_in 'Expiration date', with: 5.days.from_now.to_date
- find_field('Expiration date').native.send_keys :enter
+ it 'updates group access level' do
+ click_button group_link.human_access
+ click_button 'Guest'
- wait_for_requests
+ wait_for_requests
- expect(page).to have_content(/in \d days/)
- end
- end
+ visit project_project_members_path(project)
- context 'when link has expiry date set' do
- let(:additional_link_attrs) { { expires_at: 5.days.from_now.to_date } }
+ click_groups_tab
- it 'clears expiry date' do
- page.within find_group_row(group) do
- expect(page).to have_content(/in \d days/)
+ expect(find_group_row(group)).to have_content('Guest')
+ end
- find('[data-testid="clear-button"]').click
+ it 'updates expiry date' do
+ page.within find_group_row(group) do
+ fill_in 'Expiration date', with: 5.days.from_now.to_date
+ find_field('Expiration date').native.send_keys :enter
- wait_for_requests
+ wait_for_requests
- expect(page).to have_content('No expiration set')
- end
- end
+ expect(page).to have_content(/in \d days/)
end
+ end
- it 'deletes group link' do
- expect(page).to have_content(group.full_name)
+ context 'when link has expiry date set' do
+ let(:additional_link_attrs) { { expires_at: 5.days.from_now.to_date } }
+ it 'clears expiry date' do
page.within find_group_row(group) do
- click_button 'Remove group'
- end
-
- page.within('[role="dialog"]') do
- click_button('Remove group')
- end
-
- expect(page).not_to have_content(group.full_name)
- end
-
- context 'search in existing members' do
- it 'finds no results' do
- fill_in_filtered_search 'Search groups', with: 'testing 123'
-
- click_groups_tab
-
- expect(page).not_to have_content(group.full_name)
- end
+ expect(page).to have_content(/in \d days/)
- it 'finds results' do
- fill_in_filtered_search 'Search groups', with: group.full_name
+ find('[data-testid="clear-button"]').click
- click_groups_tab
+ wait_for_requests
- expect(members_table).to have_content(group.full_name)
+ expect(page).to have_content('No expiration set')
end
end
end
- context 'when `vue_project_members_list` feature flag is disabled' do
- before do
- stub_feature_flags(vue_project_members_list: false)
-
- visit project_project_members_path(project)
- click_groups_tab
- end
-
- it 'updates group access level' do
- click_button group_link.human_access
-
- page.within '.dropdown-menu' do
- click_link 'Guest'
- end
-
- wait_for_requests
-
- visit project_project_members_path(project)
-
- click_groups_tab
+ it 'deletes group link' do
+ expect(page).to have_content(group.full_name)
- expect(first('.group_member')).to have_content('Guest')
+ page.within find_group_row(group) do
+ click_button 'Remove group'
end
- it 'updates expiry date' do
- expires_at_field = "member_expires_at_#{group.id}"
- fill_in expires_at_field, with: 3.days.from_now.to_date
-
- find_field(expires_at_field).native.send_keys :enter
- wait_for_requests
-
- page.within(find('li.group_member')) do
- expect(page).to have_content('Expires in 3 days')
- end
+ page.within('[role="dialog"]') do
+ click_button('Remove group')
end
- context 'when link has expiry date set' do
- let(:additional_link_attrs) { { expires_at: 3.days.from_now.to_date } }
-
- it 'clears expiry date' do
- page.within(find('li.group_member')) do
- expect(page).to have_content('Expires in 3 days')
-
- page.within(find('.js-edit-member-form')) do
- find('.js-clear-input').click
- end
-
- wait_for_requests
+ expect(page).not_to have_content(group.full_name)
+ end
- expect(page).not_to have_content('Expires in')
- end
- end
- end
+ context 'search in existing members' do
+ it 'finds no results' do
+ fill_in_filtered_search 'Search groups', with: 'testing 123'
- it 'deletes group link' do
- page.within(first('.group_member')) do
- accept_confirm { find('.btn-danger').click }
- end
- wait_for_requests
+ click_groups_tab
- expect(page).not_to have_selector('.group_member')
+ expect(page).not_to have_content(group.full_name)
end
- context 'search in existing members' do
- it 'finds no results' do
- page.within '.user-search-form' do
- fill_in 'search_groups', with: 'testing 123'
- find('.user-search-btn').click
- end
-
- click_groups_tab
-
- expect(page).not_to have_selector('.group_member')
- end
-
- it 'finds results' do
- page.within '.user-search-form' do
- fill_in 'search_groups', with: group.name
- find('.user-search-btn').click
- end
+ it 'finds results' do
+ fill_in_filtered_search 'Search groups', with: group.full_name
- click_groups_tab
+ click_groups_tab
- expect(page).to have_selector('.group_member', count: 1)
- end
+ expect(members_table).to have_content(group.full_name)
end
end
diff --git a/spec/features/projects/members/invite_group_spec.rb b/spec/features/projects/members/invite_group_spec.rb
index f0d115fef1d..83ba2533a73 100644
--- a/spec/features/projects/members/invite_group_spec.rb
+++ b/spec/features/projects/members/invite_group_spec.rb
@@ -41,46 +41,20 @@ RSpec.describe 'Project > Members > Invite group', :js do
context 'when the group has "Share with group lock" disabled' do
it_behaves_like 'the project can be shared with groups'
- context 'when `vue_project_members_list` feature flag is enabled' do
- it 'the project can be shared with another group' do
- visit project_project_members_path(project)
+ it 'the project can be shared with another group' do
+ visit project_project_members_path(project)
- expect(page).not_to have_link 'Groups'
+ expect(page).not_to have_link 'Groups'
- click_on 'invite-group-tab'
+ click_on 'invite-group-tab'
- select2 group_to_share_with.id, from: '#link_group_id'
- page.find('body').click
- find('.btn-success').click
+ select2 group_to_share_with.id, from: '#link_group_id'
+ page.find('body').click
+ find('.btn-confirm').click
- click_link 'Groups'
+ click_link 'Groups'
- expect(members_table).to have_content(group_to_share_with.name)
- end
- end
-
- context 'when `vue_project_members_list` feature flag is disabled' do
- before do
- stub_feature_flags(vue_project_members_list: false)
- end
-
- it 'the project can be shared with another group' do
- visit project_project_members_path(project)
-
- expect(page).not_to have_link 'Groups'
-
- click_on 'invite-group-tab'
-
- select2 group_to_share_with.id, from: '#link_group_id'
- page.find('body').click
- find('.btn-success').click
-
- click_link 'Groups'
-
- page.within('[data-testid="project-member-groups"]') do
- expect(page).to have_content(group_to_share_with.name)
- end
- end
+ expect(members_table).to have_content(group_to_share_with.name)
end
end
@@ -159,36 +133,15 @@ RSpec.describe 'Project > Members > Invite group', :js do
fill_in 'expires_at_groups', with: 5.days.from_now.strftime('%Y-%m-%d')
click_on 'invite-group-tab'
- find('.btn-success').click
- end
-
- context 'when `vue_project_members_list` feature flag is enabled' do
- it 'the group link shows the expiration time with a warning class' do
- setup
- click_link 'Groups'
-
- expect(find_group_row(group)).to have_content(/in \d days/)
- expect(find_group_row(group)).to have_selector('.gl-text-orange-500')
- end
+ find('.btn-confirm').click
end
- context 'when `vue_project_members_list` feature flag is disabled' do
- before do
- stub_feature_flags(vue_project_members_list: false)
- end
-
- it 'the group link shows the expiration time with a warning class' do
- setup
- click_link 'Groups'
+ it 'the group link shows the expiration time with a warning class' do
+ setup
+ click_link 'Groups'
- page.within('[data-testid="project-member-groups"]') do
- # Using distance_of_time_in_words_to_now because it is not the same as
- # subtraction, and this way avoids time zone issues as well
- expires_in_text = distance_of_time_in_words_to_now(project.project_group_links.first.expires_at)
- expect(page).to have_content(expires_in_text)
- expect(page).to have_selector('.text-warning')
- end
- end
+ expect(find_group_row(group)).to have_content(/in \d days/)
+ expect(find_group_row(group)).to have_selector('.gl-text-orange-500')
end
end
diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb
index b0fe5b9c48a..0830585da9b 100644
--- a/spec/features/projects/members/list_spec.rb
+++ b/spec/features/projects/members/list_spec.rb
@@ -2,232 +2,192 @@
require 'spec_helper'
-RSpec.describe 'Project members list' do
+RSpec.describe 'Project members list', :js do
include Select2Helper
+ include Spec::Support::Helpers::Features::MembersHelpers
let(:user1) { create(:user, name: 'John Doe') }
let(:user2) { create(:user, name: 'Mary Jane') }
let(:group) { create(:group) }
- let(:project) { create(:project, namespace: group) }
+ let(:project) { create(:project, :internal, namespace: group) }
before do
- stub_feature_flags(invite_members_group_modal: false)
+ stub_feature_flags(invite_members_group_modal: true)
sign_in(user1)
group.add_owner(user1)
end
- context 'when `vue_project_members_list` feature flag is enabled', :js do
- include Spec::Support::Helpers::Features::MembersHelpers
+ it 'show members from project and group' do
+ project.add_developer(user2)
- it 'pushes `vue_project_members_list` feature flag to the frontend' do
- visit_members_page
-
- expect(page).to have_pushed_frontend_feature_flags(vueProjectMembersList: true)
- end
+ visit_members_page
- it 'show members from project and group' do
- project.add_developer(user2)
-
- visit_members_page
-
- expect(first_row).to have_content(user1.name)
- expect(second_row).to have_content(user2.name)
- end
+ expect(first_row).to have_content(user1.name)
+ expect(second_row).to have_content(user2.name)
+ end
- it 'show user once if member of both group and project' do
- project.add_developer(user1)
+ it 'show user once if member of both group and project' do
+ project.add_developer(user1)
- visit_members_page
+ visit_members_page
- expect(first_row).to have_content(user1.name)
- expect(second_row).to be_blank
- end
+ expect(first_row).to have_content(user1.name)
+ expect(second_row).to be_blank
+ end
- it 'update user access level', :js do
- project.add_developer(user2)
+ it 'update user access level' do
+ project.add_developer(user2)
- visit_members_page
+ visit_members_page
- page.within find_member_row(user2) do
- click_button('Developer')
- click_button('Reporter')
+ page.within find_member_row(user2) do
+ click_button('Developer')
+ click_button('Reporter')
- expect(page).to have_button('Reporter')
- end
+ expect(page).to have_button('Reporter')
end
+ end
- it 'add user to project', :js do
- visit_members_page
+ it 'add user to project' do
+ visit_members_page
- add_user(user2.id, 'Reporter')
+ add_user(user2.name, 'Reporter')
- page.within find_member_row(user2) do
- expect(page).to have_button('Reporter')
- end
+ page.within find_member_row(user2) do
+ expect(page).to have_button('Reporter')
end
+ end
- it 'remove user from project', :js do
- other_user = create(:user)
- project.add_developer(other_user)
-
- visit_members_page
-
- # Open modal
- page.within find_member_row(other_user) do
- click_button 'Remove member'
- end
+ it 'uses ProjectMember access_level_roles for the invite members modal access option' do
+ visit_members_page
- page.within('[role="dialog"]') do
- expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
- click_button('Remove member')
- end
+ click_on 'Invite members'
- wait_for_requests
+ click_on 'Guest'
+ wait_for_requests
- expect(members_table).not_to have_content(other_user.name)
+ page.within '.dropdown-menu' do
+ expect(page).to have_button('Guest')
+ expect(page).to have_button('Reporter')
+ expect(page).to have_button('Developer')
+ expect(page).to have_button('Maintainer')
+ expect(page).not_to have_button('Owner')
end
+ end
- it 'invite user to project', :js do
- visit_members_page
+ it 'remove user from project' do
+ other_user = create(:user)
+ project.add_developer(other_user)
- add_user('test@example.com', 'Reporter')
+ visit_members_page
- click_link 'Invited'
+ # Open modal
+ page.within find_member_row(other_user) do
+ click_button 'Remove member'
+ end
- page.within find_invited_member_row('test@example.com') do
- expect(page).to have_button('Reporter')
- end
+ page.within('[role="dialog"]') do
+ expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
+ click_button('Remove member')
end
- context 'project bots' do
- let(:project_bot) { create(:user, :project_bot, name: 'project_bot') }
+ wait_for_requests
- before do
- project.add_maintainer(project_bot)
- end
+ expect(members_table).not_to have_content(other_user.name)
+ end
- it 'does not show form used to change roles and "Expiration date" or the remove user button' do
- visit_members_page
+ it 'invite user to project' do
+ visit_members_page
- page.within find_member_row(project_bot) do
- expect(page).not_to have_button('Maintainer')
- expect(page).to have_field('Expiration date', disabled: true)
- expect(page).not_to have_button('Remove member')
- end
- end
+ add_user('test@example.com', 'Reporter')
+
+ click_link 'Invited'
+
+ page.within find_invited_member_row('test@example.com') do
+ expect(page).to have_button('Reporter')
end
end
- context 'when `vue_project_members_list` feature flag is disabled' do
- include Spec::Support::Helpers::Features::ListRowsHelpers
+ context 'project bots' do
+ let(:project_bot) { create(:user, :project_bot, name: 'project_bot') }
before do
- stub_feature_flags(vue_project_members_list: false)
+ project.add_maintainer(project_bot)
end
- it 'show members from project and group' do
- project.add_developer(user2)
-
+ it 'does not show form used to change roles and "Expiration date" or the remove user button' do
visit_members_page
- expect(first_row.text).to include(user1.name)
- expect(second_row.text).to include(user2.name)
+ page.within find_member_row(project_bot) do
+ expect(page).not_to have_button('Maintainer')
+ expect(page).to have_field('Expiration date', disabled: true)
+ expect(page).not_to have_button('Remove member')
+ end
end
+ end
- it 'show user once if member of both group and project' do
- project.add_developer(user1)
-
- visit_members_page
+ describe 'when user has 2FA enabled' do
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:user_with_2fa) { create(:user, :two_factor_via_otp) }
- expect(first_row.text).to include(user1.name)
- expect(second_row).to be_blank
+ before do
+ project.add_guest(user_with_2fa)
end
- it 'update user access level', :js do
- project.add_developer(user2)
+ it 'shows 2FA badge to user with "Maintainer" access level' do
+ project.add_maintainer(user1)
visit_members_page
- page.within(second_row) do
- click_button('Developer')
- click_link('Reporter')
-
- expect(page).to have_button('Reporter')
- end
+ expect(find_member_row(user_with_2fa)).to have_content('2FA')
end
- it 'add user to project', :js do
- visit_members_page
+ it 'shows 2FA badge to admins' do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
- add_user(user2.id, 'Reporter')
+ visit_members_page
- page.within(second_row) do
- expect(page).to have_content(user2.name)
- expect(page).to have_button('Reporter')
- end
+ expect(find_member_row(user_with_2fa)).to have_content('2FA')
end
- it 'remove user from project', :js do
- other_user = create(:user)
- project.add_developer(other_user)
+ it 'does not show 2FA badge to users with access level below "Maintainer"' do
+ group.add_developer(user1)
visit_members_page
- # Open modal
- find(:css, 'li.project_member', text: other_user.name).find(:css, 'button.btn-danger').click
-
- expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
-
- click_on('Remove member')
-
- wait_for_requests
-
- expect(page).not_to have_content(other_user.name)
- expect(project.users).not_to include(other_user)
+ expect(find_member_row(user_with_2fa)).not_to have_content('2FA')
end
- it 'invite user to project', :js do
- visit_members_page
-
- add_user('test@example.com', 'Reporter')
+ it 'shows 2FA badge to themselves' do
+ sign_in(user_with_2fa)
- click_link 'Invited'
+ visit_members_page
- page.within(first_row) do
- expect(page).to have_content('test@example.com')
- expect(page).to have_content('Invited')
- expect(page).to have_button('Reporter')
- end
+ expect(find_member_row(user_with_2fa)).to have_content('2FA')
end
+ end
- context 'project bots' do
- let(:project_bot) { create(:user, :project_bot, name: 'project_bot') }
-
- before do
- project.add_maintainer(project_bot)
- end
+ private
- it 'does not show form used to change roles and "Expiration date" or the remove user button' do
- project_member = project.project_members.find_by(user_id: project_bot.id)
+ def add_user(id, role)
+ click_on 'Invite members'
- visit_members_page
+ page.within '#invite-members-modal' do
+ fill_in 'Search for members to invite', with: id
- expect(page).not_to have_selector("#edit_project_member_#{project_member.id}")
- expect(page).to have_no_selector("#project_member_#{project_member.id} .btn-danger")
- end
- end
- end
+ wait_for_requests
+ click_button id
- private
+ click_button 'Guest'
+ wait_for_requests
+ click_button role
- def add_user(id, role)
- page.within ".invite-users-form" do
- select2(id, from: "#user_ids", multiple: true)
- select(role, from: "access_level")
+ click_button 'Invite'
end
- click_button "Invite"
+ page.refresh
end
def visit_members_page
diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
index 1127c64e0c7..d22097a2f6f 100644
--- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
+++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
@@ -18,107 +18,51 @@ RSpec.describe 'Projects > Members > Maintainer adds member with expiration date
sign_in(maintainer)
end
- context 'when `vue_project_members_list` feature flag is enabled' do
- it 'expiration date is displayed in the members list' do
- stub_feature_flags(invite_members_group_modal: false)
+ it 'expiration date is displayed in the members list' do
+ stub_feature_flags(invite_members_group_modal: false)
- visit project_project_members_path(project)
+ visit project_project_members_path(project)
- page.within '.invite-users-form' do
- select2(new_member.id, from: '#user_ids', multiple: true)
+ page.within '.invite-users-form' do
+ select2(new_member.id, from: '#user_ids', multiple: true)
- fill_in 'expires_at', with: 5.days.from_now.to_date
- find_field('expires_at').native.send_keys :enter
+ fill_in 'expires_at', with: 5.days.from_now.to_date
+ find_field('expires_at').native.send_keys :enter
- click_on 'Invite'
- end
-
- page.within find_member_row(new_member) do
- expect(page).to have_content(/in \d days/)
- end
- end
-
- it 'changes expiration date' do
- project.team.add_users([new_member.id], :developer, expires_at: 3.days.from_now.to_date)
- visit project_project_members_path(project)
-
- page.within find_member_row(new_member) do
- fill_in 'Expiration date', with: 5.days.from_now.to_date
- find_field('Expiration date').native.send_keys :enter
-
- wait_for_requests
-
- expect(page).to have_content(/in \d days/)
- end
+ click_on 'Invite'
end
- it 'clears expiration date' do
- project.team.add_users([new_member.id], :developer, expires_at: 5.days.from_now.to_date)
- visit project_project_members_path(project)
-
- page.within find_member_row(new_member) do
- expect(page).to have_content(/in \d days/)
-
- find('[data-testid="clear-button"]').click
-
- wait_for_requests
-
- expect(page).to have_content('No expiration set')
- end
+ page.within find_member_row(new_member) do
+ expect(page).to have_content(/in \d days/)
end
end
- context 'when `vue_project_members_list` feature flag is disabled' do
- before do
- stub_feature_flags(vue_project_members_list: false)
- end
-
- it 'expiration date is displayed in the members list' do
- stub_feature_flags(invite_members_group_modal: false)
-
- visit project_project_members_path(project)
-
- page.within '.invite-users-form' do
- select2(new_member.id, from: '#user_ids', multiple: true)
-
- fill_in 'expires_at', with: 3.days.from_now.to_date
- find_field('expires_at').native.send_keys :enter
+ it 'changes expiration date' do
+ project.team.add_users([new_member.id], :developer, expires_at: 3.days.from_now.to_date)
+ visit project_project_members_path(project)
- click_on 'Invite'
- end
+ page.within find_member_row(new_member) do
+ fill_in 'Expiration date', with: 5.days.from_now.to_date
+ find_field('Expiration date').native.send_keys :enter
- page.within "#project_member_#{project_member_id}" do
- expect(page).to have_content('Expires in 3 days')
- end
- end
-
- it 'changes expiration date' do
- project.team.add_users([new_member.id], :developer, expires_at: 1.day.from_now.to_date)
- visit project_project_members_path(project)
-
- page.within "#project_member_#{project_member_id}" do
- fill_in 'Expiration date', with: 3.days.from_now.to_date
- find_field('Expiration date').native.send_keys :enter
+ wait_for_requests
- wait_for_requests
-
- expect(page).to have_content('Expires in 3 days')
- end
+ expect(page).to have_content(/in \d days/)
end
+ end
- it 'clears expiration date' do
- project.team.add_users([new_member.id], :developer, expires_at: 3.days.from_now.to_date)
- visit project_project_members_path(project)
+ it 'clears expiration date' do
+ project.team.add_users([new_member.id], :developer, expires_at: 5.days.from_now.to_date)
+ visit project_project_members_path(project)
- page.within "#project_member_#{project_member_id}" do
- expect(page).to have_content('Expires in 3 days')
+ page.within find_member_row(new_member) do
+ expect(page).to have_content(/in \d days/)
- find('.js-clear-input').click
+ find('[data-testid="clear-button"]').click
- wait_for_requests
+ wait_for_requests
- expect(page).not_to have_content('Expires in')
- end
+ expect(page).to have_content('No expiration set')
end
end
diff --git a/spec/features/projects/members/sorting_spec.rb b/spec/features/projects/members/sorting_spec.rb
index 3c132747bc4..653564d1566 100644
--- a/spec/features/projects/members/sorting_spec.rb
+++ b/spec/features/projects/members/sorting_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Projects > Members > Sorting' do
+RSpec.describe 'Projects > Members > Sorting', :js do
include Spec::Support::Helpers::Features::MembersHelpers
let(:maintainer) { create(:user, name: 'John Doe') }
@@ -15,165 +15,85 @@ RSpec.describe 'Projects > Members > Sorting' do
sign_in(maintainer)
end
- context 'when `vue_project_members_list` feature flag is enabled', :js do
- it 'sorts by account by default' do
- visit_members_list(sort: nil)
+ it 'sorts by account by default' do
+ visit_members_list(sort: nil)
- expect(first_row).to have_content(maintainer.name)
- expect(second_row).to have_content(developer.name)
+ expect(first_row).to have_content(maintainer.name)
+ expect(second_row).to have_content(developer.name)
- expect_sort_by('Account', :asc)
- end
-
- it 'sorts by max role ascending' do
- visit_members_list(sort: :access_level_asc)
-
- expect(first_row).to have_content(developer.name)
- expect(second_row).to have_content(maintainer.name)
-
- expect_sort_by('Max role', :asc)
- end
-
- it 'sorts by max role descending' do
- visit_members_list(sort: :access_level_desc)
-
- expect(first_row).to have_content(maintainer.name)
- expect(second_row).to have_content(developer.name)
-
- expect_sort_by('Max role', :desc)
- end
-
- it 'sorts by access granted ascending' do
- visit_members_list(sort: :last_joined)
-
- expect(first_row).to have_content(maintainer.name)
- expect(second_row).to have_content(developer.name)
-
- expect_sort_by('Access granted', :asc)
- end
-
- it 'sorts by access granted descending' do
- visit_members_list(sort: :oldest_joined)
-
- expect(first_row).to have_content(developer.name)
- expect(second_row).to have_content(maintainer.name)
-
- expect_sort_by('Access granted', :desc)
- end
-
- it 'sorts by account ascending' do
- visit_members_list(sort: :name_asc)
-
- expect(first_row).to have_content(maintainer.name)
- expect(second_row).to have_content(developer.name)
-
- expect_sort_by('Account', :asc)
- end
-
- it 'sorts by account descending' do
- visit_members_list(sort: :name_desc)
-
- expect(first_row).to have_content(developer.name)
- expect(second_row).to have_content(maintainer.name)
-
- expect_sort_by('Account', :desc)
- end
+ expect_sort_by('Account', :asc)
+ end
- it 'sorts by last sign-in ascending', :clean_gitlab_redis_shared_state do
- visit_members_list(sort: :recent_sign_in)
+ it 'sorts by max role ascending' do
+ visit_members_list(sort: :access_level_asc)
- expect(first_row).to have_content(maintainer.name)
- expect(second_row).to have_content(developer.name)
+ expect(first_row).to have_content(developer.name)
+ expect(second_row).to have_content(maintainer.name)
- expect_sort_by('Last sign-in', :asc)
- end
+ expect_sort_by('Max role', :asc)
+ end
- it 'sorts by last sign-in descending', :clean_gitlab_redis_shared_state do
- visit_members_list(sort: :oldest_sign_in)
+ it 'sorts by max role descending' do
+ visit_members_list(sort: :access_level_desc)
- expect(first_row).to have_content(developer.name)
- expect(second_row).to have_content(maintainer.name)
+ expect(first_row).to have_content(maintainer.name)
+ expect(second_row).to have_content(developer.name)
- expect_sort_by('Last sign-in', :desc)
- end
+ expect_sort_by('Max role', :desc)
end
- context 'when `vue_project_members_list` feature flag is disabled' do
- before do
- stub_feature_flags(vue_project_members_list: false)
- end
-
- it 'sorts alphabetically by default' do
- visit_members_list(sort: nil)
+ it 'sorts by access granted ascending' do
+ visit_members_list(sort: :last_joined)
- expect(first_member).to include(maintainer.name)
- expect(second_member).to include(developer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, ascending')
- end
+ expect(first_row).to have_content(maintainer.name)
+ expect(second_row).to have_content(developer.name)
- it 'sorts by access level ascending' do
- visit_members_list(sort: :access_level_asc)
+ expect_sort_by('Access granted', :asc)
+ end
- expect(first_member).to include(developer.name)
- expect(second_member).to include(maintainer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Access level, ascending')
- end
+ it 'sorts by access granted descending' do
+ visit_members_list(sort: :oldest_joined)
- it 'sorts by access level descending' do
- visit_members_list(sort: :access_level_desc)
+ expect(first_row).to have_content(developer.name)
+ expect(second_row).to have_content(maintainer.name)
- expect(first_member).to include(maintainer.name)
- expect(second_member).to include(developer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Access level, descending')
- end
+ expect_sort_by('Access granted', :desc)
+ end
- it 'sorts by last joined' do
- visit_members_list(sort: :last_joined)
+ it 'sorts by account ascending' do
+ visit_members_list(sort: :name_asc)
- expect(first_member).to include(maintainer.name)
- expect(second_member).to include(developer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Last joined')
- end
+ expect(first_row).to have_content(maintainer.name)
+ expect(second_row).to have_content(developer.name)
- it 'sorts by oldest joined' do
- visit_members_list(sort: :oldest_joined)
+ expect_sort_by('Account', :asc)
+ end
- expect(first_member).to include(developer.name)
- expect(second_member).to include(maintainer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Oldest joined')
- end
+ it 'sorts by account descending' do
+ visit_members_list(sort: :name_desc)
- it 'sorts by name ascending' do
- visit_members_list(sort: :name_asc)
+ expect(first_row).to have_content(developer.name)
+ expect(second_row).to have_content(maintainer.name)
- expect(first_member).to include(maintainer.name)
- expect(second_member).to include(developer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, ascending')
- end
+ expect_sort_by('Account', :desc)
+ end
- it 'sorts by name descending' do
- visit_members_list(sort: :name_desc)
+ it 'sorts by last sign-in ascending', :clean_gitlab_redis_shared_state do
+ visit_members_list(sort: :recent_sign_in)
- expect(first_member).to include(developer.name)
- expect(second_member).to include(maintainer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, descending')
- end
+ expect(first_row).to have_content(maintainer.name)
+ expect(second_row).to have_content(developer.name)
- it 'sorts by recent sign in', :clean_gitlab_redis_shared_state do
- visit_members_list(sort: :recent_sign_in)
+ expect_sort_by('Last sign-in', :asc)
+ end
- expect(first_member).to include(maintainer.name)
- expect(second_member).to include(developer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Recent sign in')
- end
+ it 'sorts by last sign-in descending', :clean_gitlab_redis_shared_state do
+ visit_members_list(sort: :oldest_sign_in)
- it 'sorts by oldest sign in', :clean_gitlab_redis_shared_state do
- visit_members_list(sort: :oldest_sign_in)
+ expect(first_row).to have_content(developer.name)
+ expect(second_row).to have_content(maintainer.name)
- expect(first_member).to include(developer.name)
- expect(second_member).to include(maintainer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Oldest sign in')
- end
+ expect_sort_by('Last sign-in', :desc)
end
private
diff --git a/spec/features/projects/members/tabs_spec.rb b/spec/features/projects/members/tabs_spec.rb
index eef3395de91..471be26e126 100644
--- a/spec/features/projects/members/tabs_spec.rb
+++ b/spec/features/projects/members/tabs_spec.rb
@@ -14,6 +14,11 @@ RSpec.describe 'Projects > Members > Tabs' do
let_it_be(:invites) { create_list(:project_member, 2, :invited, project: project) }
let_it_be(:project_group_links) { create_list(:project_group_link, 2, project: project) }
+ before do
+ sign_in(user)
+ visit project_project_members_path(project)
+ end
+
shared_examples 'active "Members" tab' do
it 'displays "Members" tab' do
expect(page).to have_selector('.nav-link.active', text: 'Members')
@@ -21,11 +26,6 @@ RSpec.describe 'Projects > Members > Tabs' do
end
context 'tabs' do
- before do
- sign_in(user)
- visit project_project_members_path(project)
- end
-
where(:tab, :count) do
'Members' | 3
'Invited' | 2
@@ -44,69 +44,25 @@ RSpec.describe 'Projects > Members > Tabs' do
end
end
- context 'when `vue_project_members_list` feature flag is enabled' do
+ context 'when searching "Groups"', :js do
before do
- sign_in(user)
- visit project_project_members_path(project)
- end
-
- context 'when searching "Groups"', :js do
- before do
- click_link 'Groups'
-
- fill_in_filtered_search 'Search groups', with: 'group'
- end
-
- it 'displays "Groups" tab' do
- expect(page).to have_selector('.nav-link.active', text: 'Groups')
- end
+ click_link 'Groups'
- context 'and then searching "Members"' do
- before do
- click_link 'Members 3'
-
- fill_in_filtered_search 'Filter members', with: 'user'
- end
-
- it_behaves_like 'active "Members" tab'
- end
+ fill_in_filtered_search 'Search groups', with: 'group'
end
- end
-
- context 'when `vue_project_members_list` feature flag is disabled' do
- before do
- stub_feature_flags(vue_project_members_list: false)
- sign_in(user)
- visit project_project_members_path(project)
+ it 'displays "Groups" tab' do
+ expect(page).to have_selector('.nav-link.active', text: 'Groups')
end
- context 'when searching "Groups"', :js do
+ context 'and then searching "Members"' do
before do
- click_link 'Groups'
+ click_link 'Members 3'
- page.within '[data-testid="group-link-search-form"]' do
- fill_in 'search_groups', with: 'group'
- find('button[type="submit"]').click
- end
+ fill_in_filtered_search 'Filter members', with: 'user'
end
- it 'displays "Groups" tab' do
- expect(page).to have_selector('.nav-link.active', text: 'Groups')
- end
-
- context 'and then searching "Members"' do
- before do
- click_link 'Members 3'
-
- page.within '[data-testid="user-search-form"]' do
- fill_in 'search', with: 'user'
- find('button[type="submit"]').click
- end
- end
-
- it_behaves_like 'active "Members" tab'
- end
+ it_behaves_like 'active "Members" tab'
end
end
end
diff --git a/spec/features/projects/merge_request_button_spec.rb b/spec/features/projects/merge_request_button_spec.rb
index e3d8534ace9..9547ba8a390 100644
--- a/spec/features/projects/merge_request_button_spec.rb
+++ b/spec/features/projects/merge_request_button_spec.rb
@@ -3,11 +3,13 @@
require 'spec_helper'
RSpec.describe 'Merge Request button' do
- shared_examples 'Merge request button only shown when allowed' do
- let(:user) { create(:user) }
- let(:project) { create(:project, :public, :repository) }
- let(:forked_project) { create(:project, :public, :repository, forked_from_project: project) }
+ include ProjectForksHelper
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let(:forked_project) { fork_project(project, user, repository: true) }
+ shared_examples 'Merge request button only shown when allowed' do
context 'not logged in' do
it 'does not show Create merge request button' do
visit url
@@ -22,10 +24,16 @@ RSpec.describe 'Merge Request button' do
project.add_developer(user)
end
- it 'shows Create merge request button' do
- href = project_new_merge_request_path(project,
- merge_request: { source_branch: 'feature',
- target_branch: 'master' })
+ it 'shows Create merge request button', :js do
+ href = project_new_merge_request_path(
+ project,
+ merge_request: {
+ source_project_id: project.id,
+ source_branch: 'feature',
+ target_project_id: project.id,
+ target_branch: 'master'
+ }
+ )
visit url
@@ -75,12 +83,16 @@ RSpec.describe 'Merge Request button' do
end
context 'on own fork of project' do
- let(:user) { forked_project.owner }
-
- it 'shows Create merge request button' do
- href = project_new_merge_request_path(forked_project,
- merge_request: { source_branch: 'feature',
- target_branch: 'master' })
+ it 'shows Create merge request button', :js do
+ href = project_new_merge_request_path(
+ forked_project,
+ merge_request: {
+ source_project_id: forked_project.id,
+ source_branch: 'feature',
+ target_project_id: forked_project.id,
+ target_branch: 'master'
+ }
+ )
visit fork_url
@@ -101,11 +113,33 @@ RSpec.describe 'Merge Request button' do
end
context 'on compare page' do
+ let(:label) { 'Create merge request' }
+
it_behaves_like 'Merge request button only shown when allowed' do
- let(:label) { 'Create merge request' }
let(:url) { project_compare_path(project, from: 'master', to: 'feature') }
let(:fork_url) { project_compare_path(forked_project, from: 'master', to: 'feature') }
end
+
+ it 'shows the correct merge request button when viewing across forks', :js do
+ sign_in(user)
+ project.add_developer(user)
+
+ href = project_new_merge_request_path(
+ project,
+ merge_request: {
+ source_project_id: forked_project.id,
+ source_branch: 'feature',
+ target_project_id: project.id,
+ target_branch: 'master'
+ }
+ )
+
+ visit project_compare_path(forked_project, from: 'master', to: 'feature', from_project_id: project.id)
+
+ within("#content-body") do
+ expect(page).to have_link(label, href: href)
+ end
+ end
end
context 'on commits page' do
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index 4aabf040655..ec34640bd00 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -86,7 +86,7 @@ RSpec.describe 'New project', :js do
visit new_project_path
find('[data-qa-selector="blank_project_link"]').click
- choose(s_(key))
+ choose(key)
click_button('Create project')
page.within('#blank-project-pane') do
expect(find_field("project_visibility_level_#{level}")).to be_checked
@@ -95,33 +95,55 @@ RSpec.describe 'New project', :js do
end
context 'when group visibility is private but default is internal' do
+ let_it_be(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
+
before do
stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL)
end
- it 'has private selected' do
- group = create(:group, visibility_level: Gitlab::VisibilityLevel::PRIVATE)
- visit new_project_path(namespace_id: group.id)
- find('[data-qa-selector="blank_project_link"]').click
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it 'has private selected' do
+ visit new_project_path(namespace_id: group.id)
+ find('[data-qa-selector="blank_project_link"]').click
- page.within('#blank-project-pane') do
- expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked
+ page.within('#blank-project-pane') do
+ expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked
+ end
+ end
+ end
+
+ context 'when admin mode is disabled' do
+ it 'is not allowed' do
+ visit new_project_path(namespace_id: group.id)
+
+ expect(page).to have_content('Not Found')
end
end
end
context 'when group visibility is public but user requests private' do
+ let_it_be(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
+
before do
stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL)
end
- it 'has private selected' do
- group = create(:group, visibility_level: Gitlab::VisibilityLevel::PUBLIC)
- visit new_project_path(namespace_id: group.id, project: { visibility_level: Gitlab::VisibilityLevel::PRIVATE })
- find('[data-qa-selector="blank_project_link"]').click
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it 'has private selected' do
+ visit new_project_path(namespace_id: group.id, project: { visibility_level: Gitlab::VisibilityLevel::PRIVATE })
+ find('[data-qa-selector="blank_project_link"]').click
- page.within('#blank-project-pane') do
- expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked
+ page.within('#blank-project-pane') do
+ expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked
+ end
+ end
+ end
+
+ context 'when admin mode is disabled' do
+ it 'is not allowed' do
+ visit new_project_path(namespace_id: group.id, project: { visibility_level: Gitlab::VisibilityLevel::PRIVATE })
+
+ expect(page).to have_content('Not Found')
end
end
end
diff --git a/spec/features/projects/pages/user_edits_settings_spec.rb b/spec/features/projects/pages/user_edits_settings_spec.rb
index 3649fae17ce..6156b5243de 100644
--- a/spec/features/projects/pages/user_edits_settings_spec.rb
+++ b/spec/features/projects/pages/user_edits_settings_spec.rb
@@ -140,7 +140,7 @@ RSpec.describe 'Pages edits pages settings', :js do
before do
allow(Projects::UpdateService).to receive(:new).and_return(service)
- allow(service).to receive(:execute).and_return(status: :error, message: 'Some error has occured')
+ allow(service).to receive(:execute).and_return(status: :error, message: 'Some error has occurred')
end
it 'tries to change the setting' do
@@ -150,7 +150,7 @@ RSpec.describe 'Pages edits pages settings', :js do
click_button 'Save'
- expect(page).to have_text('Some error has occured')
+ expect(page).to have_text('Some error has occurred')
end
end
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 6421d3db2cd..9037aa5c9a8 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe 'Pipelines', :js do
sign_in(user)
stub_feature_flags(graphql_pipeline_details: false)
stub_feature_flags(graphql_pipeline_details_users: false)
+ stub_feature_flags(new_pipelines_table: false)
project.add_developer(user)
project.update!(auto_devops_attributes: { enabled: false })
@@ -519,75 +520,58 @@ RSpec.describe 'Pipelines', :js do
end
end
- shared_examples 'mini pipeline renders' do |ci_mini_pipeline_gl_dropdown_enabled|
- context 'mini pipeline graph' do
- let!(:build) do
- create(:ci_build, :pending, pipeline: pipeline,
- stage: 'build',
- name: 'build')
- end
+ context 'mini pipeline graph' do
+ let!(:build) do
+ create(:ci_build, :pending, pipeline: pipeline,
+ stage: 'build',
+ name: 'build')
+ end
- before do
- stub_feature_flags(ci_mini_pipeline_gl_dropdown: ci_mini_pipeline_gl_dropdown_enabled)
- visit_project_pipelines
- end
+ dropdown_selector = '[data-testid="mini-pipeline-graph-dropdown"]'
- let_it_be(:dropdown_toggle_selector) do
- if ci_mini_pipeline_gl_dropdown_enabled
- '[data-testid="mini-pipeline-graph-dropdown"] .dropdown-toggle'
- else
- '[data-testid="mini-pipeline-graph-dropdown-toggle"]'
- end
- end
+ before do
+ visit_project_pipelines
+ end
- it 'renders a mini pipeline graph' do
- expect(page).to have_selector('[data-testid="widget-mini-pipeline-graph"]')
- expect(page).to have_selector(dropdown_toggle_selector)
- end
+ it 'renders a mini pipeline graph' do
+ expect(page).to have_selector('[data-testid="widget-mini-pipeline-graph"]')
+ expect(page).to have_selector(dropdown_selector)
+ end
- context 'when clicking a stage badge' do
- it 'opens a dropdown' do
- find(dropdown_toggle_selector).click
+ context 'when clicking a stage badge' do
+ it 'opens a dropdown' do
+ find(dropdown_selector).click
- expect(page).to have_link build.name
- end
+ expect(page).to have_link build.name
+ end
- it 'is possible to cancel pending build' do
- find(dropdown_toggle_selector).click
- find('.js-ci-action').click
- wait_for_requests
+ it 'is possible to cancel pending build' do
+ find(dropdown_selector).click
+ find('.js-ci-action').click
+ wait_for_requests
- expect(build.reload).to be_canceled
- end
+ expect(build.reload).to be_canceled
end
+ end
- context 'for a failed pipeline' do
- let!(:build) do
- create(:ci_build, :failed, pipeline: pipeline,
- stage: 'build',
- name: 'build')
- end
+ context 'for a failed pipeline' do
+ let!(:build) do
+ create(:ci_build, :failed, pipeline: pipeline,
+ stage: 'build',
+ name: 'build')
+ end
- it 'displays the failure reason' do
- find(dropdown_toggle_selector).click
+ it 'displays the failure reason' do
+ find(dropdown_selector).click
- within('.js-builds-dropdown-list') do
- build_element = page.find('.mini-pipeline-graph-dropdown-item')
- expect(build_element['title']).to eq('build - failed - (unknown failure)')
- end
+ within('.js-builds-dropdown-list') do
+ build_element = page.find('.mini-pipeline-graph-dropdown-item')
+ expect(build_element['title']).to eq('build - failed - (unknown failure)')
end
end
end
end
- context 'with ci_mini_pipeline_gl_dropdown disabled' do
- it_behaves_like "mini pipeline renders", false
- end
-
- context 'with ci_mini_pipeline_gl_dropdown enabled' do
- it_behaves_like "mini pipeline renders", true
- end
-
context 'with pagination' do
before do
allow(Ci::Pipeline).to receive(:default_per_page).and_return(1)
diff --git a/spec/features/projects/releases/user_creates_release_spec.rb b/spec/features/projects/releases/user_creates_release_spec.rb
index 2acdf983cf2..9e428a0623d 100644
--- a/spec/features/projects/releases/user_creates_release_spec.rb
+++ b/spec/features/projects/releases/user_creates_release_spec.rb
@@ -33,11 +33,11 @@ RSpec.describe 'User creates release', :js do
end
it 'defaults the "Create from" dropdown to the project\'s default branch' do
- expect(page.find('.ref-selector button')).to have_content(project.default_branch)
+ expect(page.find('[data-testid="create-from-field"] .ref-selector button')).to have_content(project.default_branch)
end
- context 'when the "Save release" button is clicked', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/297507' do
- let(:tag_name) { 'v1.0' }
+ context 'when the "Save release" button is clicked' do
+ let(:tag_name) { 'v2.0.31' }
let(:release_title) { 'A most magnificent release' }
let(:release_notes) { 'Best. Release. **Ever.** :rocket:' }
let(:link_1) { { url: 'https://gitlab.example.com/runbook', title: 'An example runbook', type: 'runbook' } }
@@ -47,7 +47,7 @@ RSpec.describe 'User creates release', :js do
fill_out_form_and_submit
end
- it 'creates a new release when "Create release" is clicked', :aggregate_failures do
+ it 'creates a new release when "Create release" is clicked and redirects to the release\'s dedicated page', :aggregate_failures do
release = project.releases.last
expect(release.tag).to eq(tag_name)
@@ -65,10 +65,6 @@ RSpec.describe 'User creates release', :js do
link = release.links.find { |l| l.link_type == link_2[:type] }
expect(link.url).to eq(link_2[:url])
expect(link.name).to eq(link_2[:title])
- end
-
- it 'redirects to the dedicated page for the newly created release' do
- release = project.releases.last
expect(page).to have_current_path(project_release_path(project, release))
end
@@ -116,30 +112,27 @@ RSpec.describe 'User creates release', :js do
end
def fill_out_form_and_submit
- fill_tag_name(tag_name)
+ select_new_tag_name(tag_name)
select_create_from(branch.name)
fill_release_title(release_title)
- select_milestone(milestone_1.title, and_tab: false)
+ select_milestone(milestone_1.title)
select_milestone(milestone_2.title)
- # Focus the "Release notes" field by clicking instead of tabbing
- # because tabbing to the field requires too many tabs
- # (see https://gitlab.com/gitlab-org/gitlab/-/issues/238619)
- find_field('Release notes').click
fill_release_notes(release_notes)
- # Tab past the "assets" documentation link
- focused_element.send_keys(:tab)
-
fill_asset_link(link_1)
add_another_asset_link
fill_asset_link(link_2)
- # Submit using the Control+Enter shortcut
- focused_element.send_keys([:control, :enter])
+ # Click on the body in order to trigger a `blur` event on the current field.
+ # This triggers the form's validation to run so that the
+ # "Create release" button is enabled and clickable.
+ page.find('body').click
+
+ click_button('Create release')
wait_for_all_requests
end
diff --git a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb
index 32519b14d4e..88812fc188b 100644
--- a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb
+++ b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb
@@ -113,7 +113,7 @@ RSpec.describe 'Set up Mattermost slash commands', :js do
click_link 'Add to Mattermost'
- expect(page).to have_selector('.alert')
+ expect(page).to have_selector('.gl-alert')
expect(page).to have_content('test mattermost error message')
end
diff --git a/spec/features/projects/settings/operations_settings_spec.rb b/spec/features/projects/settings/operations_settings_spec.rb
index 1d9f256a819..fe0ee52e4fa 100644
--- a/spec/features/projects/settings/operations_settings_spec.rb
+++ b/spec/features/projects/settings/operations_settings_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do
describe 'Settings > Operations' do
describe 'Incidents' do
let(:create_issue) { 'Create an incident. Incidents are created for each alert triggered.' }
- let(:send_email) { 'Send a separate email notification to Developers.' }
+ let(:send_email) { 'Send a single email notification to Owners and Maintainers for new alerts.' }
before do
create(:project_incident_management_setting, send_email: true, project: project)
@@ -162,13 +162,13 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do
end
expect(page).to have_content('Grafana URL')
- expect(page).to have_content('API Token')
- expect(page).to have_button('Save Changes')
+ expect(page).to have_content('API token')
+ expect(page).to have_button('Save changes')
fill_in('grafana-url', with: 'http://gitlab-test.grafana.net')
fill_in('grafana-token', with: 'token')
- click_button('Save Changes')
+ click_button('Save changes')
wait_for_requests
diff --git a/spec/features/projects/settings/service_desk_setting_spec.rb b/spec/features/projects/settings/service_desk_setting_spec.rb
index d31913d2dcf..50451075db5 100644
--- a/spec/features/projects/settings/service_desk_setting_spec.rb
+++ b/spec/features/projects/settings/service_desk_setting_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Service Desk Setting', :js do
+RSpec.describe 'Service Desk Setting', :js, :clean_gitlab_redis_cache do
let(:project) { create(:project_empty_repo, :private, service_desk_enabled: false) }
let(:presenter) { project.present(current_user: user) }
let(:user) { create(:user) }
@@ -66,5 +66,48 @@ RSpec.describe 'Service Desk Setting', :js do
expect(find('[data-testid="incoming-email"]').value).to eq('address-suffix@example.com')
end
+
+ context 'issue description templates' do
+ let_it_be(:issuable_project_template_files) do
+ {
+ '.gitlab/issue_templates/project-issue-bar.md' => 'Project Issue Template Bar',
+ '.gitlab/issue_templates/project-issue-foo.md' => 'Project Issue Template Foo'
+ }
+ end
+
+ let_it_be(:issuable_group_template_files) do
+ {
+ '.gitlab/issue_templates/group-issue-bar.md' => 'Group Issue Template Bar',
+ '.gitlab/issue_templates/group-issue-foo.md' => 'Group Issue Template Foo'
+ }
+ end
+
+ let_it_be_with_reload(:group) { create(:group)}
+ let_it_be_with_reload(:project) { create(:project, :custom_repo, group: group, files: issuable_project_template_files) }
+ let_it_be(:group_template_repo) { create(:project, :custom_repo, group: group, files: issuable_group_template_files) }
+
+ before do
+ stub_licensed_features(custom_file_templates_for_namespace: false, custom_file_templates: false)
+ group.update_columns(file_template_project_id: group_template_repo.id)
+ end
+
+ context 'when inherited_issuable_templates enabled' do
+ before do
+ stub_feature_flags(inherited_issuable_templates: true)
+ visit edit_project_path(project)
+ end
+
+ it_behaves_like 'issue description templates from current project only'
+ end
+
+ context 'when inherited_issuable_templates disabled' do
+ before do
+ stub_feature_flags(inherited_issuable_templates: false)
+ visit edit_project_path(project)
+ end
+
+ it_behaves_like 'issue description templates from current project only'
+ end
+ end
end
end
diff --git a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb
index e8e32d93f7b..397c334a2b8 100644
--- a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb
+++ b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb
@@ -133,7 +133,7 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do
it 'when unchecked sets :remove_source_branch_after_merge to false' do
uncheck('project_remove_source_branch_after_merge')
within('.merge-request-settings-form') do
- find('.qa-save-merge-request-changes')
+ find('.rspec-save-merge-request-changes')
click_on('Save changes')
end
@@ -157,7 +157,7 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do
choose('project_project_setting_attributes_squash_option_default_on')
within('.merge-request-settings-form') do
- find('.qa-save-merge-request-changes')
+ find('.rspec-save-merge-request-changes')
click_on('Save changes')
end
@@ -172,7 +172,7 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do
choose('project_project_setting_attributes_squash_option_always')
within('.merge-request-settings-form') do
- find('.qa-save-merge-request-changes')
+ find('.rspec-save-merge-request-changes')
click_on('Save changes')
end
@@ -187,7 +187,7 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do
choose('project_project_setting_attributes_squash_option_never')
within('.merge-request-settings-form') do
- find('.qa-save-merge-request-changes')
+ find('.rspec-save-merge-request-changes')
click_on('Save changes')
end
diff --git a/spec/features/projects/settings/user_manages_project_members_spec.rb b/spec/features/projects/settings/user_manages_project_members_spec.rb
index 0d22da34b91..b237e7e8ce7 100644
--- a/spec/features/projects/settings/user_manages_project_members_spec.rb
+++ b/spec/features/projects/settings/user_manages_project_members_spec.rb
@@ -19,123 +19,54 @@ RSpec.describe 'Projects > Settings > User manages project members' do
sign_in(user)
end
- context 'when `vue_project_members_list` feature flag is enabled' do
- it 'cancels a team member', :js do
- visit(project_project_members_path(project))
+ it 'cancels a team member', :js do
+ visit(project_project_members_path(project))
- page.within find_member_row(user_dmitriy) do
- click_button 'Remove member'
- end
-
- page.within('[role="dialog"]') do
- expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
- click_button('Remove member')
- end
-
- visit(project_project_members_path(project))
-
- expect(members_table).not_to have_content(user_dmitriy.name)
- expect(members_table).not_to have_content(user_dmitriy.username)
+ page.within find_member_row(user_dmitriy) do
+ click_button 'Remove member'
end
- it 'imports a team from another project', :js do
- stub_feature_flags(invite_members_group_modal: false)
-
- project2.add_maintainer(user)
- project2.add_reporter(user_mike)
-
- visit(project_project_members_path(project))
-
- page.within('.invite-users-form') do
- click_link('Import')
- end
-
- select2(project2.id, from: '#source_project_id')
- click_button('Import project members')
-
- expect(find_member_row(user_mike)).to have_content('Reporter')
+ page.within('[role="dialog"]') do
+ expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
+ click_button('Remove member')
end
- it 'shows all members of project shared group', :js do
- group.add_owner(user)
- group.add_developer(user_dmitriy)
-
- share_link = project.project_group_links.new(group_access: Gitlab::Access::MAINTAINER)
- share_link.group_id = group.id
- share_link.save!
-
- visit(project_project_members_path(project))
+ visit(project_project_members_path(project))
- click_link 'Groups'
-
- expect(find_group_row(group)).to have_content('Maintainer')
- end
+ expect(members_table).not_to have_content(user_dmitriy.name)
+ expect(members_table).not_to have_content(user_dmitriy.username)
end
- context 'when `vue_project_members_list` feature flag is disabled' do
- before do
- stub_feature_flags(vue_project_members_list: false)
- end
+ it 'imports a team from another project', :js do
+ stub_feature_flags(invite_members_group_modal: false)
- it 'cancels a team member', :js do
- visit(project_project_members_path(project))
+ project2.add_maintainer(user)
+ project2.add_reporter(user_mike)
- project_member = project.project_members.find_by(user_id: user_dmitriy.id)
+ visit(project_project_members_path(project))
- page.within("#project_member_#{project_member.id}") do
- # Open modal
- click_on('Remove user from project')
- end
-
- expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
-
- click_on('Remove member')
-
- visit(project_project_members_path(project))
-
- expect(page).not_to have_content(user_dmitriy.name)
- expect(page).not_to have_content(user_dmitriy.username)
+ page.within('.invite-users-form') do
+ click_link('Import')
end
- it 'imports a team from another project' do
- stub_feature_flags(invite_members_group_modal: false)
-
- project2.add_maintainer(user)
- project2.add_reporter(user_mike)
-
- visit(project_project_members_path(project))
+ select2(project2.id, from: '#source_project_id')
+ click_button('Import project members')
- page.within('.invite-users-form') do
- click_link('Import')
- end
-
- select(project2.full_name, from: 'source_project_id')
- click_button('Import')
-
- project_member = project.project_members.find_by(user_id: user_mike.id)
-
- page.within("#project_member_#{project_member.id}") do
- expect(page).to have_content('Mike')
- expect(page).to have_content('Reporter')
- end
- end
+ expect(find_member_row(user_mike)).to have_content('Reporter')
+ end
- it 'shows all members of project shared group', :js do
- group.add_owner(user)
- group.add_developer(user_dmitriy)
+ it 'shows all members of project shared group', :js do
+ group.add_owner(user)
+ group.add_developer(user_dmitriy)
- share_link = project.project_group_links.new(group_access: Gitlab::Access::MAINTAINER)
- share_link.group_id = group.id
- share_link.save!
+ share_link = project.project_group_links.new(group_access: Gitlab::Access::MAINTAINER)
+ share_link.group_id = group.id
+ share_link.save!
- visit(project_project_members_path(project))
+ visit(project_project_members_path(project))
- click_link 'Groups'
+ click_link 'Groups'
- page.within('[data-testid="project-member-groups"]') do
- expect(page).to have_content('OpenSource')
- expect(first('.group_member')).to have_content('Maintainer')
- end
- end
+ expect(find_group_row(group)).to have_content('Maintainer')
end
end
diff --git a/spec/features/projects/settings/user_searches_in_settings_spec.rb b/spec/features/projects/settings/user_searches_in_settings_spec.rb
new file mode 100644
index 00000000000..4c5b39d5282
--- /dev/null
+++ b/spec/features/projects/settings/user_searches_in_settings_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User searches project settings', :js do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository, namespace: user.namespace) }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'in general settings page' do
+ let(:visit_path) { edit_project_path(project) }
+
+ it_behaves_like 'can search settings with feature flag check', 'Naming', 'Visibility'
+ end
+
+ context 'in Repository page' do
+ before do
+ visit project_settings_repository_path(project)
+ end
+
+ it_behaves_like 'can search settings', 'Deploy keys', 'Mirroring repositories'
+ end
+
+ context 'in CI/CD page' do
+ before do
+ visit project_settings_ci_cd_path(project)
+ end
+
+ it_behaves_like 'can search settings', 'General pipelines', 'Auto DevOps'
+ end
+
+ context 'in Operations page' do
+ before do
+ visit project_settings_operations_path(project)
+ end
+
+ it_behaves_like 'can search settings', 'Alerts', 'Error tracking'
+ end
+end
diff --git a/spec/features/projects/show/user_manages_notifications_spec.rb b/spec/features/projects/show/user_manages_notifications_spec.rb
index 5f7d9b0963b..80dae4ec386 100644
--- a/spec/features/projects/show/user_manages_notifications_spec.rb
+++ b/spec/features/projects/show/user_manages_notifications_spec.rb
@@ -6,38 +6,36 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do
let(:project) { create(:project, :public, :repository) }
before do
- stub_feature_flags(vue_notification_dropdown: false)
sign_in(project.owner)
end
def click_notifications_button
- first('.notifications-btn').click
+ first('[data-testid="notification-dropdown"]').click
end
it 'changes the notification setting' do
visit project_path(project)
click_notifications_button
- click_link 'On mention'
+ click_button 'On mention'
- page.within('.notification-dropdown') do
- expect(page).not_to have_css('.gl-spinner')
- end
+ wait_for_requests
click_notifications_button
- expect(find('.update-notification.is-active')).to have_content('On mention')
- expect(page).to have_css('.notifications-icon[data-testid="notifications-icon"]')
+
+ page.within first('[data-testid="notification-dropdown"]') do
+ expect(page.find('.gl-new-dropdown-item.is-active')).to have_content('On mention')
+ expect(page).to have_css('[data-testid="notifications-icon"]')
+ end
end
it 'changes the notification setting to disabled' do
visit project_path(project)
click_notifications_button
- click_link 'Disabled'
+ click_button 'Disabled'
- page.within('.notification-dropdown') do
- expect(page).not_to have_css('.gl-spinner')
+ page.within first('[data-testid="notification-dropdown"]') do
+ expect(page).to have_css('[data-testid="notifications-off-icon"]')
end
-
- expect(page).to have_css('.notifications-icon[data-testid="notifications-off-icon"]')
end
context 'custom notification settings' do
@@ -65,11 +63,13 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do
it 'shows notification settings checkbox' do
visit project_path(project)
click_notifications_button
- page.find('a[data-notification-level="custom"]').click
+ click_button 'Custom'
+
+ wait_for_requests
- page.within('.custom-notifications-form') do
+ page.within('#custom-notifications-modal') do
email_events.each do |event_name|
- expect(page).to have_selector("input[name='notification_setting[#{event_name}]']")
+ expect(page).to have_selector("[data-testid='notification-setting-#{event_name}']")
end
end
end
@@ -80,7 +80,7 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do
it 'is disabled' do
visit project_path(project)
- expect(page).to have_selector('.notifications-btn.disabled', visible: true)
+ expect(page).to have_selector('[data-testid="notification-dropdown"] .disabled', visible: true)
end
end
end
diff --git a/spec/features/projects/show/user_uploads_files_spec.rb b/spec/features/projects/show/user_uploads_files_spec.rb
index 053598a528e..2030c4d998a 100644
--- a/spec/features/projects/show/user_uploads_files_spec.rb
+++ b/spec/features/projects/show/user_uploads_files_spec.rb
@@ -33,4 +33,24 @@ RSpec.describe 'Projects > Show > User uploads files' do
include_examples 'it uploads and commit a new file to a forked project'
end
+
+ context 'when in the empty_repo_upload experiment' do
+ before do
+ stub_experiments(empty_repo_upload: :candidate)
+
+ visit(project_path(project))
+ end
+
+ context 'with an empty repo' do
+ let(:project) { create(:project, :empty_repo, creator: user) }
+
+ include_examples 'uploads and commits a new text file via "upload file" button'
+ end
+
+ context 'with a nonempty repo' do
+ let(:project) { create(:project, :repository, creator: user) }
+
+ include_examples 'uploads and commits a new text file via "upload file" button'
+ end
+ end
end
diff --git a/spec/features/projects/user_sees_sidebar_spec.rb b/spec/features/projects/user_sees_sidebar_spec.rb
index 616c5065c07..e5ba6b503cc 100644
--- a/spec/features/projects/user_sees_sidebar_spec.rb
+++ b/spec/features/projects/user_sees_sidebar_spec.rb
@@ -201,7 +201,7 @@ RSpec.describe 'Projects > User sees sidebar' do
expect(page).to have_content 'Operations'
expect(page).not_to have_content 'Repository'
- expect(page).not_to have_content 'CI / CD'
+ expect(page).not_to have_content 'CI/CD'
expect(page).not_to have_content 'Merge Requests'
end
end
@@ -213,7 +213,7 @@ RSpec.describe 'Projects > User sees sidebar' do
visit project_path(project)
within('.nav-sidebar') do
- expect(page).to have_content 'CI / CD'
+ expect(page).to have_content 'CI/CD'
end
end
diff --git a/spec/features/projects/user_uses_shortcuts_spec.rb b/spec/features/projects/user_uses_shortcuts_spec.rb
index 13ae035e8ef..f97c8d820e3 100644
--- a/spec/features/projects/user_uses_shortcuts_spec.rb
+++ b/spec/features/projects/user_uses_shortcuts_spec.rb
@@ -155,12 +155,12 @@ RSpec.describe 'User uses shortcuts', :js do
end
end
- context 'when navigating to the CI / CD pages' do
+ context 'when navigating to the CI/CD pages' do
it 'redirects to the Jobs page' do
find('body').native.send_key('g')
find('body').native.send_key('j')
- expect(page).to have_active_navigation('CI / CD')
+ expect(page).to have_active_navigation('CI/CD')
expect(page).to have_active_sub_navigation('Jobs')
end
end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 618a256d4fb..4730679feb8 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe 'Project' do
it 'shows the command in a popover', :js do
click_link 'Show command'
- expect(page).to have_css('.popover .push-to-create-popover #push_to_create_tip')
+ expect(page).to have_css('.popover #push-to-create-tip')
expect(page).to have_content 'Private projects can be created in your personal namespace with:'
end
end
diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb
index c146ac1e8ee..755f170a93e 100644
--- a/spec/features/security/group/internal_access_spec.rb
+++ b/spec/features/security/group/internal_access_spec.rb
@@ -24,7 +24,12 @@ RSpec.describe 'Internal Group access' do
describe 'GET /groups/:path' do
subject { group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -39,7 +44,12 @@ RSpec.describe 'Internal Group access' do
describe 'GET /groups/:path/-/issues' do
subject { issues_group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -56,7 +66,12 @@ RSpec.describe 'Internal Group access' do
subject { merge_requests_group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -71,7 +86,12 @@ RSpec.describe 'Internal Group access' do
describe 'GET /groups/:path/-/group_members' do
subject { group_group_members_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -86,7 +106,12 @@ RSpec.describe 'Internal Group access' do
describe 'GET /groups/:path/-/edit' do
subject { edit_group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_denied_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_denied_for(:maintainer).of(group) }
it { is_expected.to be_denied_for(:developer).of(group) }
diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb
index de05b4d3d16..fc1fb3e3848 100644
--- a/spec/features/security/group/private_access_spec.rb
+++ b/spec/features/security/group/private_access_spec.rb
@@ -24,7 +24,12 @@ RSpec.describe 'Private Group access' do
describe 'GET /groups/:path' do
subject { group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_denied_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -39,7 +44,12 @@ RSpec.describe 'Private Group access' do
describe 'GET /groups/:path/-/issues' do
subject { issues_group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_denied_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -56,7 +66,12 @@ RSpec.describe 'Private Group access' do
subject { merge_requests_group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_denied_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -71,7 +86,12 @@ RSpec.describe 'Private Group access' do
describe 'GET /groups/:path/-/group_members' do
subject { group_group_members_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_denied_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -86,7 +106,12 @@ RSpec.describe 'Private Group access' do
describe 'GET /groups/:path/-/edit' do
subject { edit_group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_denied_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_denied_for(:maintainer).of(group) }
it { is_expected.to be_denied_for(:developer).of(group) }
@@ -107,7 +132,12 @@ RSpec.describe 'Private Group access' do
subject { group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_denied_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb
index ee72b84616a..90de2b58044 100644
--- a/spec/features/security/group/public_access_spec.rb
+++ b/spec/features/security/group/public_access_spec.rb
@@ -24,7 +24,12 @@ RSpec.describe 'Public Group access' do
describe 'GET /groups/:path' do
subject { group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -39,7 +44,12 @@ RSpec.describe 'Public Group access' do
describe 'GET /groups/:path/-/issues' do
subject { issues_group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -56,7 +66,12 @@ RSpec.describe 'Public Group access' do
subject { merge_requests_group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -71,7 +86,12 @@ RSpec.describe 'Public Group access' do
describe 'GET /groups/:path/-/group_members' do
subject { group_group_members_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_allowed_for(:maintainer).of(group) }
it { is_expected.to be_allowed_for(:developer).of(group) }
@@ -86,7 +106,12 @@ RSpec.describe 'Public Group access' do
describe 'GET /groups/:path/-/edit' do
subject { edit_group_path(group) }
- it { is_expected.to be_allowed_for(:admin) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed_for(:admin) }
+ end
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_denied_for(:admin) }
+ end
it { is_expected.to be_allowed_for(:owner).of(group) }
it { is_expected.to be_denied_for(:maintainer).of(group) }
it { is_expected.to be_denied_for(:developer).of(group) }
diff --git a/spec/features/sentry_js_spec.rb b/spec/features/sentry_js_spec.rb
index aa0ad17340a..1d277ba7b3c 100644
--- a/spec/features/sentry_js_spec.rb
+++ b/spec/features/sentry_js_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'Sentry' do
expect(has_requested_sentry).to eq(false)
end
- xit 'loads sentry if sentry is enabled' do
+ it 'loads sentry if sentry is enabled' do
stub_sentry_settings
visit new_user_session_path
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index e17521e1d02..0f8daaf8e15 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -69,13 +69,7 @@ RSpec.describe 'Task Lists', :js do
wait_for_requests
expect(page).to have_selector(".md .task-list .task-list-item .task-list-item-checkbox")
- end
-
- it_behaves_like 'page with comment and close button', 'Close issue' do
- def setup
- visit_issue(project, issue)
- wait_for_requests
- end
+ expect(page).to have_selector('.btn-close')
end
it 'is only editable by author' do
diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
index 31e29810c65..900cd72c17f 100644
--- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'User uploads avatar to profile' do
expect(user.reload.avatar.file).to exist
end
- it 'their new avatar is immediately visible in the header', :js do
+ it 'their new avatar is immediately visible in the header and setting sidebar', :js do
find('.js-user-avatar-input', visible: false).set(avatar_file_path)
click_button 'Set new profile picture'
@@ -33,5 +33,6 @@ RSpec.describe 'User uploads avatar to profile' do
data_uri = find('.avatar-image .avatar')['src']
expect(page.find('.header-user-avatar')['src']).to eq data_uri
+ expect(page.find('[data-testid="sidebar-user-avatar"]')['src']).to eq data_uri
end
end
diff --git a/spec/features/user_can_display_performance_bar_spec.rb b/spec/features/user_can_display_performance_bar_spec.rb
index 9c67523f88f..b8f41925156 100644
--- a/spec/features/user_can_display_performance_bar_spec.rb
+++ b/spec/features/user_can_display_performance_bar_spec.rb
@@ -49,6 +49,10 @@ RSpec.describe 'User can display performance bar', :js do
let(:group) { create(:group) }
+ before do
+ allow(GitlabPerformanceBarStatsWorker).to receive(:perform_in)
+ end
+
context 'when user is logged-out' do
before do
visit root_path
@@ -97,6 +101,26 @@ RSpec.describe 'User can display performance bar', :js do
it_behaves_like 'performance bar is enabled by default in development'
it_behaves_like 'performance bar can be displayed'
+
+ it 'does not show Stats link by default' do
+ find('body').native.send_keys('pb')
+
+ expect(page).not_to have_link('Stats', visible: :all)
+ end
+
+ context 'when GITLAB_PERFORMANCE_BAR_STATS_URL environment variable is set' do
+ let(:stats_url) { 'https://log.gprd.gitlab.net/app/dashboards#/view/' }
+
+ before do
+ stub_env('GITLAB_PERFORMANCE_BAR_STATS_URL', stats_url)
+ end
+
+ it 'shows Stats link' do
+ find('body').native.send_keys('pb')
+
+ expect(page).to have_link('Stats', href: stats_url, visible: :all)
+ end
+ end
end
end
end