summaryrefslogtreecommitdiff
path: root/spec/features
diff options
context:
space:
mode:
Diffstat (limited to 'spec/features')
-rw-r--r--spec/features/abuse_report_spec.rb24
-rw-r--r--spec/features/action_cable_logging_spec.rb2
-rw-r--r--spec/features/admin/admin_abuse_reports_spec.rb260
-rw-r--r--spec/features/admin/admin_appearance_spec.rb268
-rw-r--r--spec/features/admin/admin_browse_spam_logs_spec.rb2
-rw-r--r--spec/features/admin/admin_deploy_keys_spec.rb2
-rw-r--r--spec/features/admin/admin_groups_spec.rb4
-rw-r--r--spec/features/admin/admin_health_check_spec.rb6
-rw-r--r--spec/features/admin/admin_hook_logs_spec.rb2
-rw-r--r--spec/features/admin/admin_hooks_spec.rb4
-rw-r--r--spec/features/admin/admin_labels_spec.rb7
-rw-r--r--spec/features/admin/admin_mode/login_spec.rb344
-rw-r--r--spec/features/admin/admin_mode/logout_spec.rb4
-rw-r--r--spec/features/admin/admin_mode/workers_spec.rb4
-rw-r--r--spec/features/admin/admin_mode_spec.rb10
-rw-r--r--spec/features/admin/admin_projects_spec.rb44
-rw-r--r--spec/features/admin/admin_runners_spec.rb77
-rw-r--r--spec/features/admin/admin_sees_background_migrations_spec.rb2
-rw-r--r--spec/features/admin/admin_settings_spec.rb69
-rw-r--r--spec/features/admin/admin_system_info_spec.rb2
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb4
-rw-r--r--spec/features/admin/admin_uses_repository_checks_spec.rb2
-rw-r--r--spec/features/admin/broadcast_messages_spec.rb73
-rw-r--r--spec/features/admin/integrations/instance_integrations_spec.rb4
-rw-r--r--spec/features/admin/users/user_spec.rb7
-rw-r--r--spec/features/admin/users/users_spec.rb36
-rw-r--r--spec/features/admin_variables_spec.rb16
-rw-r--r--spec/features/alerts_settings/user_views_alerts_settings_spec.rb1
-rw-r--r--spec/features/boards/board_filters_spec.rb2
-rw-r--r--spec/features/boards/boards_spec.rb13
-rw-r--r--spec/features/boards/issue_ordering_spec.rb4
-rw-r--r--spec/features/boards/new_issue_spec.rb50
-rw-r--r--spec/features/boards/sidebar_spec.rb2
-rw-r--r--spec/features/breadcrumbs_schema_markup_spec.rb2
-rw-r--r--spec/features/broadcast_messages_spec.rb32
-rw-r--r--spec/features/calendar_spec.rb381
-rw-r--r--spec/features/callouts/registration_enabled_spec.rb2
-rw-r--r--spec/features/canonical_link_spec.rb2
-rw-r--r--spec/features/clusters/cluster_detail_page_spec.rb2
-rw-r--r--spec/features/clusters/cluster_health_dashboard_spec.rb22
-rw-r--r--spec/features/clusters/create_agent_spec.rb2
-rw-r--r--spec/features/commit_spec.rb42
-rw-r--r--spec/features/commits/user_uses_quick_actions_spec.rb2
-rw-r--r--spec/features/commits_spec.rb28
-rw-r--r--spec/features/contextual_sidebar_spec.rb69
-rw-r--r--spec/features/cycle_analytics_spec.rb9
-rw-r--r--spec/features/dashboard/activity_spec.rb2
-rw-r--r--spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb12
-rw-r--r--spec/features/dashboard/groups_list_spec.rb9
-rw-r--r--spec/features/dashboard/issuables_counter_spec.rb2
-rw-r--r--spec/features/dashboard/issues_filter_spec.rb79
-rw-r--r--spec/features/dashboard/issues_spec.rb45
-rw-r--r--spec/features/dashboard/label_filter_spec.rb34
-rw-r--r--spec/features/dashboard/merge_requests_spec.rb4
-rw-r--r--spec/features/dashboard/milestones_spec.rb2
-rw-r--r--spec/features/dashboard/projects_spec.rb28
-rw-r--r--spec/features/dashboard/root_explore_spec.rb6
-rw-r--r--spec/features/dashboard/shortcuts_spec.rb2
-rw-r--r--spec/features/dashboard/snippets_spec.rb12
-rw-r--r--spec/features/dashboard/todos/todos_spec.rb2
-rw-r--r--spec/features/display_system_header_and_footer_bar_spec.rb2
-rw-r--r--spec/features/emails/issues_spec.rb110
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb14
-rw-r--r--spec/features/explore/groups_spec.rb44
-rw-r--r--spec/features/explore/navbar_spec.rb13
-rw-r--r--spec/features/explore/user_explores_projects_spec.rb12
-rw-r--r--spec/features/file_uploads/project_import_spec.rb4
-rw-r--r--spec/features/frequently_visited_projects_and_groups_spec.rb4
-rw-r--r--spec/features/global_search_spec.rb58
-rw-r--r--spec/features/group_variables_spec.rb15
-rw-r--r--spec/features/groups/board_spec.rb6
-rw-r--r--spec/features/groups/container_registry_spec.rb4
-rw-r--r--spec/features/groups/crm/contacts/create_spec.rb2
-rw-r--r--spec/features/groups/dependency_proxy_spec.rb10
-rw-r--r--spec/features/groups/group_runners_spec.rb38
-rw-r--r--spec/features/groups/group_settings_spec.rb92
-rw-r--r--spec/features/groups/import_export/connect_instance_spec.rb2
-rw-r--r--spec/features/groups/integrations/group_integrations_spec.rb16
-rw-r--r--spec/features/groups/issues_spec.rb22
-rw-r--r--spec/features/groups/labels/index_spec.rb3
-rw-r--r--spec/features/groups/members/filter_members_spec.rb2
-rw-r--r--spec/features/groups/members/leave_group_spec.rb2
-rw-r--r--spec/features/groups/members/list_members_spec.rb2
-rw-r--r--spec/features/groups/members/manage_groups_spec.rb4
-rw-r--r--spec/features/groups/members/manage_members_spec.rb4
-rw-r--r--spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb4
-rw-r--r--spec/features/groups/members/search_members_spec.rb2
-rw-r--r--spec/features/groups/members/sort_members_spec.rb4
-rw-r--r--spec/features/groups/milestone_spec.rb6
-rw-r--r--spec/features/groups/milestones/milestone_editing_spec.rb18
-rw-r--r--spec/features/groups/new_group_page_spec.rb50
-rw-r--r--spec/features/groups/packages_spec.rb8
-rw-r--r--spec/features/groups/settings/access_tokens_spec.rb2
-rw-r--r--spec/features/groups/settings/packages_and_registries_spec.rb9
-rw-r--r--spec/features/groups/show_spec.rb2
-rw-r--r--spec/features/groups_spec.rb41
-rw-r--r--spec/features/help_dropdown_spec.rb2
-rw-r--r--spec/features/help_pages_spec.rb2
-rw-r--r--spec/features/ide/user_opens_merge_request_spec.rb4
-rw-r--r--spec/features/ide_spec.rb13
-rw-r--r--spec/features/import/manifest_import_spec.rb2
-rw-r--r--spec/features/incidents/incident_details_spec.rb2
-rw-r--r--spec/features/incidents/incident_timeline_events_spec.rb7
-rw-r--r--spec/features/incidents/user_uses_quick_actions_spec.rb2
-rw-r--r--spec/features/incidents/user_views_alert_details_spec.rb34
-rw-r--r--spec/features/integrations_settings_spec.rb29
-rw-r--r--spec/features/invites_spec.rb47
-rw-r--r--spec/features/issuables/issuable_list_spec.rb2
-rw-r--r--spec/features/issuables/markdown_references/internal_references_spec.rb2
-rw-r--r--spec/features/issuables/markdown_references/jira_spec.rb2
-rw-r--r--spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb11
-rw-r--r--spec/features/issues/csv_spec.rb1
-rw-r--r--spec/features/issues/discussion_lock_spec.rb3
-rw-r--r--spec/features/issues/filtered_search/dropdown_hint_spec.rb4
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb12
-rw-r--r--spec/features/issues/filtered_search/recent_searches_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/search_bar_spec.rb3
-rw-r--r--spec/features/issues/filtered_search/visual_tokens_spec.rb42
-rw-r--r--spec/features/issues/form_spec.rb510
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb3
-rw-r--r--spec/features/issues/incident_issue_spec.rb4
-rw-r--r--spec/features/issues/issue_detail_spec.rb29
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb14
-rw-r--r--spec/features/issues/move_spec.rb7
-rw-r--r--spec/features/issues/rss_spec.rb12
-rw-r--r--spec/features/issues/service_desk_spec.rb4
-rw-r--r--spec/features/issues/user_bulk_edits_issues_labels_spec.rb4
-rw-r--r--spec/features/issues/user_bulk_edits_issues_spec.rb14
-rw-r--r--spec/features/issues/user_comments_on_issue_spec.rb4
-rw-r--r--spec/features/issues/user_creates_branch_and_merge_request_spec.rb24
-rw-r--r--spec/features/issues/user_creates_issue_spec.rb89
-rw-r--r--spec/features/issues/user_edits_issue_spec.rb43
-rw-r--r--spec/features/issues/user_sorts_issue_comments_spec.rb3
-rw-r--r--spec/features/issues/user_toggles_subscription_spec.rb4
-rw-r--r--spec/features/issues/user_uses_quick_actions_spec.rb2
-rw-r--r--spec/features/jira_connect/branches_spec.rb2
-rw-r--r--spec/features/jira_oauth_provider_authorize_spec.rb35
-rw-r--r--spec/features/labels_hierarchy_spec.rb73
-rw-r--r--spec/features/markdown/markdown_spec.rb4
-rw-r--r--spec/features/markdown/metrics_spec.rb41
-rw-r--r--spec/features/markdown/observability_spec.rb124
-rw-r--r--spec/features/markdown/sandboxed_mermaid_spec.rb24
-rw-r--r--spec/features/merge_request/batch_comments_spec.rb4
-rw-r--r--spec/features/merge_request/maintainer_edits_fork_spec.rb2
-rw-r--r--spec/features/merge_request/user_accepts_merge_request_spec.rb20
-rw-r--r--spec/features/merge_request/user_comments_on_diff_spec.rb4
-rw-r--r--spec/features/merge_request/user_comments_on_merge_request_spec.rb2
-rw-r--r--spec/features/merge_request/user_creates_image_diff_notes_spec.rb2
-rw-r--r--spec/features/merge_request/user_creates_mr_spec.rb151
-rw-r--r--spec/features/merge_request/user_edits_assignees_sidebar_spec.rb4
-rw-r--r--spec/features/merge_request/user_edits_merge_request_spec.rb2
-rw-r--r--spec/features/merge_request/user_edits_mr_spec.rb228
-rw-r--r--spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb2
-rw-r--r--spec/features/merge_request/user_manages_subscription_spec.rb4
-rw-r--r--spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb160
-rw-r--r--spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb110
-rw-r--r--spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb2
-rw-r--r--spec/features/merge_request/user_posts_diff_notes_spec.rb2
-rw-r--r--spec/features/merge_request/user_posts_notes_spec.rb4
-rw-r--r--spec/features/merge_request/user_resolves_conflicts_spec.rb2
-rw-r--r--spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb2
-rw-r--r--spec/features/merge_request/user_reverts_merge_request_spec.rb7
-rw-r--r--spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb3
-rw-r--r--spec/features/merge_request/user_sees_diff_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_discussions_navigation_spec.rb8
-rw-r--r--spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb8
-rw-r--r--spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb46
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb7
-rw-r--r--spec/features/merge_request/user_sees_pipelines_spec.rb21
-rw-r--r--spec/features/merge_request/user_sees_real_time_reviewers_spec.rb24
-rw-r--r--spec/features/merge_request/user_sees_versions_spec.rb2
-rw-r--r--spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb2
-rw-r--r--spec/features/merge_request/user_uses_quick_actions_spec.rb2
-rw-r--r--spec/features/merge_request/user_views_open_merge_request_spec.rb32
-rw-r--r--spec/features/merge_requests/filters_generic_behavior_spec.rb2
-rw-r--r--spec/features/merge_requests/rss_spec.rb4
-rw-r--r--spec/features/merge_requests/user_exports_as_csv_spec.rb1
-rw-r--r--spec/features/merge_requests/user_lists_merge_requests_spec.rb39
-rw-r--r--spec/features/merge_requests/user_mass_updates_spec.rb8
-rw-r--r--spec/features/merge_requests/user_sorts_merge_requests_spec.rb2
-rw-r--r--spec/features/milestones/user_deletes_milestone_spec.rb2
-rw-r--r--spec/features/monitor_sidebar_link_spec.rb3
-rw-r--r--spec/features/nav/new_nav_invite_members_spec.rb50
-rw-r--r--spec/features/nav/new_nav_toggle_spec.rb2
-rw-r--r--spec/features/nav/pinned_nav_items_spec.rb195
-rw-r--r--spec/features/nav/top_nav_responsive_spec.rb26
-rw-r--r--spec/features/nav/top_nav_spec.rb14
-rw-r--r--spec/features/oauth_login_spec.rb2
-rw-r--r--spec/features/oauth_registration_spec.rb1
-rw-r--r--spec/features/populate_new_pipeline_vars_with_params_spec.rb2
-rw-r--r--spec/features/profiles/chat_names_spec.rb44
-rw-r--r--spec/features/profiles/gpg_keys_spec.rb3
-rw-r--r--spec/features/profiles/list_users_comment_template_spec.rb (renamed from spec/features/profiles/list_users_saved_replies_spec.rb)8
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb2
-rw-r--r--spec/features/profiles/user_creates_comment_template_spec.rb29
-rw-r--r--spec/features/profiles/user_deletes_comment_template_spec.rb28
-rw-r--r--spec/features/profiles/user_edit_preferences_spec.rb29
-rw-r--r--spec/features/profiles/user_edit_profile_spec.rb30
-rw-r--r--spec/features/profiles/user_updates_comment_template_spec.rb30
-rw-r--r--spec/features/profiles/user_uses_comment_template_spec.rb29
-rw-r--r--spec/features/profiles/user_visits_profile_authentication_log_spec.rb2
-rw-r--r--spec/features/project_group_variables_spec.rb2
-rw-r--r--spec/features/project_variables_spec.rb15
-rw-r--r--spec/features/projects/badges/list_spec.rb39
-rw-r--r--spec/features/projects/blobs/blame_spec.rb43
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb28
-rw-r--r--spec/features/projects/blobs/edit_spec.rb6
-rw-r--r--spec/features/projects/blobs/user_views_pipeline_editor_button_spec.rb2
-rw-r--r--spec/features/projects/branches/user_creates_branch_spec.rb6
-rw-r--r--spec/features/projects/branches_spec.rb24
-rw-r--r--spec/features/projects/ci/editor_spec.rb8
-rw-r--r--spec/features/projects/ci/lint_spec.rb4
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb2
-rw-r--r--spec/features/projects/clusters/user_spec.rb2
-rw-r--r--spec/features/projects/commit/cherry_pick_spec.rb2
-rw-r--r--spec/features/projects/commit/comments/user_adds_comment_spec.rb6
-rw-r--r--spec/features/projects/commit/comments/user_deletes_comments_spec.rb4
-rw-r--r--spec/features/projects/commit/comments/user_edits_comments_spec.rb2
-rw-r--r--spec/features/projects/commit/diff_notes_spec.rb13
-rw-r--r--spec/features/projects/commit/user_comments_on_commit_spec.rb6
-rw-r--r--spec/features/projects/commit/user_reverts_commit_spec.rb2
-rw-r--r--spec/features/projects/commit/user_sees_pipelines_tab_spec.rb58
-rw-r--r--spec/features/projects/compare_spec.rb19
-rw-r--r--spec/features/projects/container_registry_spec.rb21
-rw-r--r--spec/features/projects/environments/environment_metrics_spec.rb15
-rw-r--r--spec/features/projects/environments/environment_spec.rb30
-rw-r--r--spec/features/projects/environments/environments_spec.rb56
-rw-r--r--spec/features/projects/files/dockerfile_dropdown_spec.rb2
-rw-r--r--spec/features/projects/files/editing_a_file_spec.rb50
-rw-r--r--spec/features/projects/files/gitignore_dropdown_spec.rb2
-rw-r--r--spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb2
-rw-r--r--spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb2
-rw-r--r--spec/features/projects/files/user_browses_files_spec.rb7
-rw-r--r--spec/features/projects/files/user_creates_files_spec.rb4
-rw-r--r--spec/features/projects/files/user_edits_files_spec.rb4
-rw-r--r--spec/features/projects/fork_spec.rb28
-rw-r--r--spec/features/projects/import_export/export_file_spec.rb61
-rw-r--r--spec/features/projects/import_export/import_file_spec.rb1
-rw-r--r--spec/features/projects/import_export/test_project_export.tar.gzbin3176 -> 4799 bytes
-rw-r--r--spec/features/projects/integrations/apple_app_store_spec.rb24
-rw-r--r--spec/features/projects/integrations/google_play_spec.rb24
-rw-r--r--spec/features/projects/integrations/project_integrations_spec.rb12
-rw-r--r--spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb8
-rw-r--r--spec/features/projects/integrations/user_activates_prometheus_spec.rb1
-rw-r--r--spec/features/projects/integrations/user_activates_slack_notifications_spec.rb1
-rw-r--r--spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb2
-rw-r--r--spec/features/projects/integrations/user_uses_inherited_settings_spec.rb10
-rw-r--r--spec/features/projects/issuable_templates_spec.rb2
-rw-r--r--spec/features/projects/issues/viewing_relocated_issues_spec.rb2
-rw-r--r--spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb2
-rw-r--r--spec/features/projects/jobs_spec.rb19
-rw-r--r--spec/features/projects/labels/update_prioritization_spec.rb2
-rw-r--r--spec/features/projects/members/anonymous_user_sees_members_spec.rb2
-rw-r--r--spec/features/projects/members/group_members_spec.rb2
-rw-r--r--spec/features/projects/members/groups_with_access_list_spec.rb4
-rw-r--r--spec/features/projects/members/manage_groups_spec.rb4
-rw-r--r--spec/features/projects/members/manage_members_spec.rb4
-rw-r--r--spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb4
-rw-r--r--spec/features/projects/members/member_leaves_project_spec.rb2
-rw-r--r--spec/features/projects/members/sorting_spec.rb4
-rw-r--r--spec/features/projects/members/tabs_spec.rb2
-rw-r--r--spec/features/projects/milestones/milestone_editing_spec.rb18
-rw-r--r--spec/features/projects/navbar_spec.rb17
-rw-r--r--spec/features/projects/network_graph_spec.rb9
-rw-r--r--spec/features/projects/new_project_spec.rb106
-rw-r--r--spec/features/projects/packages_spec.rb4
-rw-r--r--spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb12
-rw-r--r--spec/features/projects/pipeline_schedules_spec.rb474
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb55
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb39
-rw-r--r--spec/features/projects/releases/user_creates_release_spec.rb17
-rw-r--r--spec/features/projects/settings/access_tokens_spec.rb2
-rw-r--r--spec/features/projects/settings/branch_rules_settings_spec.rb11
-rw-r--r--spec/features/projects/settings/forked_project_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/monitor_settings_spec.rb5
-rw-r--r--spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb13
-rw-r--r--spec/features/projects/settings/registry_settings_spec.rb13
-rw-r--r--spec/features/projects/settings/repository_settings_spec.rb39
-rw-r--r--spec/features/projects/settings/service_desk_setting_spec.rb10
-rw-r--r--spec/features/projects/settings/user_manages_project_members_spec.rb2
-rw-r--r--spec/features/projects/settings/user_renames_a_project_spec.rb4
-rw-r--r--spec/features/projects/settings/webhooks_settings_spec.rb2
-rw-r--r--spec/features/projects/snippets/create_snippet_spec.rb2
-rw-r--r--spec/features/projects/snippets/user_updates_snippet_spec.rb2
-rw-r--r--spec/features/projects/terraform_spec.rb2
-rw-r--r--spec/features/projects/tree/create_directory_spec.rb2
-rw-r--r--spec/features/projects/tree/create_file_spec.rb2
-rw-r--r--spec/features/projects/tree/tree_show_spec.rb2
-rw-r--r--spec/features/projects/tree/upload_file_spec.rb2
-rw-r--r--spec/features/projects/user_changes_project_visibility_spec.rb19
-rw-r--r--spec/features/projects/user_sees_user_popover_spec.rb2
-rw-r--r--spec/features/projects/user_uses_shortcuts_spec.rb13
-rw-r--r--spec/features/projects/user_views_empty_project_spec.rb2
-rw-r--r--spec/features/projects/work_items/work_item_children_spec.rb (renamed from spec/features/work_items/work_item_children_spec.rb)43
-rw-r--r--spec/features/projects/work_items/work_item_spec.rb92
-rw-r--r--spec/features/protected_branches_spec.rb9
-rw-r--r--spec/features/protected_tags_spec.rb34
-rw-r--r--spec/features/reportable_note/issue_spec.rb4
-rw-r--r--spec/features/runners_spec.rb51
-rw-r--r--spec/features/search/user_searches_for_code_spec.rb55
-rw-r--r--spec/features/search/user_uses_header_search_field_spec.rb18
-rw-r--r--spec/features/security/admin_access_spec.rb2
-rw-r--r--spec/features/security/dashboard_access_spec.rb2
-rw-r--r--spec/features/security/group/internal_access_spec.rb2
-rw-r--r--spec/features/security/group/private_access_spec.rb2
-rw-r--r--spec/features/security/group/public_access_spec.rb2
-rw-r--r--spec/features/security/project/internal_access_spec.rb2
-rw-r--r--spec/features/security/project/private_access_spec.rb2
-rw-r--r--spec/features/security/project/public_access_spec.rb2
-rw-r--r--spec/features/security/project/snippet/internal_access_spec.rb2
-rw-r--r--spec/features/security/project/snippet/private_access_spec.rb2
-rw-r--r--spec/features/security/project/snippet/public_access_spec.rb2
-rw-r--r--spec/features/signed_commits_spec.rb9
-rw-r--r--spec/features/snippets/notes_on_personal_snippets_spec.rb37
-rw-r--r--spec/features/snippets/show_spec.rb9
-rw-r--r--spec/features/snippets/user_creates_snippet_spec.rb6
-rw-r--r--spec/features/snippets/user_edits_snippet_spec.rb2
-rw-r--r--spec/features/tags/developer_creates_tag_spec.rb2
-rw-r--r--spec/features/tags/developer_deletes_tag_spec.rb22
-rw-r--r--spec/features/tags/developer_views_tags_spec.rb1
-rw-r--r--spec/features/tags/maintainer_deletes_protected_tag_spec.rb7
-rw-r--r--spec/features/topic_show_spec.rb2
-rw-r--r--spec/features/u2f_spec.rb216
-rw-r--r--spec/features/unsubscribe_links_spec.rb2
-rw-r--r--spec/features/user_can_display_performance_bar_spec.rb2
-rw-r--r--spec/features/user_sees_revert_modal_spec.rb5
-rw-r--r--spec/features/user_sorts_things_spec.rb2
-rw-r--r--spec/features/users/login_spec.rb358
-rw-r--r--spec/features/users/show_spec.rb74
-rw-r--r--spec/features/users/signup_spec.rb18
-rw-r--r--spec/features/webauthn_spec.rb249
-rw-r--r--spec/features/whats_new_spec.rb6
-rw-r--r--spec/features/work_items/work_item_spec.rb37
333 files changed, 5908 insertions, 2680 deletions
diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb
index 1267025a7bf..82b7379b67c 100644
--- a/spec/features/abuse_report_spec.rb
+++ b/spec/features/abuse_report_spec.rb
@@ -12,28 +12,10 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
before do
sign_in(reporter1)
+ stub_feature_flags(moved_mr_sidebar: false)
end
describe 'report abuse to administrator' do
- shared_examples 'reports the user with an abuse category' do
- it do
- fill_and_submit_abuse_category_form
- fill_and_submit_report_abuse_form
-
- expect(page).to have_content 'Thank you for your report'
- end
- end
-
- shared_examples 'reports the user without an abuse category' do
- it do
- click_link 'Report abuse to administrator'
-
- fill_and_submit_report_abuse_form
-
- expect(page).to have_content 'Thank you for your report'
- end
- end
-
context 'when reporting an issue for abuse' do
before do
visit project_issue_path(project, issue)
@@ -133,7 +115,7 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
before do
visit project_issue_path(project, issue)
- click_button 'More actions'
+ find('.more-actions-toggle button').click
end
it_behaves_like 'reports the user with an abuse category'
@@ -143,7 +125,7 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
private
def fill_and_submit_abuse_category_form(category = "They're posting spam.")
- click_button 'Report abuse to administrator'
+ click_button 'Report abuse'
choose category
click_button 'Next'
diff --git a/spec/features/action_cable_logging_spec.rb b/spec/features/action_cable_logging_spec.rb
index c02a41c4c59..c8a4e1efb7a 100644
--- a/spec/features/action_cable_logging_spec.rb
+++ b/spec/features/action_cable_logging_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'ActionCable logging', :js, feature_category: :not_owned do
+RSpec.describe 'ActionCable logging', :js, feature_category: :shared do
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/features/admin/admin_abuse_reports_spec.rb b/spec/features/admin/admin_abuse_reports_spec.rb
index 10f12d7116f..9739ea53f81 100644
--- a/spec/features/admin/admin_abuse_reports_spec.rb
+++ b/spec/features/admin/admin_abuse_reports_spec.rb
@@ -2,79 +2,247 @@
require 'spec_helper'
-RSpec.describe "Admin::AbuseReports", :js, feature_category: :not_owned do
- let(:user) { create(:user) }
+RSpec.describe "Admin::AbuseReports", :js, feature_category: :shared do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:admin) { create(:admin) }
context 'as an admin' do
- before do
- admin = create(:admin)
- sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
- end
+ describe 'displayed reports' do
+ include FilteredSearchHelpers
- describe 'if a user has been reported for abuse' do
- let!(:abuse_report) { create(:abuse_report, user: user) }
+ let_it_be(:open_report) { create(:abuse_report, created_at: 5.days.ago, updated_at: 2.days.ago) }
+ let_it_be(:open_report2) { create(:abuse_report, created_at: 4.days.ago, updated_at: 3.days.ago, category: 'phishing') }
+ let_it_be(:closed_report) { create(:abuse_report, :closed) }
- describe 'in the abuse report view' do
- it 'presents information about abuse report' do
- visit admin_abuse_reports_path
+ let(:abuse_report_row_selector) { '[data-testid="abuse-report-row"]' }
- expect(page).to have_content('Abuse Reports')
- expect(page).to have_content(abuse_report.message)
- expect(page).to have_link(user.name, href: user_path(user))
- expect(page).to have_link('Remove user')
- end
+ before do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+
+ visit admin_abuse_reports_path
end
- describe 'in the profile page of the user' do
- it 'shows a link to the admin view of the user' do
- visit user_path(user)
+ it 'only includes open reports by default' do
+ expect_displayed_reports_count(2)
+
+ expect_report_shown(open_report, open_report2)
- expect(page).to have_link '', href: admin_user_path(user)
+ within '[data-testid="abuse-reports-filtered-search-bar"]' do
+ expect(page).to have_content 'Status = Open'
end
end
- end
- describe 'if a many users have been reported for abuse' do
- let(:report_count) { AbuseReport.default_per_page + 3 }
+ it 'can be filtered by status, user, reporter, and category', :aggregate_failures do
+ # filter by status
+ filter %w[Status Closed]
+ expect_displayed_reports_count(1)
+ expect_report_shown(closed_report)
+ expect_report_not_shown(open_report, open_report2)
- before do
- report_count.times do
- create(:abuse_report, user: create(:user))
+ filter %w[Status Open]
+ expect_displayed_reports_count(2)
+ expect_report_shown(open_report, open_report2)
+ expect_report_not_shown(closed_report)
+
+ # filter by user
+ filter(['User', open_report2.user.username])
+
+ expect_displayed_reports_count(1)
+ expect_report_shown(open_report2)
+ expect_report_not_shown(open_report, closed_report)
+
+ # filter by reporter
+ filter(['Reporter', open_report.reporter.username])
+
+ expect_displayed_reports_count(1)
+ expect_report_shown(open_report)
+ expect_report_not_shown(open_report2, closed_report)
+
+ # filter by category
+ filter(['Category', open_report2.category])
+
+ expect_displayed_reports_count(1)
+ expect_report_shown(open_report2)
+ expect_report_not_shown(open_report, closed_report)
+ end
+
+ it 'can be sorted by created_at and updated_at in desc and asc order', :aggregate_failures do
+ # created_at desc (default)
+ expect(report_rows[0].text).to include(report_text(open_report2))
+ expect(report_rows[1].text).to include(report_text(open_report))
+
+ # created_at asc
+ toggle_sort_direction
+
+ expect(report_rows[0].text).to include(report_text(open_report))
+ expect(report_rows[1].text).to include(report_text(open_report2))
+
+ # updated_at ascending
+ sort_by 'Updated date'
+
+ expect(report_rows[0].text).to include(report_text(open_report2))
+ expect(report_rows[1].text).to include(report_text(open_report))
+
+ # updated_at descending
+ toggle_sort_direction
+
+ expect(report_rows[0].text).to include(report_text(open_report))
+ expect(report_rows[1].text).to include(report_text(open_report2))
+ end
+
+ def report_rows
+ page.all(abuse_report_row_selector)
+ end
+
+ def report_text(report)
+ "#{report.user.name} reported for #{report.category}"
+ end
+
+ def expect_report_shown(*reports)
+ reports.each do |r|
+ expect(page).to have_content(report_text(r))
end
end
- describe 'in the abuse report view' do
- it 'presents information about abuse report' do
- visit admin_abuse_reports_path
+ def expect_report_not_shown(*reports)
+ reports.each do |r|
+ expect(page).not_to have_content(report_text(r))
+ end
+ end
+
+ def expect_displayed_reports_count(count)
+ expect(page).to have_css(abuse_report_row_selector, count: count)
+ end
+
+ def filter(tokens)
+ # remove all existing filters first
+ page.find_all('.gl-token-close').each(&:click)
- expect(page).to have_selector('.pagination')
- expect(page).to have_selector('.pagination .js-pagination-page', count: (report_count.to_f / AbuseReport.default_per_page).ceil)
+ select_tokens(*tokens, submit: true, input_text: 'Filter reports')
+ end
+
+ def sort_by(sort)
+ page.within('.vue-filtered-search-bar-container .sort-dropdown-container') do
+ page.find('.gl-dropdown-toggle').click
+
+ page.within('.dropdown-menu') do
+ click_button sort
+ wait_for_requests
+ end
end
end
end
- describe 'filtering by user' do
- let!(:user2) { create(:user) }
- let!(:abuse_report) { create(:abuse_report, user: user) }
- let!(:abuse_report_2) { create(:abuse_report, user: user2) }
+ context 'when abuse_reports_list feature flag is disabled' do
+ before do
+ stub_feature_flags(abuse_reports_list: false)
- it 'shows only single user report' do
- visit admin_abuse_reports_path
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ end
+
+ describe 'if a user has been reported for abuse' do
+ let_it_be(:abuse_report) { create(:abuse_report, user: user) }
+
+ describe 'in the abuse report view' do
+ before do
+ visit admin_abuse_reports_path
+ end
+
+ it 'presents information about abuse report' do
+ expect(page).to have_content('Abuse Reports')
+
+ expect(page).to have_content(user.name)
+ expect(page).to have_content(abuse_report.reporter.name)
+ expect(page).to have_content(abuse_report.message)
+ expect(page).to have_link(user.name, href: user_path(user))
+ end
+
+ it 'present actions items' do
+ expect(page).to have_link('Remove user & report')
+ expect(page).to have_link('Block user')
+ expect(page).to have_link('Remove user')
+ end
+ end
+
+ describe 'in the profile page of the user' do
+ it 'shows a link to view user in the admin area' do
+ visit user_path(user)
+
+ expect(page).to have_link 'View user in admin area', href: admin_user_path(user)
+ end
+ end
+ end
+
+ describe 'if an admin has been reported for abuse' do
+ let_it_be(:admin_abuse_report) { create(:abuse_report, user: admin) }
+
+ describe 'in the abuse report view' do
+ before do
+ visit admin_abuse_reports_path
+ end
- page.within '.filter-form' do
- click_button 'User'
- wait_for_requests
+ it 'presents information about abuse report' do
+ page.within(:table_row, { "User" => admin.name }) do
+ expect(page).to have_content(admin.name)
+ expect(page).to have_content(admin_abuse_report.reporter.name)
+ expect(page).to have_content(admin_abuse_report.message)
+ expect(page).to have_link(admin.name, href: user_path(admin))
+ end
+ end
- page.within '.dropdown-menu-user' do
- click_link user2.name
+ it 'does not present actions items' do
+ page.within(:table_row, { "User" => admin.name }) do
+ expect(page).not_to have_link('Remove user & report')
+ expect(page).not_to have_link('Block user')
+ expect(page).not_to have_link('Remove user')
+ end
end
+ end
+ end
+
+ describe 'if a many users have been reported for abuse' do
+ let(:report_count) { AbuseReport.default_per_page + 3 }
- wait_for_requests
+ before do
+ report_count.times do
+ create(:abuse_report, user: create(:user))
+ end
end
- expect(page).to have_content(user2.name)
- expect(page).not_to have_content(user.name)
+ describe 'in the abuse report view' do
+ it 'presents information about abuse report' do
+ visit admin_abuse_reports_path
+
+ expect(page).to have_selector('.pagination')
+ expect(page).to have_selector('.pagination .js-pagination-page', count: (report_count.to_f / AbuseReport.default_per_page).ceil)
+ end
+ end
+ end
+
+ describe 'filtering by user' do
+ let!(:user2) { create(:user) }
+ let!(:abuse_report) { create(:abuse_report, user: user) }
+ let!(:abuse_report_2) { create(:abuse_report, user: user2) }
+
+ it 'shows only single user report' do
+ visit admin_abuse_reports_path
+
+ page.within '.filter-form' do
+ click_button 'User'
+ wait_for_requests
+
+ page.within '.dropdown-menu-user' do
+ click_link user2.name
+ end
+
+ wait_for_requests
+ end
+
+ expect(page).to have_content(user2.name)
+ expect(page).not_to have_content(user.name)
+ end
end
end
end
diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb
index 252d9ac5bac..db0ae79c9c4 100644
--- a/spec/features/admin/admin_appearance_spec.rb
+++ b/spec/features/admin/admin_appearance_spec.rb
@@ -2,190 +2,192 @@
require 'spec_helper'
-RSpec.describe 'Admin Appearance', feature_category: :not_owned do
+RSpec.describe 'Admin Appearance', feature_category: :shared do
let!(:appearance) { create(:appearance) }
let(:admin) { create(:admin) }
flag_values = [true, false]
flag_values.each do |val|
- before do
- stub_feature_flags(restyle_login_page: val)
- end
-
- it 'create new appearance' do
- sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
- visit admin_application_settings_appearances_path
-
- fill_in 'appearance_title', with: 'MyCompany'
- fill_in 'appearance_description', with: 'dev server'
- fill_in 'appearance_pwa_name', with: 'GitLab PWA'
- fill_in 'appearance_pwa_short_name', with: 'GitLab'
- fill_in 'appearance_pwa_description', with: 'GitLab as PWA'
- fill_in 'appearance_new_project_guidelines', with: 'Custom project guidelines'
- fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines'
- click_button 'Update appearance settings'
-
- expect(page).to have_current_path admin_application_settings_appearances_path, ignore_query: true
- expect(page).to have_content 'Appearance'
-
- expect(page).to have_field('appearance_title', with: 'MyCompany')
- expect(page).to have_field('appearance_description', with: 'dev server')
- expect(page).to have_field('appearance_pwa_name', with: 'GitLab PWA')
- expect(page).to have_field('appearance_pwa_short_name', with: 'GitLab')
- expect(page).to have_field('appearance_pwa_description', with: 'GitLab as PWA')
- expect(page).to have_field('appearance_new_project_guidelines', with: 'Custom project guidelines')
- expect(page).to have_field('appearance_profile_image_guidelines', with: 'Custom profile image guidelines')
- expect(page).to have_content 'Last edit'
- end
+ context "with #{val}" do
+ before do
+ stub_feature_flags(restyle_login_page: val)
+ end
- it 'preview sign-in page appearance' do
- sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
+ it 'create new appearance' do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ visit admin_application_settings_appearances_path
- visit admin_application_settings_appearances_path
- click_link "Sign-in page"
+ fill_in 'appearance_title', with: 'MyCompany'
+ fill_in 'appearance_description', with: 'dev server'
+ fill_in 'appearance_pwa_name', with: 'GitLab PWA'
+ fill_in 'appearance_pwa_short_name', with: 'GitLab'
+ fill_in 'appearance_pwa_description', with: 'GitLab as PWA'
+ fill_in 'appearance_new_project_guidelines', with: 'Custom project guidelines'
+ fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines'
+ click_button 'Update appearance settings'
- expect(find('#login')).to be_disabled
- expect(find('#password')).to be_disabled
- expect(find('button')).to be_disabled
+ expect(page).to have_current_path admin_application_settings_appearances_path, ignore_query: true
+ expect(page).to have_content 'Appearance'
+
+ expect(page).to have_field('appearance_title', with: 'MyCompany')
+ expect(page).to have_field('appearance_description', with: 'dev server')
+ expect(page).to have_field('appearance_pwa_name', with: 'GitLab PWA')
+ expect(page).to have_field('appearance_pwa_short_name', with: 'GitLab')
+ expect(page).to have_field('appearance_pwa_description', with: 'GitLab as PWA')
+ expect(page).to have_field('appearance_new_project_guidelines', with: 'Custom project guidelines')
+ expect(page).to have_field('appearance_profile_image_guidelines', with: 'Custom profile image guidelines')
+ expect(page).to have_content 'Last edit'
+ end
- expect_custom_sign_in_appearance(appearance)
- end
+ it 'preview sign-in page appearance' do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
- it 'preview new project page appearance', :js do
- sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
+ visit admin_application_settings_appearances_path
+ click_link "Sign-in page"
- visit admin_application_settings_appearances_path
- click_link "New project page"
+ expect(find('#login')).to be_disabled
+ expect(find('#password')).to be_disabled
+ expect(find('button')).to be_disabled
- expect_custom_new_project_appearance(appearance)
- end
+ expect_custom_sign_in_appearance(appearance)
+ end
- context 'Custom system header and footer' do
- before do
+ it 'preview new project page appearance', :js do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
- end
- context 'when system header and footer messages are empty' do
- it 'shows custom system header and footer fields' do
- visit admin_application_settings_appearances_path
+ visit admin_application_settings_appearances_path
+ click_link "New project page"
- expect(page).to have_field('appearance_header_message', with: '')
- expect(page).to have_field('appearance_footer_message', with: '')
- expect(page).to have_field('appearance_message_background_color')
- expect(page).to have_field('appearance_message_font_color')
- end
+ expect_custom_new_project_appearance(appearance)
end
- context 'when system header and footer messages are not empty' do
+ context 'Custom system header and footer' do
before do
- appearance.update!(header_message: 'Foo', footer_message: 'Bar')
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
end
- it 'shows custom system header and footer fields' do
- visit admin_application_settings_appearances_path
+ context 'when system header and footer messages are empty' do
+ it 'shows custom system header and footer fields' do
+ visit admin_application_settings_appearances_path
- expect(page).to have_field('appearance_header_message', with: appearance.header_message)
- expect(page).to have_field('appearance_footer_message', with: appearance.footer_message)
- expect(page).to have_field('appearance_message_background_color')
- expect(page).to have_field('appearance_message_font_color')
+ expect(page).to have_field('appearance_header_message', with: '')
+ expect(page).to have_field('appearance_footer_message', with: '')
+ expect(page).to have_field('appearance_message_background_color')
+ expect(page).to have_field('appearance_message_font_color')
+ end
end
- end
- end
- it 'custom sign-in page' do
- visit new_user_session_path
+ context 'when system header and footer messages are not empty' do
+ before do
+ appearance.update!(header_message: 'Foo', footer_message: 'Bar')
+ end
- expect_custom_sign_in_appearance(appearance)
- end
+ it 'shows custom system header and footer fields' do
+ visit admin_application_settings_appearances_path
- it 'custom new project page', :js do
- sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
- visit new_project_path
- click_link 'Create blank project'
+ expect(page).to have_field('appearance_header_message', with: appearance.header_message)
+ expect(page).to have_field('appearance_footer_message', with: appearance.footer_message)
+ expect(page).to have_field('appearance_message_background_color')
+ expect(page).to have_field('appearance_message_font_color')
+ end
+ end
+ end
- expect_custom_new_project_appearance(appearance)
- end
+ it 'custom sign-in page' do
+ visit new_user_session_path
- context 'Profile page with custom profile image guidelines' do
- before do
+ expect_custom_sign_in_appearance(appearance)
+ end
+
+ it 'custom new project page', :js do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
- visit admin_application_settings_appearances_path
- fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines, please :smile:!'
- click_button 'Update appearance settings'
+ visit new_project_path
+ click_link 'Create blank project'
+
+ expect_custom_new_project_appearance(appearance)
end
- it 'renders guidelines when set' do
- sign_in create(:user)
- visit profile_path
+ context 'Profile page with custom profile image guidelines' do
+ before do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ visit admin_application_settings_appearances_path
+ fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines, please :smile:!'
+ click_button 'Update appearance settings'
+ end
+
+ it 'renders guidelines when set' do
+ sign_in create(:user)
+ visit profile_path
- expect(page).to have_content 'Custom profile image guidelines, please 😄!'
+ expect(page).to have_content 'Custom profile image guidelines, please 😄!'
+ end
end
- end
- it 'appearance logo' do
- sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
- visit admin_application_settings_appearances_path
+ it 'appearance logo' do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ visit admin_application_settings_appearances_path
- attach_file(:appearance_logo, logo_fixture)
- click_button 'Update appearance settings'
- expect(page).to have_css(logo_selector)
+ attach_file(:appearance_logo, logo_fixture)
+ click_button 'Update appearance settings'
+ expect(page).to have_css(logo_selector)
- click_link 'Remove logo'
- expect(page).not_to have_css(logo_selector)
- end
+ click_link 'Remove logo'
+ expect(page).not_to have_css(logo_selector)
+ end
- it 'appearance pwa icon' do
- sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
- visit admin_application_settings_appearances_path
+ it 'appearance pwa icon' do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ visit admin_application_settings_appearances_path
- attach_file(:appearance_pwa_icon, logo_fixture)
- click_button 'Update appearance settings'
- expect(page).to have_css(pwa_icon_selector)
+ attach_file(:appearance_pwa_icon, logo_fixture)
+ click_button 'Update appearance settings'
+ expect(page).to have_css(pwa_icon_selector)
- click_link 'Remove icon'
- expect(page).not_to have_css(pwa_icon_selector)
- end
+ click_link 'Remove icon'
+ expect(page).not_to have_css(pwa_icon_selector)
+ end
- it 'header logos' do
- sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
- visit admin_application_settings_appearances_path
+ it 'header logos' do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ visit admin_application_settings_appearances_path
- attach_file(:appearance_header_logo, logo_fixture)
- click_button 'Update appearance settings'
- expect(page).to have_css(header_logo_selector)
+ attach_file(:appearance_header_logo, logo_fixture)
+ click_button 'Update appearance settings'
+ expect(page).to have_css(header_logo_selector)
- click_link 'Remove header logo'
- expect(page).not_to have_css(header_logo_selector)
- end
+ click_link 'Remove header logo'
+ expect(page).not_to have_css(header_logo_selector)
+ end
- it 'Favicon' do
- sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
- visit admin_application_settings_appearances_path
+ it 'Favicon' do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ visit admin_application_settings_appearances_path
- attach_file(:appearance_favicon, logo_fixture)
- click_button 'Update appearance settings'
+ attach_file(:appearance_favicon, logo_fixture)
+ click_button 'Update appearance settings'
- expect(page).to have_css('.appearance-light-logo-preview')
+ expect(page).to have_css('.appearance-light-logo-preview')
- click_link 'Remove favicon'
+ click_link 'Remove favicon'
- expect(page).not_to have_css('.appearance-light-logo-preview')
+ expect(page).not_to have_css('.appearance-light-logo-preview')
- # allowed file types
- attach_file(:appearance_favicon, Rails.root.join('spec', 'fixtures', 'sanitized.svg'))
- click_button 'Update appearance settings'
+ # allowed file types
+ attach_file(:appearance_favicon, Rails.root.join('spec', 'fixtures', 'sanitized.svg'))
+ click_button 'Update appearance settings'
- expect(page).to have_content 'Favicon You are not allowed to upload "svg" files, allowed types: png, ico'
+ expect(page).to have_content 'Favicon You are not allowed to upload "svg" files, allowed types: png, ico'
+ end
end
end
diff --git a/spec/features/admin/admin_browse_spam_logs_spec.rb b/spec/features/admin/admin_browse_spam_logs_spec.rb
index 461c9d08273..c272a8630b7 100644
--- a/spec/features/admin/admin_browse_spam_logs_spec.rb
+++ b/spec/features/admin/admin_browse_spam_logs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin browse spam logs', feature_category: :not_owned do
+RSpec.describe 'Admin browse spam logs', feature_category: :shared do
let!(:spam_log) { create(:spam_log, description: 'abcde ' * 20) }
before do
diff --git a/spec/features/admin/admin_deploy_keys_spec.rb b/spec/features/admin/admin_deploy_keys_spec.rb
index e55e1cce6b9..f59b4db5cc2 100644
--- a/spec/features/admin/admin_deploy_keys_spec.rb
+++ b/spec/features/admin/admin_deploy_keys_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'admin deploy keys', :js, feature_category: :authentication_and_authorization do
+RSpec.describe 'admin deploy keys', :js, feature_category: :system_access do
include Spec::Support::Helpers::ModalHelpers
let_it_be(:admin) { create(:admin) }
diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb
index a07a5c48713..34fe98d22bd 100644
--- a/spec/features/admin/admin_groups_spec.rb
+++ b/spec/features/admin/admin_groups_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'Admin Groups', feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::MembersHelpers
+ include Features::InviteMembersModalHelpers
include Spec::Support::Helpers::ModalHelpers
let(:internal) { Gitlab::VisibilityLevel::INTERNAL }
diff --git a/spec/features/admin/admin_health_check_spec.rb b/spec/features/admin/admin_health_check_spec.rb
index de71a48d2dc..66014e676d5 100644
--- a/spec/features/admin/admin_health_check_spec.rb
+++ b/spec/features/admin/admin_health_check_spec.rb
@@ -2,8 +2,9 @@
require 'spec_helper'
-RSpec.describe "Admin Health Check", feature_category: :continuous_verification do
+RSpec.describe "Admin Health Check", :js, feature_category: :error_budgets do
include StubENV
+ include Spec::Support::Helpers::ModalHelpers
let_it_be(:admin) { create(:admin) }
before do
@@ -30,7 +31,8 @@ RSpec.describe "Admin Health Check", feature_category: :continuous_verification
describe 'reload access token' do
it 'changes the access token' do
orig_token = Gitlab::CurrentSettings.health_check_access_token
- click_button 'Reset health check access token'
+ click_link 'Reset health check access token'
+ accept_gl_confirm('Are you sure you want to reset the health check token?')
expect(page).to have_content('New health check access token has been generated!')
expect(find('#health-check-token').text).not_to eq orig_token
diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb
index d6507e68692..34208cca113 100644
--- a/spec/features/admin/admin_hook_logs_spec.rb
+++ b/spec/features/admin/admin_hook_logs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin::HookLogs', feature_category: :continuous_verification do
+RSpec.describe 'Admin::HookLogs', feature_category: :integrations do
let_it_be(:system_hook) { create(:system_hook) }
let_it_be(:hook_log) { create(:web_hook_log, web_hook: system_hook, internal_error_message: 'some error') }
let_it_be(:admin) { create(:admin) }
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb
index 363c152371e..a8aa2680b55 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/features/admin/admin_hooks_spec.rb
@@ -106,7 +106,7 @@ RSpec.describe 'Admin::Hooks', feature_category: :integrations do
visit admin_hooks_path
click_button 'Test'
- click_button 'Push events'
+ click_link 'Push events'
end
it { expect(page).to have_current_path(admin_hooks_path, ignore_query: true) }
@@ -142,7 +142,7 @@ RSpec.describe 'Admin::Hooks', feature_category: :integrations do
visit admin_hooks_path
click_button 'Test'
- click_button 'Merge request events'
+ click_link 'Merge request events'
expect(page).to have_content 'Hook executed successfully'
end
diff --git a/spec/features/admin/admin_labels_spec.rb b/spec/features/admin/admin_labels_spec.rb
index 8d2813d26f7..68d63ac321e 100644
--- a/spec/features/admin/admin_labels_spec.rb
+++ b/spec/features/admin/admin_labels_spec.rb
@@ -37,8 +37,11 @@ RSpec.describe 'admin issues labels', feature_category: :team_planning do
end
it 'deletes all labels', :js do
- page.all('.labels .js-remove-label').each do |remove|
- accept_gl_confirm(button_text: 'Delete label') { remove.click }
+ page.all('.labels .label-actions-list').each do |label|
+ label.click
+ accept_gl_confirm(button_text: 'Delete label') do
+ click_link 'Delete'
+ end
wait_for_requests
end
diff --git a/spec/features/admin/admin_mode/login_spec.rb b/spec/features/admin/admin_mode/login_spec.rb
index 393721fe451..c0c8b12342a 100644
--- a/spec/features/admin/admin_mode/login_spec.rb
+++ b/spec/features/admin/admin_mode/login_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authorization do
+RSpec.describe 'Admin Mode Login', feature_category: :system_access do
include TermsHelper
include UserLoginHelper
include LdapHelpers
@@ -15,249 +15,251 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
flag_values = [true, false]
flag_values.each do |val|
- before do
- stub_feature_flags(restyle_login_page: val)
- end
- context 'with valid username/password' do
- let(:user) { create(:admin, :two_factor) }
+ context "with #{val}" do
+ before do
+ stub_feature_flags(restyle_login_page: val)
+ end
+ context 'with valid username/password' do
+ let(:user) { create(:admin, :two_factor) }
- context 'using one-time code' do
- it 'blocks login if we reuse the same code immediately' do
- gitlab_sign_in(user, remember: true)
+ context 'using one-time code' do
+ it 'blocks login if we reuse the same code immediately' do
+ gitlab_sign_in(user, remember: true)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
- repeated_otp = user.current_otp
- enter_code(repeated_otp)
- gitlab_enable_admin_mode_sign_in(user)
+ repeated_otp = user.current_otp
+ enter_code(repeated_otp)
+ gitlab_enable_admin_mode_sign_in(user)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
- enter_code(repeated_otp)
+ enter_code(repeated_otp)
- expect(page).to have_current_path admin_session_path, ignore_query: true
- expect(page).to have_content('Invalid two-factor code')
- end
+ expect(page).to have_current_path admin_session_path, ignore_query: true
+ expect(page).to have_content('Invalid two-factor code')
+ end
- context 'not re-using codes' do
- before do
- gitlab_sign_in(user, remember: true)
+ context 'not re-using codes' do
+ before do
+ gitlab_sign_in(user, remember: true)
- expect(page).to have_content('Two-factor authentication code')
+ expect(page).to have_content('Enter verification code')
- enter_code(user.current_otp)
- gitlab_enable_admin_mode_sign_in(user)
+ enter_code(user.current_otp)
+ gitlab_enable_admin_mode_sign_in(user)
- expect(page).to have_content('Two-Factor Authentication')
- end
+ expect(page).to have_content(_('Enter verification code'))
+ end
- it 'allows login with valid code' do
- # Cannot reuse the TOTP
- travel_to(30.seconds.from_now) do
- enter_code(user.current_otp)
+ it 'allows login with valid code' do
+ # Cannot reuse the TOTP
+ travel_to(30.seconds.from_now) do
+ enter_code(user.current_otp)
- expect(page).to have_current_path admin_root_path, ignore_query: true
- expect(page).to have_content('Admin mode enabled')
+ expect(page).to have_current_path admin_root_path, ignore_query: true
+ expect(page).to have_content('Admin mode enabled')
+ end
end
- end
- it 'blocks login with invalid code' do
- # Cannot reuse the TOTP
- travel_to(30.seconds.from_now) do
- enter_code('foo')
+ it 'blocks login with invalid code' do
+ # Cannot reuse the TOTP
+ travel_to(30.seconds.from_now) do
+ enter_code('foo')
- expect(page).to have_content('Invalid two-factor code')
+ expect(page).to have_content('Invalid two-factor code')
+ end
end
- end
- it 'allows login with invalid code, then valid code' do
- # Cannot reuse the TOTP
- travel_to(30.seconds.from_now) do
- enter_code('foo')
+ it 'allows login with invalid code, then valid code' do
+ # Cannot reuse the TOTP
+ travel_to(30.seconds.from_now) do
+ enter_code('foo')
- expect(page).to have_content('Invalid two-factor code')
+ expect(page).to have_content('Invalid two-factor code')
- enter_code(user.current_otp)
+ enter_code(user.current_otp)
- expect(page).to have_current_path admin_root_path, ignore_query: true
- expect(page).to have_content('Admin mode enabled')
+ expect(page).to have_current_path admin_root_path, ignore_query: true
+ expect(page).to have_content('Admin mode enabled')
+ end
end
- end
- context 'using backup code' do
- let(:codes) { user.generate_otp_backup_codes! }
+ context 'using backup code' do
+ let(:codes) { user.generate_otp_backup_codes! }
- before do
- expect(codes.size).to eq 10
+ before do
+ expect(codes.size).to eq 10
- # Ensure the generated codes get saved
- user.save!
- end
+ # Ensure the generated codes get saved
+ user.save!
+ end
- context 'with valid code' do
- it 'allows login' do
- enter_code(codes.sample)
+ context 'with valid code' do
+ it 'allows login' do
+ enter_code(codes.sample)
- expect(page).to have_current_path admin_root_path, ignore_query: true
- expect(page).to have_content('Admin mode enabled')
- end
+ expect(page).to have_current_path admin_root_path, ignore_query: true
+ expect(page).to have_content('Admin mode enabled')
+ end
- it 'invalidates the used code' do
- expect { enter_code(codes.sample) }
- .to change { user.reload.otp_backup_codes.size }.by(-1)
+ it 'invalidates the used code' do
+ expect { enter_code(codes.sample) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+ end
end
- end
- context 'with invalid code' do
- it 'blocks login' do
- code = codes.sample
- expect(user.invalidate_otp_backup_code!(code)).to eq true
+ context 'with invalid code' do
+ it 'blocks login' do
+ code = codes.sample
+ expect(user.invalidate_otp_backup_code!(code)).to eq true
- user.save!
- expect(user.reload.otp_backup_codes.size).to eq 9
+ user.save!
+ expect(user.reload.otp_backup_codes.size).to eq 9
- enter_code(code)
+ enter_code(code)
- expect(page).to have_content('Invalid two-factor code.')
+ expect(page).to have_content('Invalid two-factor code.')
+ end
end
end
end
end
- end
-
- context 'when logging in via omniauth' do
- let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: 'my-uid', provider: 'saml', password_automatically_set: false) }
- let(:mock_saml_response) do
- File.read('spec/fixtures/authentication/saml_response.xml')
- end
- before do
- stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config_with_upstream_two_factor_authn_contexts])
- end
-
- context 'when authn_context is worth two factors' do
+ context 'when logging in via omniauth' do
+ let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: 'my-uid', provider: 'saml', password_automatically_set: false) }
let(:mock_saml_response) do
File.read('spec/fixtures/authentication/saml_response.xml')
- .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
- 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS')
end
- it 'signs user in without prompting for second factor' do
- sign_in_using_saml!
+ before do
+ stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config_with_upstream_two_factor_authn_contexts])
+ end
+
+ context 'when authn_context is worth two factors' do
+ let(:mock_saml_response) do
+ File.read('spec/fixtures/authentication/saml_response.xml')
+ .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
+ 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS')
+ end
- expect(page).not_to have_content('Two-Factor Authentication')
+ it 'signs user in without prompting for second factor' do
+ sign_in_using_saml!
- enable_admin_mode_using_saml!
+ expect(page).not_to have_content(_('Enter verification code'))
- expect(page).not_to have_content('Two-Factor Authentication')
- expect(page).to have_current_path admin_root_path, ignore_query: true
- expect(page).to have_content('Admin mode enabled')
+ enable_admin_mode_using_saml!
+
+ expect(page).not_to have_content(_('Enter verification code'))
+ expect(page).to have_current_path admin_root_path, ignore_query: true
+ expect(page).to have_content('Admin mode enabled')
+ end
end
- end
- context 'when two factor authentication is required' do
- it 'shows 2FA prompt after omniauth login' do
- sign_in_using_saml!
+ context 'when two factor authentication is required' do
+ it 'shows 2FA prompt after omniauth login' do
+ sign_in_using_saml!
- expect(page).to have_content('Two-Factor Authentication')
- enter_code(user.current_otp)
+ expect(page).to have_content(_('Enter verification code'))
+ enter_code(user.current_otp)
- enable_admin_mode_using_saml!
+ enable_admin_mode_using_saml!
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
- # Cannot reuse the TOTP
- travel_to(30.seconds.from_now) do
- enter_code(user.current_otp)
+ # Cannot reuse the TOTP
+ travel_to(30.seconds.from_now) do
+ enter_code(user.current_otp)
- expect(page).to have_current_path admin_root_path, ignore_query: true
- expect(page).to have_content('Admin mode enabled')
+ expect(page).to have_current_path admin_root_path, ignore_query: true
+ expect(page).to have_content('Admin mode enabled')
+ end
end
end
- end
- def sign_in_using_saml!
- gitlab_sign_in_via('saml', user, 'my-uid', mock_saml_response)
- end
+ def sign_in_using_saml!
+ gitlab_sign_in_via('saml', user, 'my-uid', mock_saml_response)
+ end
- def enable_admin_mode_using_saml!
- gitlab_enable_admin_mode_sign_in_via('saml', user, 'my-uid', mock_saml_response)
+ def enable_admin_mode_using_saml!
+ gitlab_enable_admin_mode_sign_in_via('saml', user, 'my-uid', mock_saml_response)
+ end
end
- end
- context 'when logging in via ldap' do
- let(:uid) { 'my-uid' }
- let(:provider_label) { 'Main LDAP' }
- let(:provider_name) { 'main' }
- let(:provider) { "ldap#{provider_name}" }
- let(:ldap_server_config) do
- {
- 'label' => provider_label,
- 'provider_name' => provider,
- 'attributes' => {},
- 'encryption' => 'plain',
- 'uid' => 'uid',
- 'base' => 'dc=example,dc=com'
- }
- end
+ context 'when logging in via ldap' do
+ let(:uid) { 'my-uid' }
+ let(:provider_label) { 'Main LDAP' }
+ let(:provider_name) { 'main' }
+ let(:provider) { "ldap#{provider_name}" }
+ let(:ldap_server_config) do
+ {
+ 'label' => provider_label,
+ 'provider_name' => provider,
+ 'attributes' => {},
+ 'encryption' => 'plain',
+ 'uid' => 'uid',
+ 'base' => 'dc=example,dc=com'
+ }
+ end
- let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: uid, provider: provider) }
+ let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: uid, provider: provider) }
- before do
- setup_ldap(provider, user, uid, ldap_server_config)
- end
+ before do
+ setup_ldap(provider, user, uid, ldap_server_config)
+ end
- context 'when two factor authentication is required' do
- it 'shows 2FA prompt after ldap login' do
- sign_in_using_ldap!(user, provider_label)
- expect(page).to have_content('Two-Factor Authentication')
+ context 'when two factor authentication is required' do
+ it 'shows 2FA prompt after ldap login' do
+ sign_in_using_ldap!(user, provider_label)
+ expect(page).to have_content(_('Enter verification code'))
- enter_code(user.current_otp)
- enable_admin_mode_using_ldap!(user)
+ enter_code(user.current_otp)
+ enable_admin_mode_using_ldap!(user)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
- # Cannot reuse the TOTP
- travel_to(30.seconds.from_now) do
- enter_code(user.current_otp)
+ # Cannot reuse the TOTP
+ travel_to(30.seconds.from_now) do
+ enter_code(user.current_otp)
- expect(page).to have_current_path admin_root_path, ignore_query: true
- expect(page).to have_content('Admin mode enabled')
+ expect(page).to have_current_path admin_root_path, ignore_query: true
+ expect(page).to have_content('Admin mode enabled')
+ end
end
end
- end
- def setup_ldap(provider, user, uid, ldap_server_config)
- stub_ldap_setting(enabled: true)
+ def setup_ldap(provider, user, uid, ldap_server_config)
+ stub_ldap_setting(enabled: true)
- allow(::Gitlab::Auth::Ldap::Config).to receive_messages(enabled: true, servers: [ldap_server_config])
- allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [provider.to_sym])
+ allow(::Gitlab::Auth::Ldap::Config).to receive_messages(enabled: true, servers: [ldap_server_config])
+ allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [provider.to_sym])
- Ldap::OmniauthCallbacksController.define_providers!
- Rails.application.reload_routes!
+ Ldap::OmniauthCallbacksController.define_providers!
+ Rails.application.reload_routes!
- mock_auth_hash(provider, uid, user.email)
- allow(Gitlab::Auth::Ldap::Access).to receive(:allowed?).with(user).and_return(true)
+ mock_auth_hash(provider, uid, user.email)
+ allow(Gitlab::Auth::Ldap::Access).to receive(:allowed?).with(user).and_return(true)
- allow_any_instance_of(ActionDispatch::Routing::RoutesProxy)
- .to receive(:"user_#{provider}_omniauth_callback_path")
- .and_return("/users/auth/#{provider}/callback")
- end
+ allow_any_instance_of(ActionDispatch::Routing::RoutesProxy)
+ .to receive(:"user_#{provider}_omniauth_callback_path")
+ .and_return("/users/auth/#{provider}/callback")
+ end
- def sign_in_using_ldap!(user, provider_label)
- visit new_user_session_path
- click_link provider_label
- fill_in 'username', with: user.username
- fill_in 'password', with: user.password
- click_button 'Sign in'
- end
+ def sign_in_using_ldap!(user, provider_label)
+ visit new_user_session_path
+ click_link provider_label
+ fill_in 'username', with: user.username
+ fill_in 'password', with: user.password
+ click_button 'Sign in'
+ end
- def enable_admin_mode_using_ldap!(user)
- visit new_admin_session_path
- click_link provider_label
- fill_in 'username', with: user.username
- fill_in 'password', with: user.password
- click_button 'Enter Admin Mode'
+ def enable_admin_mode_using_ldap!(user)
+ visit new_admin_session_path
+ click_link provider_label
+ fill_in 'username', with: user.username
+ fill_in 'password', with: user.password
+ click_button 'Enter admin mode'
+ end
end
end
end
diff --git a/spec/features/admin/admin_mode/logout_spec.rb b/spec/features/admin/admin_mode/logout_spec.rb
index f4e8941d25a..a64d3f241f6 100644
--- a/spec/features/admin/admin_mode/logout_spec.rb
+++ b/spec/features/admin/admin_mode/logout_spec.rb
@@ -2,10 +2,10 @@
require 'spec_helper'
-RSpec.describe 'Admin Mode Logout', :js, feature_category: :authentication_and_authorization do
+RSpec.describe 'Admin Mode Logout', :js, feature_category: :system_access do
include TermsHelper
include UserLoginHelper
- include Spec::Support::Helpers::Features::TopNavSpecHelpers
+ include Features::TopNavSpecHelpers
let(:user) { create(:admin) }
diff --git a/spec/features/admin/admin_mode/workers_spec.rb b/spec/features/admin/admin_mode/workers_spec.rb
index f3639fd0800..124c43eef9d 100644
--- a/spec/features/admin/admin_mode/workers_spec.rb
+++ b/spec/features/admin/admin_mode/workers_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
# Test an operation that triggers background jobs requiring administrative rights
-RSpec.describe 'Admin mode for workers', :request_store, feature_category: :authentication_and_authorization do
- include Spec::Support::Helpers::Features::AdminUsersHelpers
+RSpec.describe 'Admin mode for workers', :request_store, feature_category: :system_access do
+ include Features::AdminUsersHelpers
let(:user) { create(:user) }
let(:user_to_delete) { create(:user) }
diff --git a/spec/features/admin/admin_mode_spec.rb b/spec/features/admin/admin_mode_spec.rb
index 769ff75b5a2..65249fa0235 100644
--- a/spec/features/admin/admin_mode_spec.rb
+++ b/spec/features/admin/admin_mode_spec.rb
@@ -2,9 +2,9 @@
require 'spec_helper'
-RSpec.describe 'Admin mode', :js, feature_category: :not_owned do
+RSpec.describe 'Admin mode', :js, feature_category: :shared do
include MobileHelpers
- include Spec::Support::Helpers::Features::TopNavSpecHelpers
+ include Features::TopNavSpecHelpers
include StubENV
let(:admin) { create(:admin) }
@@ -50,7 +50,7 @@ RSpec.describe 'Admin mode', :js, feature_category: :not_owned do
fill_in 'user_password', with: admin.password
- click_button 'Enter Admin Mode'
+ click_button 'Enter admin mode'
expect(page).to have_current_path(admin_root_path)
end
@@ -65,7 +65,7 @@ RSpec.describe 'Admin mode', :js, feature_category: :not_owned do
fill_in 'user_password', with: admin.password
- click_button 'Enter Admin Mode'
+ click_button 'Enter admin mode'
expect(page).to have_current_path(admin_root_path)
end
@@ -111,7 +111,7 @@ RSpec.describe 'Admin mode', :js, feature_category: :not_owned do
open_top_nav
expect(page).to have_link(text: 'Admin', href: admin_root_path, visible: true)
- expect(page).to have_link(text: 'Leave Admin Mode', href: destroy_admin_session_path, visible: true)
+ expect(page).to have_link(text: 'Leave admin mode', href: destroy_admin_session_path, visible: true)
end
end
diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb
index f08e6521184..ac2e9de7aee 100644
--- a/spec/features/admin/admin_projects_spec.rb
+++ b/spec/features/admin/admin_projects_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe "Admin::Projects", feature_category: :projects do
- include Spec::Support::Helpers::Features::MembersHelpers
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::MembersHelpers
+ include Features::InviteMembersModalHelpers
include Spec::Support::Helpers::ModalHelpers
include ListboxHelpers
@@ -161,4 +161,44 @@ RSpec.describe "Admin::Projects", feature_category: :projects do
expect(page).to have_current_path(dashboard_projects_path, ignore_query: true, url: false)
end
end
+
+ describe 'project edit' do
+ it 'updates project details' do
+ project = create(:project, :private, name: 'Garfield', description: 'Funny Cat')
+
+ visit edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param })
+
+ aggregate_failures do
+ expect(page).to have_content(project.name)
+ expect(page).to have_content(project.description)
+ end
+
+ fill_in 'Project name', with: 'Scooby-Doo'
+ fill_in 'Project description (optional)', with: 'Funny Dog'
+
+ click_button 'Save changes'
+
+ visit edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param })
+
+ aggregate_failures do
+ expect(page).to have_content('Scooby-Doo')
+ expect(page).to have_content('Funny Dog')
+ end
+ end
+ end
+
+ describe 'project runner registration edit' do
+ it 'updates runner registration' do
+ visit edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param })
+
+ expect(find_field('New project runners can be registered')).to be_checked
+
+ uncheck 'New project runners can be registered'
+ click_button 'Save changes'
+
+ visit edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param })
+
+ expect(find_field('New project runners can be registered')).not_to be_checked
+ end
+ end
end
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 04dc206f052..582535790bd 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe "Admin Runners", feature_category: :runner_fleet do
- include Spec::Support::Helpers::Features::RunnersHelpers
+ include Features::RunnersHelpers
include Spec::Support::Helpers::ModalHelpers
let_it_be(:admin) { create(:admin) }
@@ -23,8 +23,6 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
describe "runners creation" do
before do
- stub_feature_flags(create_runner_workflow: true)
-
visit admin_runners_path
end
@@ -34,15 +32,30 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
end
describe "runners registration" do
- before do
- stub_feature_flags(create_runner_workflow: false)
+ context 'when create_runner_workflow_for_namespace is enabled' do
+ before do
+ stub_feature_flags(create_runner_workflow_for_admin: true)
- visit admin_runners_path
+ visit admin_runners_path
+ end
+
+ it_behaves_like "shows and resets runner registration token" do
+ let(:dropdown_text) { s_('Runners|Register an instance runner') }
+ let(:registration_token) { Gitlab::CurrentSettings.runners_registration_token }
+ end
end
- it_behaves_like "shows and resets runner registration token" do
- let(:dropdown_text) { s_('Runners|Register an instance runner') }
- let(:registration_token) { Gitlab::CurrentSettings.runners_registration_token }
+ context 'when create_runner_workflow_for_namespace is disabled' do
+ before do
+ stub_feature_flags(create_runner_workflow_for_admin: false)
+
+ visit admin_runners_path
+ end
+
+ it_behaves_like "shows and resets runner registration token" do
+ let(:dropdown_text) { s_('Runners|Register an instance runner') }
+ let(:registration_token) { Gitlab::CurrentSettings.runners_registration_token }
+ end
end
end
@@ -373,11 +386,9 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
it_behaves_like 'shows no runners found'
- it 'shows active tab' do
+ it 'shows active tab with no runner' do
expect(page).to have_link('Instance', class: 'active')
- end
- it 'shows no runner' do
expect(page).not_to have_content 'runner-project'
expect(page).not_to have_content 'runner-group'
end
@@ -471,10 +482,12 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
it_behaves_like 'shows no runners registered'
it 'shows tabs with total counts equal to 0' do
- expect(page).to have_link('All 0')
- expect(page).to have_link('Instance 0')
- expect(page).to have_link('Group 0')
- expect(page).to have_link('Project 0')
+ aggregate_failures do
+ expect(page).to have_link('All 0')
+ expect(page).to have_link('Instance 0')
+ expect(page).to have_link('Group 0')
+ expect(page).to have_link('Project 0')
+ end
end
end
@@ -493,6 +506,16 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
end
end
+ describe "Runner create page", :js do
+ before do
+ visit new_admin_runner_path
+ end
+
+ it_behaves_like 'creates runner and shows register page' do
+ let(:register_path_pattern) { register_admin_runner_path('.*') }
+ end
+ end
+
describe "Runner show page", :js do
let_it_be(:runner) do
create(
@@ -546,11 +569,8 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
end
end
- it 'deletes runner' do
+ it 'deletes runner and redirects to runner list' do
expect(page.find('[data-testid="alert-success"]')).to have_content('deleted')
- end
-
- it 'redirects to runner list' do
expect(current_url).to match(admin_runners_path)
end
end
@@ -593,12 +613,9 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
wait_for_requests
end
- it 'show success alert' do
- expect(page.find('[data-testid="alert-success"]')).to have_content('saved')
- end
-
- it 'redirects to runner page' do
+ it 'show success alert and redirects to runner page' do
expect(current_url).to match(admin_runner_path(project_runner))
+ expect(page.find('[data-testid="alert-success"]')).to have_content('saved')
end
end
@@ -632,12 +649,12 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
assigned_project = page.find('[data-testid="assigned-projects"]')
expect(page).to have_content('Runner assigned to project.')
- expect(assigned_project).to have_content(project2.path)
+ expect(assigned_project).to have_content(project2.name)
end
end
context 'with project runner' do
- let(:project_runner) { create(:ci_runner, :project, projects: [project1]) }
+ let_it_be(:project_runner) { create(:ci_runner, :project, projects: [project1]) }
before do
visit edit_admin_runner_path(project_runner)
@@ -647,7 +664,7 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
end
context 'with locked runner' do
- let(:locked_runner) { create(:ci_runner, :project, projects: [project1], locked: true) }
+ let_it_be(:locked_runner) { create(:ci_runner, :project, projects: [project1], locked: true) }
before do
visit edit_admin_runner_path(locked_runner)
@@ -658,7 +675,7 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
end
describe 'disable/destroy' do
- let(:runner) { create(:ci_runner, :project, projects: [project1]) }
+ let_it_be(:runner) { create(:ci_runner, :project, projects: [project1]) }
before do
visit edit_admin_runner_path(runner)
@@ -672,7 +689,7 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
new_runner_project = page.find('[data-testid="unassigned-projects"]')
expect(page).to have_content('Runner unassigned from project.')
- expect(new_runner_project).to have_content(project1.path)
+ expect(new_runner_project).to have_content(project1.name)
end
end
end
diff --git a/spec/features/admin/admin_sees_background_migrations_spec.rb b/spec/features/admin/admin_sees_background_migrations_spec.rb
index cad1bf74d2e..77266e65e4c 100644
--- a/spec/features/admin/admin_sees_background_migrations_spec.rb
+++ b/spec/features/admin/admin_sees_background_migrations_spec.rb
@@ -191,7 +191,7 @@ RSpec.describe "Admin > Admin sees background migrations", feature_category: :da
visit admin_background_migrations_path
within '#content-body' do
- expect(page).to have_link('Learn more', href: help_page_path('user/admin_area/monitoring/background_migrations'))
+ expect(page).to have_link('Learn more', href: help_page_path('update/background_migrations'))
end
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 26efed85513..1f43caf37e7 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin updates settings', feature_category: :not_owned do
+RSpec.describe 'Admin updates settings', feature_category: :shared do
include StubENV
include TermsHelper
include UsageDataHelpers
@@ -53,17 +53,6 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
end
it 'modify import sources' do
- expect(current_settings.import_sources).not_to be_empty
-
- page.within('[data-testid="admin-visibility-access-settings"]') do
- Gitlab::ImportSources.options.map do |name, _|
- uncheck name
- end
-
- click_button 'Save changes'
- end
-
- expect(page).to have_content "Application settings saved successfully"
expect(current_settings.import_sources).to be_empty
page.within('[data-testid="admin-visibility-access-settings"]') do
@@ -157,7 +146,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
expect(user_internal_regex['placeholder']).to eq 'Regex pattern'
end
- context 'Dormant users' do
+ context 'Dormant users', feature_category: :user_management do
context 'when Gitlab.com' do
let(:dot_com?) { true }
@@ -182,7 +171,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
expect(page).to have_field('Days of inactivity before deactivation')
end
- it 'changes dormant users' do
+ it 'changes dormant users', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408224' do
expect(page).to have_unchecked_field('Deactivate dormant users after a period of inactivity')
expect(current_settings.deactivate_dormant_users).to be_falsey
@@ -199,7 +188,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
expect(page).to have_checked_field('Deactivate dormant users after a period of inactivity')
end
- it 'change dormant users period' do
+ it 'change dormant users period', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408224' do
expect(page).to have_field _('Days of inactivity before deactivation')
page.within(find('[data-testid="account-limit"]')) do
@@ -360,8 +349,8 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
end
end
- context 'GitLab for Jira App settings' do
- it 'changes the setting' do
+ context 'GitLab for Jira App settings', feature_category: :integrations do
+ it 'changes the settings' do
page.within('#js-jira_connect-settings') do
fill_in 'Jira Connect Application ID', with: '1234'
fill_in 'Jira Connect Proxy URL', with: 'https://example.com'
@@ -375,6 +364,28 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
expect(page).to have_content "Application settings saved successfully"
end
end
+
+ context 'GitLab for Slack app settings', feature_category: :integrations do
+ it 'changes the settings' do
+ page.within('.as-slack') do
+ check 'Enable Slack application'
+ fill_in 'Client ID', with: 'slack_app_id'
+ fill_in 'Client secret', with: 'slack_app_secret'
+ fill_in 'Signing secret', with: 'slack_app_signing_secret'
+ fill_in 'Verification token', with: 'slack_app_verification_token'
+ click_button 'Save changes'
+ end
+
+ expect(current_settings).to have_attributes(
+ slack_app_enabled: true,
+ slack_app_id: 'slack_app_id',
+ slack_app_secret: 'slack_app_secret',
+ slack_app_signing_secret: 'slack_app_signing_secret',
+ slack_app_verification_token: 'slack_app_verification_token'
+ )
+ expect(page).to have_content 'Application settings saved successfully'
+ end
+ end
end
context 'Integrations page' do
@@ -426,6 +437,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
fill_in 'application_setting_auto_devops_domain', with: 'domain.com'
uncheck 'Keep the latest artifacts for all jobs in the latest successful pipelines'
uncheck 'Enable pipeline suggestion banner'
+ fill_in 'application_setting_ci_max_includes', with: 200
click_button 'Save changes'
end
@@ -433,6 +445,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
expect(current_settings.auto_devops_domain).to eq('domain.com')
expect(current_settings.keep_latest_artifact).to be false
expect(current_settings.suggest_pipeline_enabled).to be false
+ expect(current_settings.ci_max_includes).to be 200
expect(page).to have_content "Application settings saved successfully"
end
@@ -442,7 +455,6 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
page.within('.as-ci-cd') do
fill_in 'plan_limits_ci_pipeline_size', with: 10
fill_in 'plan_limits_ci_active_jobs', with: 20
- fill_in 'plan_limits_ci_active_pipelines', with: 25
fill_in 'plan_limits_ci_project_subscriptions', with: 30
fill_in 'plan_limits_ci_pipeline_schedules', with: 40
fill_in 'plan_limits_ci_needs_size_limit', with: 50
@@ -454,7 +466,6 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
limits = default_plan.reload.limits
expect(limits.ci_pipeline_size).to eq(10)
expect(limits.ci_active_jobs).to eq(20)
- expect(limits.ci_active_pipelines).to eq(25)
expect(limits.ci_project_subscriptions).to eq(30)
expect(limits.ci_pipeline_schedules).to eq(40)
expect(limits.ci_needs_size_limit).to eq(50)
@@ -487,7 +498,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
container_registry_delete_tags_service_timeout: 'Container Registry delete tags service execution timeout',
container_registry_expiration_policies_worker_capacity: 'Cleanup policy maximum workers running concurrently',
container_registry_cleanup_tags_service_max_list_size: 'Cleanup policy maximum number of tags to be deleted',
- container_registry_expiration_policies_caching: 'Enable container expiration caching'
+ container_registry_expiration_policies_caching: 'Enable cleanup policy caching'
}
end
@@ -638,6 +649,8 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
end
it 'loads togglable usage ping payload on click', :js do
+ allow(Gitlab::Usage::ServicePingReport).to receive(:for).and_return({ uuid: '12345678', hostname: '127.0.0.1' })
+
stub_usage_data_connections
stub_database_flavor_check
@@ -666,11 +679,11 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
visit network_admin_application_settings_path
page.within('.as-outbound') do
- check 'Allow requests to the local network from web hooks and services'
+ check 'Allow requests to the local network from webhooks and integrations'
# Enabled by default
uncheck 'Allow requests to the local network from system hooks'
# Enabled by default
- uncheck 'Enforce DNS rebinding attack protection'
+ uncheck 'Enforce DNS-rebinding attack protection'
click_button 'Save changes'
end
@@ -762,6 +775,18 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
expect(current_settings.users_get_by_id_limit_allowlist).to eq(%w[someone someone_else])
end
+ it 'changes Projects API rate limits settings' do
+ visit network_admin_application_settings_path
+
+ page.within('.as-projects-api-limits') do
+ fill_in 'Maximum requests per 10 minutes per IP address', with: 100
+ click_button 'Save changes'
+ end
+
+ expect(page).to have_content "Application settings saved successfully"
+ expect(current_settings.projects_api_rate_limit_unauthenticated).to eq(100)
+ end
+
shared_examples 'regular throttle rate limit settings' do
it 'changes rate limit settings' do
visit network_admin_application_settings_path
diff --git a/spec/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb
index 6c4a316ae77..21a001f12c3 100644
--- a/spec/features/admin/admin_system_info_spec.rb
+++ b/spec/features/admin/admin_system_info_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin System Info', feature_category: :not_owned do
+RSpec.describe 'Admin System Info', feature_category: :shared do
before do
admin = create(:admin)
sign_in(admin)
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
index 5e6cc206883..0350c8ab066 100644
--- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -2,9 +2,9 @@
require 'spec_helper'
-RSpec.describe 'Admin > Users > Impersonation Tokens', :js, feature_category: :authentication_and_authorization do
+RSpec.describe 'Admin > Users > Impersonation Tokens', :js, feature_category: :system_access do
include Spec::Support::Helpers::ModalHelpers
- include Spec::Support::Helpers::AccessTokenHelpers
+ include Features::AccessTokenHelpers
let(:admin) { create(:admin) }
let!(:user) { create(:user) }
diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb
index 318572a7664..d9d36ec3bae 100644
--- a/spec/features/admin/admin_uses_repository_checks_spec.rb
+++ b/spec/features/admin/admin_uses_repository_checks_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe 'Admin uses repository checks', :request_store, feature_category:
visit_admin_project_page(project)
expect(page).not_to have_css('.repository-check')
- expect(page).to have_content('Enter Admin Mode')
+ expect(page).to have_content('Enter admin mode')
end
end
diff --git a/spec/features/admin/broadcast_messages_spec.rb b/spec/features/admin/broadcast_messages_spec.rb
new file mode 100644
index 00000000000..fca4cdb0ff4
--- /dev/null
+++ b/spec/features/admin/broadcast_messages_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Admin Broadcast Messages', :js, feature_category: :onboarding do
+ context 'when creating and editing' do
+ it 'previews, creates and edits a broadcast message' do
+ admin = create(:admin)
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+
+ # create
+ visit admin_broadcast_messages_path
+
+ fill_in 'Message', with: 'test message'
+
+ wait_for_requests
+
+ page.within(preview_container) do
+ expect(page).to have_content('test message')
+ end
+
+ click_button 'Add broadcast message'
+
+ wait_for_requests
+
+ page.within(preview_container) do
+ expect(page).to have_content('Your message here')
+ end
+
+ page.within(first_message_container) do
+ expect(page).to have_content('test message')
+ end
+
+ # edit
+ page.within(first_message_container) do
+ find('[data-testid="edit-message"]').click
+ end
+
+ wait_for_requests
+
+ expect(find('[data-testid="message-input"]').value).to eq('test message')
+
+ fill_in 'Message', with: 'changed test message'
+
+ wait_for_requests
+
+ page.within(preview_container) do
+ expect(page).to have_content('changed test message')
+ end
+
+ click_button 'Update broadcast message'
+
+ wait_for_requests
+
+ page.within(preview_container) do
+ expect(page).to have_content('Your message here')
+ end
+
+ page.within(first_message_container) do
+ expect(page).to have_content('changed test message')
+ end
+ end
+
+ def preview_container
+ find('[data-testid="preview-broadcast-message"]')
+ end
+
+ def first_message_container
+ find('[data-testid="message-row"]', match: :first)
+ end
+ end
+end
diff --git a/spec/features/admin/integrations/instance_integrations_spec.rb b/spec/features/admin/integrations/instance_integrations_spec.rb
index 3b2ed1d9810..d963aa700eb 100644
--- a/spec/features/admin/integrations/instance_integrations_spec.rb
+++ b/spec/features/admin/integrations/instance_integrations_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe 'Instance integrations', :js, feature_category: :integrations do
include_context 'instance integration activation'
+ before do
+ stub_feature_flags(remove_monitor_metrics: false)
+ end
+
it_behaves_like 'integration settings form' do
let(:integrations) { Integration.find_or_initialize_all_non_project_specific(Integration.for_instance) }
diff --git a/spec/features/admin/users/user_spec.rb b/spec/features/admin/users/user_spec.rb
index 66129617220..18d62cb585f 100644
--- a/spec/features/admin/users/user_spec.rb
+++ b/spec/features/admin/users/user_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Admin::Users::User', feature_category: :user_management do
- include Spec::Support::Helpers::Features::AdminUsersHelpers
+ include Features::AdminUsersHelpers
include Spec::Support::Helpers::ModalHelpers
let_it_be(:user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') }
@@ -273,8 +273,11 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do
end
context 'when viewing the confirm email warning', :js do
- let_it_be(:another_user) { create(:user, :unconfirmed) }
+ before do
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
+ end
+ let_it_be(:another_user) { create(:user, :unconfirmed) }
let(:warning_alert) { page.find(:css, '[data-testid="alert-warning"]') }
let(:expected_styling) { { 'pointer-events' => 'none', 'cursor' => 'default' } }
diff --git a/spec/features/admin/users/users_spec.rb b/spec/features/admin/users/users_spec.rb
index 07db0750074..8e80ce5edd9 100644
--- a/spec/features/admin/users/users_spec.rb
+++ b/spec/features/admin/users/users_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Admin::Users', feature_category: :user_management do
- include Spec::Support::Helpers::Features::AdminUsersHelpers
+ include Features::AdminUsersHelpers
include Spec::Support::Helpers::ModalHelpers
include ListboxHelpers
@@ -311,6 +311,40 @@ RSpec.describe 'Admin::Users', feature_category: :user_management do
end
end
+ describe 'users pending approval' do
+ it 'sends a welcome email and a password reset email to the user upon admin approval', :sidekiq_inline do
+ user = create(:user, :blocked_pending_approval, created_by_id: current_user.id)
+
+ visit admin_users_path
+
+ click_link 'Pending approval'
+
+ click_user_dropdown_toggle(user.id)
+
+ find('[data-testid="approve"]').click
+
+ expect(page).to have_content("Approve user #{user.name}?")
+
+ within_modal do
+ perform_enqueued_jobs do
+ click_button 'Approve'
+ end
+ end
+
+ expect(page).to have_content('Successfully approved')
+
+ welcome_email = ActionMailer::Base.deliveries.find { |m| m.subject == 'Welcome to GitLab!' }
+ expect(welcome_email.to).to eq([user.email])
+ expect(welcome_email.text_part.body).to have_content('Your GitLab account request has been approved!')
+
+ password_reset_email = ActionMailer::Base.deliveries.find { |m| m.subject == 'Account was created for you' }
+ expect(password_reset_email.to).to eq([user.email])
+ expect(password_reset_email.text_part.body).to have_content('Click here to set your password')
+
+ expect(ActionMailer::Base.deliveries.count).to eq(2)
+ end
+ end
+
describe 'internal users' do
context 'when showing a `Ghost User`' do
let_it_be(:ghost_user) { create(:user, :ghost) }
diff --git a/spec/features/admin_variables_spec.rb b/spec/features/admin_variables_spec.rb
index d1adbf59984..744d18a3b6d 100644
--- a/spec/features/admin_variables_spec.rb
+++ b/spec/features/admin_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Instance variables', :js, feature_category: :pipeline_authoring do
+RSpec.describe 'Instance variables', :js, feature_category: :secrets_management do
let(:admin) { create(:admin) }
let(:page_path) { ci_cd_admin_application_settings_path }
@@ -12,9 +12,21 @@ RSpec.describe 'Instance variables', :js, feature_category: :pipeline_authoring
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
+
visit page_path
wait_for_requests
end
- it_behaves_like 'variable list', isAdmin: true
+ context 'when ci_variables_pages FF is enabled' do
+ it_behaves_like 'variable list', is_admin: true
+ it_behaves_like 'variable list pagination', :ci_instance_variable
+ end
+
+ context 'when ci_variables_pages FF is disabled' do
+ before do
+ stub_feature_flags(ci_variables_pages: false)
+ end
+
+ it_behaves_like 'variable list', is_admin: true
+ 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 70223b2c0d4..94f5cf8f5b2 100644
--- a/spec/features/alerts_settings/user_views_alerts_settings_spec.rb
+++ b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb
@@ -19,6 +19,7 @@ RSpec.describe 'Alert integrations settings form', :js, feature_category: :incid
describe 'when viewing alert integrations as a maintainer' do
context 'with the default page permissions' do
before do
+ stub_feature_flags(remove_monitor_metrics: false)
visit project_settings_operations_path(project, anchor: 'js-alert-management-settings')
wait_for_requests
end
diff --git a/spec/features/boards/board_filters_spec.rb b/spec/features/boards/board_filters_spec.rb
index dee63be8119..006b7ce45d4 100644
--- a/spec/features/boards/board_filters_spec.rb
+++ b/spec/features/boards/board_filters_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe 'Issue board filters', :js, feature_category: :team_planning do
set_filter('assignee')
end
- it_behaves_like 'loads all the users when opened' do
+ it_behaves_like 'loads all the users when opened', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/351426' do
let(:issue) { issue_2 }
end
end
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index 3e2e391d060..1ea6e079104 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -150,8 +150,7 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do
find('.board .board-list')
inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do
- evaluate_script("window.scrollTo(0, document.body.scrollHeight)")
- evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight")
+ evaluate_script("[...document.querySelectorAll('.board:nth-child(2) .board-list [data-testid=\"board-card-gl-io\"]')].pop().scrollIntoView()")
end
expect(page).to have_selector('.board-card', count: 20)
@@ -160,8 +159,7 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do
find('.board .board-list')
inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do
- evaluate_script("window.scrollTo(0, document.body.scrollHeight)")
- evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight")
+ evaluate_script("[...document.querySelectorAll('.board:nth-child(2) .board-list [data-testid=\"board-card-gl-io\"]')].pop().scrollIntoView()")
end
expect(page).to have_selector('.board-card', count: 30)
@@ -170,8 +168,7 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do
find('.board .board-list')
inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do
- evaluate_script("window.scrollTo(0, document.body.scrollHeight)")
- evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight")
+ evaluate_script("[...document.querySelectorAll('.board:nth-child(2) .board-list [data-testid=\"board-card-gl-io\"]')].pop().scrollIntoView()")
end
expect(page).to have_selector('.board-card', count: 38)
@@ -594,7 +591,9 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do
def remove_list
page.within(find('.board:nth-child(2)')) do
- find('button[title="List settings"]').click
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button('Edit list settings')
end
page.within(find('.js-board-settings-sidebar')) do
diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb
index 8aecaab42c2..b6196fa6a1d 100644
--- a/spec/features/boards/issue_ordering_spec.rb
+++ b/spec/features/boards/issue_ordering_spec.rb
@@ -138,7 +138,7 @@ RSpec.describe 'Issue Boards', :js, feature_category: :team_planning do
wait_for_requests
end
- it 'moves to end of list' do
+ it 'moves to end of list', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410100' do
expect(all('.board-card').first).to have_content(issue3.title)
page.within(find('.board:nth-child(2)')) do
@@ -151,7 +151,7 @@ RSpec.describe 'Issue Boards', :js, feature_category: :team_planning do
expect(all('.board-card').last).to have_content(issue3.title)
end
- it 'moves to start of list' do
+ it 'moves to start of list', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410100' do
expect(all('.board-card').last).to have_content(issue1.title)
page.within(find('.board:nth-child(2)')) do
diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb
index d597c57ac1c..6753f0ea009 100644
--- a/spec/features/boards/new_issue_spec.rb
+++ b/spec/features/boards/new_issue_spec.rb
@@ -32,18 +32,23 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
end
it 'displays new issue button' do
- expect(first('.board')).to have_button('New issue', count: 1)
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ expect(first('.board')).to have_button('Create new issue', count: 1)
end
it 'does not display new issue button in closed list' do
page.within('.board:nth-child(3)') do
- expect(page).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(page).not_to have_button('Create new issue')
end
end
it 'shows form when clicking button' do
page.within(first('.board')) do
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button 'Create new issue'
expect(page).to have_selector('.board-new-issue-form')
end
@@ -51,7 +56,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
it 'hides form when clicking cancel' do
page.within(first('.board')) do
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button 'Create new issue'
expect(page).to have_selector('.board-new-issue-form')
@@ -63,7 +70,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
it 'creates new issue, places it on top of the list, and opens sidebar' do
page.within(first('.board')) do
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button 'Create new issue'
end
page.within(first('.board-new-issue-form')) do
@@ -91,7 +100,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
it 'successfuly loads labels to be added to newly created issue' do
page.within(first('.board')) do
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button 'Create new issue'
end
page.within(first('.board-new-issue-form')) do
@@ -121,7 +132,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
wait_for_all_requests
page.within('.board:nth-child(2)') do
- click_button('New issue')
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button('Create new issue')
page.within(first('.board-new-issue-form')) do
find('.form-control').set('new issue')
@@ -144,12 +157,14 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
end
it 'does not display new issue button in open list' do
- expect(first('.board')).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(first('.board')).not_to have_button('Create new issue')
end
it 'does not display new issue button in label list' do
page.within('.board:nth-child(2)') do
- expect(page).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(page).not_to have_button('Create new issue')
end
end
end
@@ -173,7 +188,8 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
context 'when backlog does not exist' do
it 'does not display new issue button in label list' do
page.within('.board.is-draggable') do
- expect(page).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(page).not_to have_button('Create new issue')
end
end
end
@@ -182,12 +198,14 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
let_it_be(:backlog_list) { create(:backlog_list, board: group_board) }
it 'does not display new issue button in open list' do
- expect(first('.board')).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(first('.board')).not_to have_button('Create new issue')
end
it 'does not display new issue button in label list' do
page.within('.board.is-draggable') do
- expect(page).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(page).not_to have_button('Create new issue')
end
end
end
@@ -205,7 +223,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
context 'when backlog does not exist' do
it 'display new issue button in label list' do
- expect(board_list_header).to have_button('New issue')
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ expect(board_list_header).to have_button('Create new issue')
end
end
@@ -214,7 +234,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
before do
page.within(board_list_header) do
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button 'Create new issue'
end
project_select_dropdown.click
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index 0a16e95c0bf..358da1e1279 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe 'Project issue boards sidebar', :js, feature_category: :team_plan
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, namespace: group) }
let_it_be(:board) { create(:board, project: project) }
- let_it_be(:label) { create(:label, project: project, name: 'Label') }
+ let_it_be(:label) { create(:label, project: project, name: 'Label') }
let_it_be(:list) { create(:list, board: board, label: label, position: 0) }
let_it_be(:issue, reload: true) { create(:issue, project: project, relative_position: 1) }
diff --git a/spec/features/breadcrumbs_schema_markup_spec.rb b/spec/features/breadcrumbs_schema_markup_spec.rb
index d924423c9a9..6610519cd24 100644
--- a/spec/features/breadcrumbs_schema_markup_spec.rb
+++ b/spec/features/breadcrumbs_schema_markup_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures, feature_category: :not_owned do
+RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures, feature_category: :shared do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, namespace: user.namespace) }
let_it_be(:issue) { create(:issue, project: project) }
diff --git a/spec/features/broadcast_messages_spec.rb b/spec/features/broadcast_messages_spec.rb
index 3e4289347e3..2fad15c8a1f 100644
--- a/spec/features/broadcast_messages_spec.rb
+++ b/spec/features/broadcast_messages_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Broadcast Messages', feature_category: :onboarding do
shared_examples 'a Broadcast Messages' do |type|
it 'shows broadcast message' do
- visit root_path
+ visit explore_projects_path
expect(page).to have_content 'SampleMessage'
end
@@ -15,17 +15,17 @@ RSpec.describe 'Broadcast Messages', feature_category: :onboarding do
it 'renders styled links' do
create(:broadcast_message, type, message: "<a href='gitlab.com' style='color: purple'>click me</a>")
- visit root_path
+ visit explore_projects_path
expected_html = "<p><a href=\"gitlab.com\" style=\"color: purple\">click me</a></p>"
expect(page.body).to include(expected_html)
end
end
- shared_examples 'a dismissable Broadcast Messages' do
+ shared_examples 'a dismissible Broadcast Messages' do
it 'hides broadcast message after dismiss', :js,
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/390900' do
- visit root_path
+ visit explore_projects_path
find('.js-dismiss-current-broadcast-notification').click
@@ -34,25 +34,25 @@ RSpec.describe 'Broadcast Messages', feature_category: :onboarding do
it 'broadcast message is still hidden after refresh', :js,
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391406' do
- visit root_path
+ visit explore_projects_path
find('.js-dismiss-current-broadcast-notification').click
wait_for_cookie_set("hide_broadcast_message_#{broadcast_message.id}")
- visit root_path
+ visit explore_projects_path
expect(page).not_to have_content 'SampleMessage'
end
end
describe 'banner type' do
- let!(:broadcast_message) { create(:broadcast_message, message: 'SampleMessage') }
+ let_it_be(:broadcast_message) { create(:broadcast_message, message: 'SampleMessage') }
it_behaves_like 'a Broadcast Messages'
- it 'is not dismissable' do
- visit root_path
+ it 'is not dismissible' do
+ visit explore_projects_path
expect(page).not_to have_selector('.js-dismiss-current-broadcast-notification')
end
@@ -62,33 +62,33 @@ RSpec.describe 'Broadcast Messages', feature_category: :onboarding do
sign_in(user)
- visit root_path
+ visit explore_projects_path
expect(page).to have_content 'Hi {{name}}'
end
end
- describe 'dismissable banner type' do
- let!(:broadcast_message) { create(:broadcast_message, dismissable: true, message: 'SampleMessage') }
+ describe 'dismissible banner type' do
+ let_it_be(:broadcast_message) { create(:broadcast_message, dismissable: true, message: 'SampleMessage') }
it_behaves_like 'a Broadcast Messages'
- it_behaves_like 'a dismissable Broadcast Messages'
+ it_behaves_like 'a dismissible Broadcast Messages'
end
describe 'notification type' do
- let!(:broadcast_message) { create(:broadcast_message, :notification, message: 'SampleMessage') }
+ let_it_be(:broadcast_message) { create(:broadcast_message, :notification, message: 'SampleMessage') }
it_behaves_like 'a Broadcast Messages', :notification
- it_behaves_like 'a dismissable Broadcast Messages'
+ it_behaves_like 'a dismissible Broadcast Messages'
it 'replaces placeholders' do
create(:broadcast_message, :notification, message: 'Hi {{name}}')
sign_in(user)
- visit root_path
+ visit explore_projects_path
expect(page).to have_content "Hi #{user.name}"
end
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index b2a29c88b68..67baed5dc91 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -44,15 +44,25 @@ RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do
"#{get_cell_level_selector(contributions)}[title='#{contribution_text}<br /><span class=\"gl-text-gray-300\">#{date}</span>']"
end
+ def get_days_of_week
+ page.all('[data-testid="user-contrib-cell-group"]')[1]
+ .all('[data-testid="user-contrib-cell"]')
+ .map do |node|
+ node[:title].match(/(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday)/)[0]
+ end
+ end
+
def push_code_contribution
event = create(:push_event, project: contributed_project, author: user)
- create(:push_event_payload,
- event: event,
- commit_from: '11f9ac0a48b62cef25eedede4c1819964f08d5ce',
- commit_to: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2',
- commit_count: 3,
- ref: 'master')
+ create(
+ :push_event_payload,
+ event: event,
+ commit_from: '11f9ac0a48b62cef25eedede4c1819964f08d5ce',
+ commit_to: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2',
+ commit_count: 3,
+ ref: 'master'
+ )
end
def note_comment_contribution
@@ -70,162 +80,331 @@ RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do
find('#js-overview .user-calendar-activities', visible: visible).text
end
- before do
- stub_feature_flags(profile_tabs_vue: false)
- sign_in user
- end
-
- describe 'calendar day selection' do
+ shared_context 'when user page is visited' do
before do
visit user.username
- page.find('.js-overview-tab a').click
+ page.click_link('Overview')
wait_for_requests
end
+ end
- it 'displays calendar' do
- expect(find('#js-overview')).to have_css('.js-contrib-calendar')
+ context 'with `profile_tabs_vue` feature flag disabled' do
+ before do
+ stub_feature_flags(profile_tabs_vue: false)
+ sign_in user
end
- describe 'select calendar day' do
- let(:cells) { page.all('#js-overview .user-contrib-cell') }
+ describe 'calendar day selection' do
+ include_context 'when user page is visited'
- before do
- cells[0].click
- wait_for_requests
- @first_day_activities = selected_day_activities
+ it 'displays calendar' do
+ expect(find('#js-overview')).to have_css('.js-contrib-calendar')
end
- it 'displays calendar day activities' do
- expect(selected_day_activities).not_to be_empty
- end
+ describe 'select calendar day' do
+ let(:cells) { page.all('#js-overview .user-contrib-cell') }
- describe 'select another calendar day' do
before do
- cells[1].click
+ cells[0].click
wait_for_requests
end
- it 'displays different calendar day activities' do
- expect(selected_day_activities).not_to eq(@first_day_activities)
+ it 'displays calendar day activities' do
+ expect(selected_day_activities).not_to be_empty
end
- end
- describe 'deselect calendar day' do
- before do
- cells[0].click
- wait_for_requests
- cells[0].click
+ describe 'select another calendar day' do
+ it 'displays different calendar day activities' do
+ first_day_activities = selected_day_activities
+
+ cells[1].click
+ wait_for_requests
+
+ expect(selected_day_activities).not_to eq(first_day_activities)
+ end
end
- it 'hides calendar day activities' do
- expect(selected_day_activities(visible: false)).to be_empty
+ describe 'deselect calendar day' do
+ before do
+ cells[0].click
+ wait_for_requests
+ cells[0].click
+ end
+
+ it 'hides calendar day activities' do
+ expect(selected_day_activities(visible: false)).to be_empty
+ end
end
end
end
- end
- shared_context 'visit user page' do
- before do
- visit user.username
- page.find('.js-overview-tab a').click
- wait_for_requests
- end
- end
+ describe 'calendar daily activities' do
+ shared_examples 'a day with activity' do |contribution_count:|
+ include_context 'when user page is visited'
+
+ it 'displays calendar activity square for 1 contribution', :sidekiq_inline do
+ expect(find('#js-overview')).to have_selector(get_cell_level_selector(contribution_count), count: 1)
+
+ today = Date.today.strftime(date_format)
+ expect(find('#js-overview')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
+ end
+ end
- describe 'calendar daily activities' do
- shared_examples 'a day with activity' do |contribution_count:|
- include_context 'visit user page'
+ describe '1 issue and 1 work item creation calendar activity' do
+ before do
+ Issues::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: issue_params,
+ spam_params: nil
+ ).execute
+ WorkItems::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: { title: 'new task' },
+ spam_params: nil
+ ).execute
+ end
- it 'displays calendar activity square for 1 contribution', :sidekiq_might_not_need_inline do
- expect(find('#js-overview')).to have_selector(get_cell_level_selector(contribution_count), count: 1)
+ it_behaves_like 'a day with activity', contribution_count: 2
- today = Date.today.strftime(date_format)
- expect(find('#js-overview')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
+ describe 'issue title is shown on activity page' do
+ include_context 'when user page is visited'
+
+ it 'displays calendar activity log', :sidekiq_inline do
+ expect(all('#js-overview .overview-content-list .event-target-title').map(&:text)).to contain_exactly(
+ match(/#{issue_title}/),
+ match(/new task/)
+ )
+ end
+ end
end
- end
- describe '1 issue and 1 work item creation calendar activity' do
- before do
- Issues::CreateService.new(container: contributed_project, current_user: user, params: issue_params, spam_params: nil).execute
- WorkItems::CreateService.new(
- container: contributed_project,
- current_user: user,
- params: { title: 'new task' },
- spam_params: nil
- ).execute
+ describe '1 comment calendar activity' do
+ before do
+ note_comment_contribution
+ end
+
+ it_behaves_like 'a day with activity', contribution_count: 1
end
- it_behaves_like 'a day with activity', contribution_count: 2
+ describe '10 calendar activities' do
+ before do
+ 10.times { push_code_contribution }
+ end
+
+ it_behaves_like 'a day with activity', contribution_count: 10
+ end
+
+ describe 'calendar activity on two days' do
+ before do
+ push_code_contribution
+
+ travel_to(Date.yesterday) do
+ Issues::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: issue_params,
+ spam_params: nil
+ ).execute
+ end
+ end
+
+ include_context 'when user page is visited'
- describe 'issue title is shown on activity page' do
- include_context 'visit user page'
+ it 'displays calendar activity squares for both days', :sidekiq_inline do
+ expect(find('#js-overview')).to have_selector(get_cell_level_selector(1), count: 2)
+ end
- it 'displays calendar activity log', :sidekiq_inline do
- expect(all('#js-overview .overview-content-list .event-target-title').map(&:text)).to contain_exactly(
- match(/#{issue_title}/),
- match(/new task/)
- )
+ it 'displays calendar activity square for yesterday', :sidekiq_inline do
+ yesterday = Date.yesterday.strftime(date_format)
+ expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
+ end
+
+ it 'displays calendar activity square for today' do
+ today = Date.today.strftime(date_format)
+ expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, today), count: 1)
end
end
end
- describe '1 comment calendar activity' do
- before do
- note_comment_contribution
+ describe 'on smaller screens' do
+ shared_examples 'hidden activity calendar' do
+ include_context 'when user page is visited'
+
+ it 'hides the activity calender' do
+ expect(find('#js-overview')).not_to have_css('.js-contrib-calendar')
+ end
end
- it_behaves_like 'a day with activity', contribution_count: 1
+ context 'when screen size is xs' do
+ before do
+ resize_screen_xs
+ end
+
+ it_behaves_like 'hidden activity calendar'
+ end
end
- describe '10 calendar activities' do
- before do
- 10.times { push_code_contribution }
+ describe 'first_day_of_week setting' do
+ context 'when first day of the week is set to Monday' do
+ before do
+ stub_application_setting(first_day_of_week: 1)
+ end
+
+ include_context 'when user page is visited'
+
+ it 'shows calendar with Monday as the first day of the week' do
+ expect(get_days_of_week).to eq(%w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday])
+ end
+ end
+
+ context 'when first day of the week is set to Sunday' do
+ before do
+ stub_application_setting(first_day_of_week: 0)
+ end
+
+ include_context 'when user page is visited'
+
+ it 'shows calendar with Sunday as the first day of the week' do
+ expect(get_days_of_week).to eq(%w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday])
+ end
end
+ end
+ end
+
+ context 'with `profile_tabs_vue` feature flag enabled' do
+ before do
+ sign_in user
+ end
- it_behaves_like 'a day with activity', contribution_count: 10
+ include_context 'when user page is visited'
+
+ it 'displays calendar' do
+ expect(page).to have_css('[data-testid="contrib-calendar"]')
end
- describe 'calendar activity on two days' do
- before do
- push_code_contribution
+ describe 'calendar daily activities' do
+ shared_examples 'a day with activity' do |contribution_count:|
+ include_context 'when user page is visited'
- travel_to(Date.yesterday) do
- Issues::CreateService.new(container: contributed_project, current_user: user, params: issue_params, spam_params: nil).execute
+ it 'displays calendar activity square for 1 contribution', :sidekiq_inline do
+ expect(page).to have_selector(get_cell_level_selector(contribution_count), count: 1)
+
+ today = Date.today.strftime(date_format)
+ expect(page).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
end
end
- include_context 'visit user page'
- it 'displays calendar activity squares for both days', :sidekiq_might_not_need_inline do
- expect(find('#js-overview')).to have_selector(get_cell_level_selector(1), count: 2)
+ describe '1 issue and 1 work item creation calendar activity' do
+ before do
+ Issues::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: issue_params,
+ spam_params: nil
+ ).execute
+ WorkItems::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: { title: 'new task' },
+ spam_params: nil
+ ).execute
+ end
+
+ it_behaves_like 'a day with activity', contribution_count: 2
end
- it 'displays calendar activity square for yesterday', :sidekiq_might_not_need_inline do
- yesterday = Date.yesterday.strftime(date_format)
- expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
+ describe '1 comment calendar activity' do
+ before do
+ note_comment_contribution
+ end
+
+ it_behaves_like 'a day with activity', contribution_count: 1
end
- it 'displays calendar activity square for today' do
- today = Date.today.strftime(date_format)
- expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, today), count: 1)
+ describe '10 calendar activities' do
+ before do
+ 10.times { push_code_contribution }
+ end
+
+ it_behaves_like 'a day with activity', contribution_count: 10
+ end
+
+ describe 'calendar activity on two days' do
+ before do
+ push_code_contribution
+
+ travel_to(Date.yesterday) do
+ Issues::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: issue_params,
+ spam_params: nil
+ ).execute
+ end
+ end
+
+ include_context 'when user page is visited'
+
+ it 'displays calendar activity squares for both days', :sidekiq_inline do
+ expect(page).to have_selector(get_cell_level_selector(1), count: 2)
+ end
+
+ it 'displays calendar activity square for yesterday', :sidekiq_inline do
+ yesterday = Date.yesterday.strftime(date_format)
+ expect(page).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
+ end
+
+ it 'displays calendar activity square for today' do
+ today = Date.today.strftime(date_format)
+ expect(page).to have_selector(get_cell_date_selector(1, today), count: 1)
+ end
end
end
- end
- describe 'on smaller screens' do
- shared_examples 'hidden activity calendar' do
- include_context 'visit user page'
+ describe 'on smaller screens' do
+ shared_examples 'hidden activity calendar' do
+ include_context 'when user page is visited'
- it 'hides the activity calender' do
- expect(find('#js-overview')).not_to have_css('.js-contrib-calendar')
+ it 'hides the activity calender' do
+ expect(page).not_to have_css('[data-testid="contrib-calendar"]')
+ end
+ end
+
+ context 'when screen size is xs' do
+ before do
+ resize_screen_xs
+ end
+
+ it_behaves_like 'hidden activity calendar'
end
end
- context 'size xs' do
- before do
- resize_screen_xs
+ describe 'first_day_of_week setting' do
+ context 'when first day of the week is set to Monday' do
+ before do
+ stub_application_setting(first_day_of_week: 1)
+ end
+
+ include_context 'when user page is visited'
+
+ it 'shows calendar with Monday as the first day of the week' do
+ expect(get_days_of_week).to eq(%w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday])
+ end
end
- it_behaves_like 'hidden activity calendar'
+ context 'when first day of the week is set to Sunday' do
+ before do
+ stub_application_setting(first_day_of_week: 0)
+ end
+
+ include_context 'when user page is visited'
+
+ it 'shows calendar with Sunday as the first day of the week' do
+ expect(get_days_of_week).to eq(%w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday])
+ end
+ end
end
end
end
diff --git a/spec/features/callouts/registration_enabled_spec.rb b/spec/features/callouts/registration_enabled_spec.rb
index 15c900592a1..3282a40854d 100644
--- a/spec/features/callouts/registration_enabled_spec.rb
+++ b/spec/features/callouts/registration_enabled_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Registration enabled callout', feature_category: :authentication_and_authorization do
+RSpec.describe 'Registration enabled callout', feature_category: :system_access do
let_it_be(:admin) { create(:admin) }
let_it_be(:non_admin) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/features/canonical_link_spec.rb b/spec/features/canonical_link_spec.rb
index d8f9a7584e7..0ed76c30ce4 100644
--- a/spec/features/canonical_link_spec.rb
+++ b/spec/features/canonical_link_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Canonical link', feature_category: :remote_development do
- include Spec::Support::Helpers::Features::CanonicalLinkHelpers
+ include Features::CanonicalLinkHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, namespace: user.namespace) }
diff --git a/spec/features/clusters/cluster_detail_page_spec.rb b/spec/features/clusters/cluster_detail_page_spec.rb
index e8fb5f4105d..31dec5e38da 100644
--- a/spec/features/clusters/cluster_detail_page_spec.rb
+++ b/spec/features/clusters/cluster_detail_page_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Clusterable > Show page', feature_category: :kubernetes_management do
+RSpec.describe 'Clusterable > Show page', feature_category: :deployment_management do
include KubernetesHelpers
let(:current_user) { create(:user) }
diff --git a/spec/features/clusters/cluster_health_dashboard_spec.rb b/spec/features/clusters/cluster_health_dashboard_spec.rb
index b557f803a99..e932f8c6b98 100644
--- a/spec/features/clusters/cluster_health_dashboard_spec.rb
+++ b/spec/features/clusters/cluster_health_dashboard_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Cluster Health board', :js, :kubeclient, :use_clean_rails_memory_store_caching, :sidekiq_inline,
-feature_category: :kubernetes_management do
+feature_category: :deployment_management do
include KubernetesHelpers
include PrometheusHelpers
@@ -13,6 +13,8 @@ feature_category: :kubernetes_management do
let_it_be(:cluster_path) { project_cluster_path(clusterable, cluster) }
before do
+ stub_feature_flags(remove_monitor_metrics: false)
+
clusterable.add_maintainer(current_user)
sign_in(current_user)
@@ -28,6 +30,24 @@ feature_category: :kubernetes_management do
expect(page).to have_css('.cluster-health-graphs')
end
+ context 'feature remove_monitor_metrics enabled' do
+ before do
+ stub_feature_flags(remove_monitor_metrics: true)
+ end
+
+ it 'does not show the cluster health tab' do
+ visit cluster_path
+
+ expect(page).not_to have_text('Health')
+ end
+
+ it 'does not show the cluster health section' do
+ visit project_cluster_path(clusterable, cluster, { tab: 'health' })
+
+ expect(page).not_to have_text('you must first enable Prometheus in the Integrations tab')
+ end
+ end
+
context 'no prometheus available' do
it 'shows enable Prometheus message' do
visit cluster_path
diff --git a/spec/features/clusters/create_agent_spec.rb b/spec/features/clusters/create_agent_spec.rb
index 01902c36e99..93a49151978 100644
--- a/spec/features/clusters/create_agent_spec.rb
+++ b/spec/features/clusters/create_agent_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Cluster agent registration', :js, feature_category: :kubernetes_management do
+RSpec.describe 'Cluster agent registration', :js, feature_category: :deployment_management do
let_it_be(:project) { create(:project, :custom_repo, files: { '.gitlab/agents/example-agent-1/config.yaml' => '' }) }
let_it_be(:current_user) { create(:user, maintainer_projects: [project]) }
let_it_be(:token) { Devise.friendly_token }
diff --git a/spec/features/commit_spec.rb b/spec/features/commit_spec.rb
index a9672569a4a..dd96b763e55 100644
--- a/spec/features/commit_spec.rb
+++ b/spec/features/commit_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Commit', feature_category: :source_code_management do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
- describe "single commit view" do
+ shared_examples "single commit view" do
let(:commit) do
project.repository.commits(nil, limit: 100).find do |commit|
commit.diffs.size > 1
@@ -16,7 +16,6 @@ RSpec.describe 'Commit', feature_category: :source_code_management do
let(:files) { commit.diffs.diff_files.to_a }
before do
- stub_feature_flags(async_commit_diff_files: false)
project.add_maintainer(user)
sign_in(user)
end
@@ -28,15 +27,9 @@ RSpec.describe 'Commit', feature_category: :source_code_management do
visit project_commit_path(project, commit)
end
- it "shows the short commit message" do
+ it "shows the short commit message, number of total changes and stats", :js, :aggregate_failures do
expect(page).to have_content(commit.title)
- end
-
- it "reports the correct number of total changes" do
expect(page).to have_content("Changes #{commit.diffs.size}")
- end
-
- it 'renders diff stats', :js do
expect(page).to have_selector(".diff-stats")
end
@@ -50,23 +43,36 @@ RSpec.describe 'Commit', feature_category: :source_code_management do
visit project_commit_path(project, commit)
end
- it "shows an adjusted count for changed files on this page", :js do
- expect(page).to have_content("Showing 1 changed file")
+ def diff_files_on_page
+ page.all('.files .diff-file').pluck(:id)
end
- it "shows only the first diff on the first page" do
- expect(page).to have_selector(".files ##{files[0].file_hash}")
- expect(page).not_to have_selector(".files ##{files[1].file_hash}")
- end
+ it "shows paginated content and controls to navigate", :js, :aggregate_failures do
+ expect(page).to have_content("Showing 1 changed file")
+
+ wait_for_requests
+
+ expect(diff_files_on_page).to eq([files[0].file_hash])
- it "can navigate to the second page" do
within(".files .gl-pagination") do
click_on("2")
end
- expect(page).not_to have_selector(".files ##{files[0].file_hash}")
- expect(page).to have_selector(".files ##{files[1].file_hash}")
+ wait_for_requests
+
+ expect(diff_files_on_page).to eq([files[1].file_hash])
end
end
end
+
+ it_behaves_like "single commit view"
+
+ context "when super sidebar is enabled" do
+ before do
+ user.update!(use_new_navigation: true)
+ stub_feature_flags(super_sidebar_nav: true)
+ end
+
+ it_behaves_like "single commit view"
+ end
end
diff --git a/spec/features/commits/user_uses_quick_actions_spec.rb b/spec/features/commits/user_uses_quick_actions_spec.rb
index 6d043a0bb2f..c83a30c99c3 100644
--- a/spec/features/commits/user_uses_quick_actions_spec.rb
+++ b/spec/features/commits/user_uses_quick_actions_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Commit > User uses quick actions', :js, feature_category: :source_code_management do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
include RepoHelpers
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index eafe74f4b0b..c38ae0c2b0d 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -107,7 +107,7 @@ RSpec.describe 'Commits', feature_category: :source_code_management do
describe 'Cancel all builds' do
it 'cancels commit', :js, :sidekiq_might_not_need_inline do
visit pipeline_path(pipeline)
- click_on 'Cancel running'
+ click_on 'Cancel pipeline'
expect(page).to have_content 'canceled'
end
end
@@ -133,7 +133,7 @@ RSpec.describe 'Commits', feature_category: :source_code_management do
expect(page).to have_content pipeline.sha[0..7]
expect(page).to have_content pipeline.git_commit_message.gsub!(/\s+/, ' ')
expect(page).to have_content pipeline.user.name
- expect(page).not_to have_link('Cancel running')
+ expect(page).not_to have_link('Cancel pipeline')
expect(page).not_to have_link('Retry')
end
@@ -156,7 +156,7 @@ RSpec.describe 'Commits', feature_category: :source_code_management do
expect(page).to have_content pipeline.git_commit_message.gsub!(/\s+/, ' ')
expect(page).to have_content pipeline.user.name
- expect(page).not_to have_link('Cancel running')
+ expect(page).not_to have_link('Cancel pipeline')
expect(page).not_to have_link('Retry')
end
end
@@ -165,10 +165,24 @@ RSpec.describe 'Commits', feature_category: :source_code_management do
context 'viewing commits for a branch' do
let(:branch_name) { 'master' }
+ let(:ref_selector) { '.ref-selector' }
+ let(:ref_with_hash) { 'ref-#-hash' }
+
+ def switch_ref_to(ref_name)
+ first(ref_selector).click
+ wait_for_requests
+
+ page.within ref_selector do
+ fill_in 'Search by Git revision', with: ref_name
+ wait_for_requests
+ find('li', text: ref_name, match: :prefer_exact).click
+ end
+ end
before do
project.add_maintainer(user)
sign_in(user)
+ project.repository.create_branch(ref_with_hash, branch_name)
visit project_commits_path(project, branch_name)
end
@@ -180,11 +194,17 @@ RSpec.describe 'Commits', feature_category: :source_code_management do
end
end
+ it 'switches ref to ref containing a hash', :js do
+ switch_ref_to(ref_with_hash)
+
+ expect(page).to have_selector ref_selector, text: ref_with_hash
+ end
+
it 'shows the ref switcher with the multi-file editor enabled', :js do
set_cookie('new_repo', 'true')
visit project_commits_path(project, branch_name)
- expect(find('.ref-selector')).to have_content branch_name
+ expect(find(ref_selector)).to have_content branch_name
end
end
diff --git a/spec/features/contextual_sidebar_spec.rb b/spec/features/contextual_sidebar_spec.rb
index 2b671d4b3f1..132c8eb7192 100644
--- a/spec/features/contextual_sidebar_spec.rb
+++ b/spec/features/contextual_sidebar_spec.rb
@@ -39,74 +39,5 @@ RSpec.describe 'Contextual sidebar', :js, feature_category: :remote_development
expect(page).to have_selector('.is-showing-fly-out')
end
end
-
- context 'with invite_members_in_side_nav experiment', :experiment do
- it 'allows opening of modal for the candidate experience' do
- stub_experiments(invite_members_in_side_nav: :candidate)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: project.group)
- .on_next_instance
-
- visit project_path(project)
-
- page.within '[data-test-id="side-nav-invite-members"' do
- find('[data-test-id="invite-members-button"').click
- end
-
- expect(page).to have_content("You're inviting members to the")
- end
-
- it 'does not have invite members link in side nav for the control experience' do
- stub_experiments(invite_members_in_side_nav: :control)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: project.group)
- .on_next_instance
-
- visit project_path(project)
-
- expect(page).not_to have_css('[data-test-id="side-nav-invite-members"')
- end
- end
- end
-
- context 'when context is a group' do
- let_it_be(:user) { create(:user) }
- let_it_be(:group) do
- create(:group).tap do |g|
- g.add_owner(user)
- end
- end
-
- before do
- sign_in(user)
- end
-
- context 'with invite_members_in_side_nav experiment', :experiment do
- it 'allows opening of modal for the candidate experience' do
- stub_experiments(invite_members_in_side_nav: :candidate)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: group)
- .on_next_instance
-
- visit group_path(group)
-
- page.within '[data-test-id="side-nav-invite-members"' do
- find('[data-test-id="invite-members-button"').click
- end
-
- expect(page).to have_content("You're inviting members to the")
- end
-
- it 'does not have invite members link in side nav for the control experience' do
- stub_experiments(invite_members_in_side_nav: :control)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: group)
- .on_next_instance
-
- visit group_path(group)
-
- expect(page).not_to have_css('[data-test-id="side-nav-invite-members"')
- end
- end
end
end
diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb
index 55bf77d00b1..56272f58e0d 100644
--- a/spec/features/cycle_analytics_spec.rb
+++ b/spec/features/cycle_analytics_spec.rb
@@ -47,12 +47,12 @@ RSpec.describe 'Value Stream Analytics', :js, feature_category: :value_stream_ma
end
it 'displays metrics with relevant values' do
- expect(metrics_values).to eq(['-'] * 4)
+ expect(metrics_values).to eq(['-'] * 3)
end
it 'shows active stage with empty message' do
expect(page).to have_selector('.gl-path-active-item-indigo', text: 'Issue')
- expect(page).to have_content("We don't have enough data to show this stage.")
+ expect(page).to have_content("There are 0 items to show in this stage, for these filters, within this time range.")
end
end
@@ -98,7 +98,6 @@ RSpec.describe 'Value Stream Analytics', :js, feature_category: :value_stream_ma
aggregate_failures 'with relevant values' do
expect(metrics_tiles).to have_content('Commit')
expect(metrics_tiles).to have_content('Deploy')
- expect(metrics_tiles).to have_content('Deployment Frequency')
expect(metrics_tiles).to have_content('New Issue')
end
end
@@ -132,11 +131,11 @@ RSpec.describe 'Value Stream Analytics', :js, feature_category: :value_stream_ma
end
it 'can filter the metrics by date' do
- expect(metrics_values).to match_array(%w[21 2 1 0])
+ expect(metrics_values).to match_array(%w[21 2 1])
set_daterange(from, to)
- expect(metrics_values).to eq(['-'] * 4)
+ expect(metrics_values).to eq(['-'] * 3)
end
it 'can sort records', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338332' do
diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb
index 2f9b7bb7e0f..2345e4be722 100644
--- a/spec/features/dashboard/activity_spec.rb
+++ b/spec/features/dashboard/activity_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe 'Dashboard > Activity', feature_category: :user_profile do
sign_in(user)
end
- it_behaves_like 'a dashboard page with sidebar', :activity_dashboard_path, :activity
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :activity_dashboard_path, :activity
context 'tabs' do
it 'shows Your Activity' do
diff --git a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
index f5b02a87758..3040c97a16f 100644
--- a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
+++ b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'The group dashboard', :js, feature_category: :subgroups do
include ExternalAuthorizationServiceHelpers
- include Spec::Support::Helpers::Features::TopNavSpecHelpers
+ include Features::TopNavSpecHelpers
let(:user) { create(:user) }
@@ -21,9 +21,8 @@ RSpec.describe 'The group dashboard', :js, feature_category: :subgroups do
within_top_nav do
expect(page).to have_button('Projects')
expect(page).to have_button('Groups')
- expect(page).to have_link('Activity')
- expect(page).to have_link('Milestones')
- expect(page).to have_link('Snippets')
+ expect(page).to have_link('Your work')
+ expect(page).to have_link('Explore')
end
end
@@ -36,9 +35,8 @@ RSpec.describe 'The group dashboard', :js, feature_category: :subgroups do
within_top_nav do
expect(page).to have_button('Projects')
expect(page).to have_button('Groups')
- expect(page).not_to have_link('Activity')
- expect(page).not_to have_link('Milestones')
- expect(page).to have_link('Snippets')
+ expect(page).to have_link('Your work')
+ expect(page).to have_link('Explore')
end
end
end
diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb
index a45e0a58ed6..7112b30957a 100644
--- a/spec/features/dashboard/groups_list_spec.rb
+++ b/spec/features/dashboard/groups_list_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe 'Dashboard Groups page', :js, feature_category: :subgroups do
page.find("[data-testid='group-#{group.id}-dropdown-button'").click
end
- it_behaves_like 'a dashboard page with sidebar', :dashboard_groups_path, :groups
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_groups_path, :groups
it 'shows groups user is member of' do
group.add_owner(user)
@@ -230,4 +230,11 @@ RSpec.describe 'Dashboard Groups page', :js, feature_category: :subgroups do
expect(page).not_to have_content(another_group.name)
end
end
+
+ it 'links to the "Explore groups" page' do
+ sign_in(user)
+ visit dashboard_groups_path
+
+ expect(page).to have_link("Explore groups", href: explore_groups_path)
+ end
end
diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb
index 5dc59cfa841..5e6ec007569 100644
--- a/spec/features/dashboard/issuables_counter_spec.rb
+++ b/spec/features/dashboard/issuables_counter_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching,
sign_in(user)
end
- it 'reflects dashboard issues count' do
+ it 'reflects dashboard issues count', :js do
visit issues_path
expect_counters('issues', '1', n_("%d assigned issue", "%d assigned issues", 1) % 1)
diff --git a/spec/features/dashboard/issues_filter_spec.rb b/spec/features/dashboard/issues_filter_spec.rb
index a7734ed50c2..964ac2f714d 100644
--- a/spec/features/dashboard/issues_filter_spec.rb
+++ b/spec/features/dashboard/issues_filter_spec.rb
@@ -3,48 +3,60 @@
require 'spec_helper'
RSpec.describe 'Dashboard Issues filtering', :js, feature_category: :team_planning do
- include Spec::Support::Helpers::Features::SortingHelpers
+ include Features::SortingHelpers
include FilteredSearchHelpers
- let(:user) { create(:user) }
- let(:project) { create(:project) }
- let(:milestone) { create(:milestone, project: project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:milestone) { create(:milestone, project: project) }
- let!(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
- let!(:issue2) { create(:issue, project: project, author: user, assignees: [user], milestone: milestone) }
+ let_it_be(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
+ let_it_be(:issue2) { create(:issue, project: project, author: user, assignees: [user], milestone: milestone) }
+ let_it_be(:label) { create(:label, project: project, title: 'bug') }
+ let_it_be(:label_link) { create(:label_link, label: label, target: issue) }
+
+ let_it_be(:project2) { create(:project, namespace: user.namespace) }
+ let_it_be(:label2) { create(:label, title: 'bug') }
before do
+ project.labels << label
+ project2.labels << label2
project.add_maintainer(user)
sign_in(user)
-
- visit_issues
end
context 'without any filter' do
it 'shows error message' do
+ visit issues_dashboard_path
+
expect(page).to have_content 'Please select at least one filter to see results'
end
end
context 'filtering by milestone' do
it 'shows all issues with no milestone' do
- input_filtered_search("milestone:=none")
+ visit issues_dashboard_path
+
+ select_tokens 'Milestone', '=', 'None', submit: true
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_selector('.issue', count: 1)
end
it 'shows all issues with the selected milestone' do
- input_filtered_search("milestone:=%\"#{milestone.title}\"")
+ visit issues_dashboard_path
+
+ select_tokens 'Milestone', '=', milestone.title, submit: true
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_selector('.issue', count: 1)
end
it 'updates atom feed link' do
- visit_issues(milestone_title: '', assignee_username: user.username)
+ visit issues_dashboard_path(milestone_title: '', assignee_username: user.username)
+ click_button 'Actions'
- link = find('[data-testid="rss-feed-link"]')
+ link = find_link('Subscribe to RSS feed')
params = CGI.parse(URI.parse(link[:href]).query)
auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
@@ -59,40 +71,47 @@ RSpec.describe 'Dashboard Issues filtering', :js, feature_category: :team_planni
end
context 'filtering by label' do
- let(:label) { create(:label, project: project) }
- let!(:label_link) { create(:label_link, label: label, target: issue) }
+ before do
+ visit issues_dashboard_path
+ end
it 'shows all issues with the selected label' do
- input_filtered_search("label:=~#{label.title}")
+ select_tokens 'Label', '=', label.title, submit: true
- page.within 'ul.content-list' do
- expect(page).to have_content issue.title
- expect(page).not_to have_content issue2.title
- end
+ expect(page).to have_content issue.title
+ expect(page).not_to have_content issue2.title
+ end
+
+ it 'removes duplicate labels' do
+ select_tokens 'Label', '='
+ send_keys 'bu'
+
+ expect_suggestion('bug')
+ expect_suggestion_count(3) # Expect None, Any, and bug
end
end
context 'sorting' do
before do
- visit_issues(assignee_username: user.username)
+ visit issues_dashboard_path(assignee_username: user.username)
end
- it 'remembers last sorting value' do
- pajamas_sort_by(s_('SortOptions|Created date'))
- visit_issues(assignee_username: user.username)
+ it 'remembers last sorting value', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408749' do
+ click_button 'Created date'
+ click_button 'Updated date'
+
+ visit issues_dashboard_path(assignee_username: user.username)
- expect(page).to have_button('Created date')
+ expect(page).to have_button('Updated date')
end
it 'keeps sorting issues after visiting Projects Issues page' do
- pajamas_sort_by(s_('SortOptions|Created date'))
+ click_button 'Created date'
+ click_button 'Due date'
+
visit project_issues_path(project)
- expect(page).to have_button('Created date')
+ expect(page).to have_button('Due date')
end
end
-
- def visit_issues(...)
- visit issues_dashboard_path(...)
- end
end
diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb
index 654cc9978a7..70d9f7e5137 100644
--- a/spec/features/dashboard/issues_spec.rb
+++ b/spec/features/dashboard/issues_spec.rb
@@ -5,15 +5,15 @@ require 'spec_helper'
RSpec.describe 'Dashboard Issues', feature_category: :team_planning do
include FilteredSearchHelpers
- let(:current_user) { create :user }
- let(:user) { current_user } # Shared examples depend on this being available
- let!(:public_project) { create(:project, :public) }
- let(:project) { create(:project) }
- let(:project_with_issues_disabled) { create(:project, :issues_disabled) }
- let!(:authored_issue) { create :issue, author: current_user, project: project }
- let!(:authored_issue_on_public_project) { create :issue, author: current_user, project: public_project }
- let!(:assigned_issue) { create :issue, assignees: [current_user], project: project }
- let!(:other_issue) { create :issue, project: project }
+ let_it_be(:current_user) { create :user }
+ let_it_be(:user) { current_user } # Shared examples depend on this being available
+ let_it_be(:public_project) { create(:project, :public) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:project_with_issues_disabled) { create(:project, :issues_disabled) }
+ let_it_be(:authored_issue) { create :issue, author: current_user, project: project }
+ let_it_be(:authored_issue_on_public_project) { create :issue, author: current_user, project: public_project }
+ let_it_be(:assigned_issue) { create :issue, assignees: [current_user], project: project }
+ let_it_be(:other_issue) { create :issue, project: project }
before do
[project, project_with_issues_disabled].each { |project| project.add_maintainer(current_user) }
@@ -21,18 +21,18 @@ RSpec.describe 'Dashboard Issues', feature_category: :team_planning do
visit issues_dashboard_path(assignee_username: current_user.username)
end
- it_behaves_like 'a dashboard page with sidebar', :issues_dashboard_path, :issues
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :issues_dashboard_path, :issues
- describe 'issues' do
+ describe 'issues', :js do
it 'shows issues assigned to current user' do
expect(page).to have_content(assigned_issue.title)
expect(page).not_to have_content(authored_issue.title)
expect(page).not_to have_content(other_issue.title)
end
- it 'shows issues when current user is author', :js do
- reset_filters
- input_filtered_search("author:=#{current_user.to_reference}")
+ it 'shows issues when current user is author' do
+ click_button 'Clear'
+ select_tokens 'Author', '=', current_user.to_reference, submit: true
expect(page).to have_content(authored_issue.title)
expect(page).to have_content(authored_issue_on_public_project.title)
@@ -41,12 +41,21 @@ RSpec.describe 'Dashboard Issues', feature_category: :team_planning do
end
it 'state filter tabs work' do
- find('#state-closed').click
- expect(page).to have_current_path(issues_dashboard_url(assignee_username: current_user.username, state: 'closed'), url: true)
+ click_link 'Closed'
+
+ expect(page).not_to have_content(assigned_issue.title)
+ expect(page).not_to have_content(authored_issue.title)
+ expect(page).not_to have_content(other_issue.title)
end
- it_behaves_like "it has an RSS button with current_user's feed token"
- it_behaves_like "an autodiscoverable RSS feed with current_user's feed token"
+ describe 'RSS link' do
+ before do
+ click_button 'Actions'
+ end
+
+ it_behaves_like "it has an RSS link with current_user's feed token"
+ it_behaves_like "an autodiscoverable RSS feed with current_user's feed token"
+ end
end
describe 'new issue dropdown' do
diff --git a/spec/features/dashboard/label_filter_spec.rb b/spec/features/dashboard/label_filter_spec.rb
deleted file mode 100644
index f116c84ff40..00000000000
--- a/spec/features/dashboard/label_filter_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Dashboard > label filter', :js, feature_category: :team_planning do
- include FilteredSearchHelpers
-
- let(:filtered_search) { find('.filtered-search') }
- let(:filter_dropdown) { find("#js-dropdown-label .filter-dropdown") }
-
- let(:user) { create(:user) }
- let(:project) { create(:project, name: 'test', namespace: user.namespace) }
- let(:project2) { create(:project, name: 'test2', path: 'test2', namespace: user.namespace) }
- let(:label) { create(:label, title: 'bug', color: '#ff0000') }
- let(:label2) { create(:label, title: 'bug') }
-
- before do
- project.labels << label
- project2.labels << label2
-
- sign_in(user)
- visit issues_dashboard_path
-
- init_label_search
- end
-
- context 'duplicate labels' do
- it 'removes duplicate labels' do
- filtered_search.send_keys('bu')
-
- expect(filter_dropdown).to have_selector('.filter-dropdown-item', text: 'bug', count: 1)
- end
- end
-end
diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb
index 34bab9dffd0..d53f5affe64 100644
--- a/spec/features/dashboard/merge_requests_spec.rb
+++ b/spec/features/dashboard/merge_requests_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Dashboard Merge Requests', feature_category: :code_review_workflow do
- include Spec::Support::Helpers::Features::SortingHelpers
+ include Features::SortingHelpers
include FilteredSearchHelpers
include ProjectForksHelper
@@ -19,7 +19,7 @@ RSpec.describe 'Dashboard Merge Requests', feature_category: :code_review_workfl
sign_in(current_user)
end
- it_behaves_like 'a dashboard page with sidebar', :merge_requests_dashboard_path, :merge_requests
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :merge_requests_dashboard_path, :merge_requests
it 'disables target branch filter' do
visit merge_requests_dashboard_path
diff --git a/spec/features/dashboard/milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb
index 3b197bbf009..0dd25ffaa94 100644
--- a/spec/features/dashboard/milestones_spec.rb
+++ b/spec/features/dashboard/milestones_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe 'Dashboard > Milestones', feature_category: :team_planning do
visit dashboard_milestones_path
end
- it_behaves_like 'a dashboard page with sidebar', :dashboard_milestones_path, :milestones
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_milestones_path, :milestones
it 'sees milestones' do
expect(page).to have_current_path dashboard_milestones_path, ignore_query: true
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 779fbb48ddb..32bce32ec6c 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Dashboard Projects', feature_category: :projects do
let_it_be(:user) { create(:user) }
- let_it_be(:project, reload: true) { create(:project, :repository) }
+ let_it_be(:project, reload: true) { create(:project, :repository, creator: build(:user)) } # ensure creator != owner to avoid N+1 false-positive
let_it_be(:project2) { create(:project, :public) }
before do
@@ -18,7 +18,13 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do
end
end
- it_behaves_like "a dashboard page with sidebar", :dashboard_projects_path, :projects
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_projects_path, :projects
+
+ it 'links to the "Explore projects" page' do
+ visit dashboard_projects_path
+
+ expect(page).to have_link("Explore projects", href: explore_projects_path)
+ end
context 'when user has access to the project' do
it 'shows role badge' do
@@ -106,6 +112,8 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do
end
context 'when on Starred projects tab', :js do
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :starred_dashboard_projects_path, :projects
+
it 'shows the empty state when there are no starred projects' do
visit(starred_dashboard_projects_path)
@@ -239,7 +247,7 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do
create(:ci_pipeline, :with_job, status: :success, project: project, ref: project.default_branch, sha: project.commit.sha)
visit dashboard_projects_path
- control_count = ActiveRecord::QueryRecorder.new { visit dashboard_projects_path }.count
+ control = ActiveRecord::QueryRecorder.new { visit dashboard_projects_path }
new_project = create(:project, :repository, name: 'new project')
create(:ci_pipeline, :with_job, status: :success, project: new_project, ref: new_project.commit.sha)
@@ -247,15 +255,11 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do
ActiveRecord::QueryRecorder.new { visit dashboard_projects_path }.count
- # There are seven known N+1 queries: https://gitlab.com/gitlab-org/gitlab/-/issues/214037
- # 1. Project#open_issues_count
- # 2. Project#open_merge_requests_count
- # 3. Project#forks_count
- # 4. ProjectsHelper#load_pipeline_status
- # 5. RendersMemberAccess#preload_max_member_access_for_collection
- # 6. User#max_member_access_for_project_ids
- # 7. Ci::CommitWithPipeline#last_pipeline
+ # There are a few known N+1 queries: https://gitlab.com/gitlab-org/gitlab/-/issues/214037
+ # - User#max_member_access_for_project_ids
+ # - ProjectsHelper#load_pipeline_status / Ci::CommitWithPipeline#last_pipeline
+ # - Ci::Pipeline#detailed_status
- expect { visit dashboard_projects_path }.not_to exceed_query_limit(control_count + 7)
+ expect { visit dashboard_projects_path }.not_to exceed_query_limit(control).with_threshold(4)
end
end
diff --git a/spec/features/dashboard/root_explore_spec.rb b/spec/features/dashboard/root_explore_spec.rb
index a232ebec68e..9e844f81a29 100644
--- a/spec/features/dashboard/root_explore_spec.rb
+++ b/spec/features/dashboard/root_explore_spec.rb
@@ -2,16 +2,12 @@
require 'spec_helper'
-RSpec.describe 'Root explore', feature_category: :not_owned do
+RSpec.describe 'Root explore', :saas, feature_category: :shared do
let_it_be(:public_project) { create(:project, :public) }
let_it_be(:archived_project) { create(:project, :archived) }
let_it_be(:internal_project) { create(:project, :internal) }
let_it_be(:private_project) { create(:project, :private) }
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
context 'when logged in' do
let_it_be(:user) { create(:user) }
diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb
index 30587756505..155f7e93961 100644
--- a/spec/features/dashboard/shortcuts_spec.rb
+++ b/spec/features/dashboard/shortcuts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Dashboard shortcuts', :js, feature_category: :not_owned do
+RSpec.describe 'Dashboard shortcuts', :js, feature_category: :shared do
context 'logged in' do
let(:user) { create(:user) }
let(:project) { create(:project) }
diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb
index ba40290d866..da985c6dc07 100644
--- a/spec/features/dashboard/snippets_spec.rb
+++ b/spec/features/dashboard/snippets_spec.rb
@@ -5,7 +5,14 @@ require 'spec_helper'
RSpec.describe 'Dashboard snippets', feature_category: :source_code_management do
let_it_be(:user) { create(:user) }
- it_behaves_like 'a dashboard page with sidebar', :dashboard_snippets_path, :snippets
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_snippets_path, :snippets
+
+ it 'links to the "Explore snippets" page' do
+ sign_in(user)
+ visit dashboard_snippets_path
+
+ expect(page).to have_link("Explore snippets", href: explore_snippets_path)
+ end
context 'when the project has snippets' do
let(:project) { create(:project, :public, creator: user) }
@@ -37,7 +44,8 @@ RSpec.describe 'Dashboard snippets', feature_category: :source_code_management d
element = page.find('.row.empty-state')
expect(element).to have_content("Code snippets")
- expect(element.find('.svg-content img.js-lazy-loaded')['src']).to have_content('illustrations/snippets_empty')
+ expect(element.find('.svg-content img.js-lazy-loaded')['src'])
+ .to have_content('illustrations/empty-state/empty-snippets-md')
end
it 'shows new snippet button in main content area' do
diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb
index 59bb1a452c9..d0003b69415 100644
--- a/spec/features/dashboard/todos/todos_spec.rb
+++ b/spec/features/dashboard/todos/todos_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'Dashboard Todos', feature_category: :team_planning do
project.add_developer(user)
end
- it_behaves_like 'a dashboard page with sidebar', :dashboard_todos_path, :todos
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_todos_path, :todos
context 'User does not have todos' do
before do
diff --git a/spec/features/display_system_header_and_footer_bar_spec.rb b/spec/features/display_system_header_and_footer_bar_spec.rb
index 22fd0987418..9b2bf0ef1fa 100644
--- a/spec/features/display_system_header_and_footer_bar_spec.rb
+++ b/spec/features/display_system_header_and_footer_bar_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Display system header and footer bar', feature_category: :not_owned do
+RSpec.describe 'Display system header and footer bar', feature_category: :shared do
let(:header_message) { "Foo" }
let(:footer_message) { "Bar" }
diff --git a/spec/features/emails/issues_spec.rb b/spec/features/emails/issues_spec.rb
new file mode 100644
index 00000000000..c425dad88aa
--- /dev/null
+++ b/spec/features/emails/issues_spec.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe "E-Mails > Issues", :js, feature_category: :team_planning do
+ let_it_be(:project) { create(:project_empty_repo, :public, name: 'Long Earth') }
+ let_it_be(:author) { create(:user, username: 'author', name: 'Sally Linsay') }
+ let_it_be(:current_user) { create(:user, username: 'current_user', name: 'Shi-mi') }
+
+ before do
+ project.add_developer(current_user)
+ sign_in(current_user)
+ end
+
+ describe 'assignees' do
+ let_it_be(:assignee) { create(:user, username: 'assignee', name: 'Joshua Valienté') }
+ let_it_be(:issue_without_assignee) { create(:issue, project: project, author: author, title: 'No milk today!') }
+
+ let_it_be(:issue_with_assignee) do
+ create(
+ :issue, project: project, author: author, assignees: [assignee],
+ title: 'All your base are belong to us')
+ end
+
+ it 'sends confirmation e-mail for assigning' do
+ synchronous_notifications
+ expect(Notify).to receive(:reassigned_issue_email)
+ .with(author.id, issue_without_assignee.id, [], current_user.id, nil)
+ .once
+ .and_call_original
+ expect(Notify).to receive(:reassigned_issue_email)
+ .with(assignee.id, issue_without_assignee.id, [], current_user.id, NotificationReason::ASSIGNED)
+ .once
+ .and_call_original
+
+ visit issue_path(issue_without_assignee)
+ assign_to(assignee)
+
+ expect(find('#notes-list')).to have_text("Shi-mi assigned to @assignee just now")
+ end
+
+ it 'sends confirmation e-mail for reassigning' do
+ synchronous_notifications
+ expect(Notify).to receive(:reassigned_issue_email)
+ .with(author.id, issue_with_assignee.id, [assignee.id], current_user.id, NotificationReason::ASSIGNED)
+ .once
+ .and_call_original
+ expect(Notify).to receive(:reassigned_issue_email)
+ .with(assignee.id, issue_with_assignee.id, [assignee.id], current_user.id, nil)
+ .once
+ .and_call_original
+
+ visit issue_path(issue_with_assignee)
+ assign_to(author)
+
+ expect(find('#notes-list')).to have_text("Shi-mi assigned to @author and unassigned @assignee just now")
+ end
+
+ it 'sends confirmation e-mail for unassigning' do
+ synchronous_notifications
+ expect(Notify).to receive(:reassigned_issue_email)
+ .with(author.id, issue_with_assignee.id, [assignee.id], current_user.id, nil)
+ .once
+ .and_call_original
+ expect(Notify).to receive(:reassigned_issue_email)
+ .with(assignee.id, issue_with_assignee.id, [assignee.id], current_user.id, nil)
+ .once
+ .and_call_original
+
+ visit issue_path(issue_with_assignee)
+ quick_action('/unassign')
+
+ expect(find('#notes-list')).to have_text("Shi-mi unassigned @assignee just now")
+ end
+ end
+
+ describe 'closing' do
+ let_it_be(:issue) { create(:issue, project: project, author: author, title: 'Public Holiday') }
+
+ it 'sends confirmation e-mail for closing' do
+ synchronous_notifications
+ expect(Notify).to receive(:closed_issue_email)
+ .with(author.id, issue.id, current_user.id, { closed_via: nil, reason: nil })
+ .once
+ .and_call_original
+
+ visit issue_path(issue)
+ quick_action("/close")
+
+ expect(find('#notes-list')).to have_text("Shi-mi closed just now")
+ end
+ end
+
+ private
+
+ def assign_to(user)
+ quick_action("/assign @#{user.username}")
+ end
+
+ def quick_action(command)
+ fill_in 'note[note]', with: command
+ click_button 'Comment'
+ end
+
+ def synchronous_notifications
+ expect_next_instance_of(NotificationService) do |service|
+ expect(service).to receive(:async).and_return(service)
+ end
+ end
+end
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index 1f09b01ddec..43dd80187ce 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -19,6 +19,8 @@ RSpec.describe 'Expand and collapse diffs', :js, feature_category: :source_code_
# Ensure that undiffable.md is in .gitattributes
project.repository.copy_gitattributes(branch)
visit project_commit_path(project, project.commit(branch))
+
+ wait_for_requests
end
def file_container(filename)
@@ -222,10 +224,16 @@ RSpec.describe 'Expand and collapse diffs', :js, feature_category: :source_code_
let(:branch) { 'expand-collapse-files' }
# safe-files -> 100 | safe-lines -> 5000 | commit-files -> 105
- it 'does collapsing from the safe number of files to the end on small files' do
- expect(page).to have_link('Expand all')
+ it 'does collapsing from the safe number of files to the end on small files', :aggregate_failures do
+ expect(page).not_to have_link('Expand all')
+ expect(page).to have_selector('.diff-content', count: 20)
+ expect(page).to have_selector('.diff-collapsed', count: 0)
- expect(page).to have_selector('.diff-content', count: 105)
+ visit project_commit_path(project, project.commit(branch), page: 6)
+ wait_for_requests
+
+ expect(page).to have_link('Expand all')
+ expect(page).to have_selector('.diff-content', count: 5)
expect(page).to have_selector('.diff-collapsed', count: 5)
%w(file-95.txt file-96.txt file-97.txt file-98.txt file-99.txt).each do |filename|
diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb
index 458f83dffb4..57a7e8ea523 100644
--- a/spec/features/explore/groups_spec.rb
+++ b/spec/features/explore/groups_spec.rb
@@ -29,8 +29,8 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do
shared_examples 'renders public and internal projects' do
it do
visit_page
- expect(page).to have_content(public_project.name)
- expect(page).to have_content(internal_project.name)
+ expect(page).to have_content(public_project.name).or(have_content(public_project.path))
+ expect(page).to have_content(internal_project.name).or(have_content(internal_project.path))
expect(page).not_to have_content(private_project.name)
end
end
@@ -38,7 +38,7 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do
shared_examples 'renders only public project' do
it do
visit_page
- expect(page).to have_content(public_project.name)
+ expect(page).to have_content(public_project.name).or(have_content(public_project.path))
expect(page).not_to have_content(internal_project.name)
expect(page).not_to have_content(private_project.name)
end
@@ -47,7 +47,7 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do
shared_examples 'renders group in public groups area' do
it do
visit explore_groups_path
- expect(page).to have_content(group.name)
+ expect(page).to have_content(group.path)
end
end
@@ -56,32 +56,44 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do
sign_in(user)
end
- it_behaves_like 'renders public and internal projects' do
- subject(:visit_page) { visit group_path(group) }
+ context 'for group_path' do
+ it_behaves_like 'renders public and internal projects' do
+ subject(:visit_page) { visit group_path(group) }
+ end
end
- it_behaves_like 'renders public and internal projects' do
- subject(:visit_page) { visit issues_group_path(group) }
+ context 'for issues_group_path' do
+ it_behaves_like 'renders public and internal projects' do
+ subject(:visit_page) { visit issues_group_path(group) }
+ end
end
- it_behaves_like 'renders public and internal projects' do
- subject(:visit_page) { visit merge_requests_group_path(group) }
+ context 'for merge_requests_group_path' do
+ it_behaves_like 'renders public and internal projects' do
+ subject(:visit_page) { visit merge_requests_group_path(group) }
+ end
end
it_behaves_like 'renders group in public groups area'
end
context 'when signed out' do
- it_behaves_like 'renders only public project' do
- subject(:visit_page) { visit group_path(group) }
+ context 'for group_path' do
+ it_behaves_like 'renders only public project' do
+ subject(:visit_page) { visit group_path(group) }
+ end
end
- it_behaves_like 'renders only public project' do
- subject(:visit_page) { visit issues_group_path(group) }
+ context 'for issues_group_path' do
+ it_behaves_like 'renders only public project' do
+ subject(:visit_page) { visit issues_group_path(group) }
+ end
end
- it_behaves_like 'renders only public project' do
- subject(:visit_page) { visit merge_requests_group_path(group) }
+ context 'for merge_requests_group_path' do
+ it_behaves_like 'renders only public project' do
+ subject(:visit_page) { visit merge_requests_group_path(group) }
+ end
end
it_behaves_like 'renders group in public groups area'
diff --git a/spec/features/explore/navbar_spec.rb b/spec/features/explore/navbar_spec.rb
new file mode 100644
index 00000000000..8f281abe6a7
--- /dev/null
+++ b/spec/features/explore/navbar_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe '"Explore" navbar', feature_category: :navigation do
+ include_context '"Explore" navbar structure'
+
+ it_behaves_like 'verified navigation bar' do
+ before do
+ visit explore_projects_path
+ end
+ end
+end
diff --git a/spec/features/explore/user_explores_projects_spec.rb b/spec/features/explore/user_explores_projects_spec.rb
index 14fddf5d84c..f259ba6a167 100644
--- a/spec/features/explore/user_explores_projects_spec.rb
+++ b/spec/features/explore/user_explores_projects_spec.rb
@@ -3,6 +3,18 @@
require 'spec_helper'
RSpec.describe 'User explores projects', feature_category: :user_profile do
+ describe '"All" tab' do
+ it_behaves_like 'an "Explore" page with sidebar and breadcrumbs', :explore_projects_path, :projects
+ end
+
+ describe '"Most starred" tab' do
+ it_behaves_like 'an "Explore" page with sidebar and breadcrumbs', :starred_explore_projects_path, :projects
+ end
+
+ describe '"Trending" tab' do
+ it_behaves_like 'an "Explore" page with sidebar and breadcrumbs', :trending_explore_projects_path, :projects
+ end
+
context 'when some projects exist' do
let_it_be(:archived_project) { create(:project, :archived) }
let_it_be(:internal_project) { create(:project, :internal) }
diff --git a/spec/features/file_uploads/project_import_spec.rb b/spec/features/file_uploads/project_import_spec.rb
index c261834206d..3934e0319ad 100644
--- a/spec/features/file_uploads/project_import_spec.rb
+++ b/spec/features/file_uploads/project_import_spec.rb
@@ -22,6 +22,10 @@ RSpec.describe 'Upload a project export archive', :api, :js, feature_category: :
)
end
+ before do
+ stub_application_setting(import_sources: ['gitlab_project'])
+ end
+
RSpec.shared_examples 'for a project export archive' do
it { expect { subject }.to change { Project.count }.by(1) }
diff --git a/spec/features/frequently_visited_projects_and_groups_spec.rb b/spec/features/frequently_visited_projects_and_groups_spec.rb
index 50e20910e16..514b642a2d4 100644
--- a/spec/features/frequently_visited_projects_and_groups_spec.rb
+++ b/spec/features/frequently_visited_projects_and_groups_spec.rb
@@ -2,8 +2,8 @@
require 'spec_helper'
-RSpec.describe 'Frequently visited items', :js, feature_category: :not_owned do
- include Spec::Support::Helpers::Features::TopNavSpecHelpers
+RSpec.describe 'Frequently visited items', :js, feature_category: :shared do
+ include Features::TopNavSpecHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb
index 15393ec4cd6..f94f0288f99 100644
--- a/spec/features/global_search_spec.rb
+++ b/spec/features/global_search_spec.rb
@@ -13,64 +13,8 @@ RSpec.describe 'Global search', :js, feature_category: :global_search do
sign_in(user)
end
- describe 'when new_header_search feature is disabled' do
+ describe 'when header search' do
before do
- # TODO: Remove this along with feature flag #339348
- stub_feature_flags(new_header_search: false)
- visit dashboard_projects_path
- end
-
- it 'increases usage ping searches counter' do
- expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:count).with(:navbar_searches)
- expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:count).with(:all_searches)
-
- submit_search('foobar')
- end
-
- describe 'I search through the issues and I see pagination' do
- before do
- allow_next(SearchService).to receive(:per_page).and_return(1)
- create_list(:issue, 2, project: project, title: 'initial')
- end
-
- it "has a pagination" do
- submit_search('initial')
- select_search_scope('Issues')
-
- expect(page).to have_selector('.gl-pagination .next')
- end
- end
-
- it 'closes the dropdown on blur' do
- find('#search').click
- fill_in 'search', with: "a"
-
- expect(page).to have_selector("div[data-testid='dashboard-search-options'].show")
-
- find('#search').send_keys(:backspace)
- find('body').click
-
- expect(page).to have_no_selector("div[data-testid='dashboard-search-options'].show")
- end
-
- it 'renders legacy search bar' do
- expect(page).to have_selector('.search-form')
- expect(page).to have_no_selector('#js-header-search')
- end
-
- it 'focuses search input when shortcut "s" is pressed' do
- expect(page).not_to have_selector('#search:focus')
-
- find('body').native.send_key('s')
-
- expect(page).to have_selector('#search:focus')
- end
- end
-
- describe 'when new_header_search feature is enabled' do
- before do
- # TODO: Remove this along with feature flag #339348
- stub_feature_flags(new_header_search: true)
visit dashboard_projects_path
end
diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb
index 117f50aefc6..3e87c90e7dc 100644
--- a/spec/features/group_variables_spec.rb
+++ b/spec/features/group_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Group variables', :js, feature_category: :pipeline_authoring do
+RSpec.describe 'Group variables', :js, feature_category: :secrets_management do
let(:user) { create(:user) }
let(:group) { create(:group) }
let!(:variable) { create(:ci_group_variable, key: 'test_key', value: 'test_value', masked: true, group: group) }
@@ -15,5 +15,16 @@ RSpec.describe 'Group variables', :js, feature_category: :pipeline_authoring do
wait_for_requests
end
- it_behaves_like 'variable list'
+ context 'when ci_variables_pages FF is enabled' do
+ it_behaves_like 'variable list'
+ it_behaves_like 'variable list pagination', :ci_group_variable
+ end
+
+ context 'when ci_variables_pages FF is disabled' do
+ before do
+ stub_feature_flags(ci_variables_pages: false)
+ end
+
+ it_behaves_like 'variable list'
+ end
end
diff --git a/spec/features/groups/board_spec.rb b/spec/features/groups/board_spec.rb
index c451a97bed5..8acf3ffe441 100644
--- a/spec/features/groups/board_spec.rb
+++ b/spec/features/groups/board_spec.rb
@@ -25,8 +25,10 @@ RSpec.describe 'Group Boards', feature_category: :team_planning do
it 'adds an issue to the backlog' do
page.within(find('.board', match: :first)) do
- issue_title = 'New Issue'
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ issue_title = 'Create new issue'
+ click_button issue_title
wait_for_requests
diff --git a/spec/features/groups/container_registry_spec.rb b/spec/features/groups/container_registry_spec.rb
index 11f94967aaf..ab8d8238bdc 100644
--- a/spec/features/groups/container_registry_spec.rb
+++ b/spec/features/groups/container_registry_spec.rb
@@ -95,7 +95,11 @@ RSpec.describe 'Container Registry', :js, feature_category: :container_registry
first('[data-testid="additional-actions"]').click
first('[data-testid="single-delete-button"]').click
expect(find('.modal .modal-title')).to have_content _('Remove tag')
+ stub_container_registry_tags(repository: %r{my/image}, tags: [], with_manifest: true)
find('.modal .modal-footer .btn-danger').click
+
+ expect(page).to have_content '0 tags'
+ expect(page).not_to have_content '1 tag'
end
end
end
diff --git a/spec/features/groups/crm/contacts/create_spec.rb b/spec/features/groups/crm/contacts/create_spec.rb
index 860cadd322d..aa05ef82a8b 100644
--- a/spec/features/groups/crm/contacts/create_spec.rb
+++ b/spec/features/groups/crm/contacts/create_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Create a CRM contact', :js, feature_category: :service_desk do
let(:user) { create(:user) }
let(:group) { create(:group, :crm_enabled) }
- let!(:organization) { create(:organization, group: group, name: 'GitLab') }
+ let!(:crm_organization) { create(:crm_organization, group: group, name: 'GitLab') }
before do
group.add_owner(user)
diff --git a/spec/features/groups/dependency_proxy_spec.rb b/spec/features/groups/dependency_proxy_spec.rb
index 05984d40ea6..60922f813df 100644
--- a/spec/features/groups/dependency_proxy_spec.rb
+++ b/spec/features/groups/dependency_proxy_spec.rb
@@ -52,6 +52,12 @@ RSpec.describe 'Group Dependency Proxy', feature_category: :dependency_proxy do
expect(find('input[data-testid="proxy-url"]').value).to have_content('/dependency_proxy/containers')
end
+ it 'has link to settings' do
+ visit path
+
+ expect(page).to have_link s_('DependencyProxy|Configure in settings')
+ end
+
it 'hides the proxy URL when feature is disabled' do
visit settings_path
wait_for_requests
@@ -80,6 +86,10 @@ RSpec.describe 'Group Dependency Proxy', feature_category: :dependency_proxy do
it 'does not show the feature toggle but shows the proxy URL' do
expect(find('input[data-testid="proxy-url"]').value).to have_content('/dependency_proxy/containers')
end
+
+ it 'does not have link to settings' do
+ expect(page).not_to have_link s_('DependencyProxy|Configure in settings')
+ end
end
end
diff --git a/spec/features/groups/group_runners_spec.rb b/spec/features/groups/group_runners_spec.rb
index ae757e04716..514110d78ae 100644
--- a/spec/features/groups/group_runners_spec.rb
+++ b/spec/features/groups/group_runners_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe "Group Runners", feature_category: :runner_fleet do
- include Spec::Support::Helpers::Features::RunnersHelpers
+ include Features::RunnersHelpers
include Spec::Support::Helpers::ModalHelpers
let_it_be(:group_owner) { create(:user) }
@@ -16,10 +16,12 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do
end
describe "Group runners page", :js do
- let!(:group_registration_token) { group.runners_token }
+ describe "legacy runners registration" do
+ let_it_be(:group_registration_token) { group.runners_token }
- describe "runners registration" do
before do
+ stub_feature_flags(create_runner_workflow_for_namespace: false)
+
visit group_runners_path(group)
end
@@ -60,15 +62,11 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do
let(:runner) { group_runner }
end
- it 'shows a group badge' do
- within_runner_row(group_runner.id) do
- expect(page).to have_selector '.badge', text: s_('Runners|Group')
- end
- end
-
- it 'can edit runner information' do
+ it 'shows an editable group badge' do
within_runner_row(group_runner.id) do
expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, group_runner))
+
+ expect(page).to have_selector '.badge', text: s_('Runners|Group')
end
end
@@ -102,15 +100,11 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do
let(:runner) { project_runner }
end
- it 'shows a project badge' do
- within_runner_row(project_runner.id) do
- expect(page).to have_selector '.badge', text: s_('Runners|Project')
- end
- end
-
- it 'can edit runner information' do
+ it 'shows an editable project runner' do
within_runner_row(project_runner.id) do
expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, project_runner))
+
+ expect(page).to have_selector '.badge', text: s_('Runners|Project')
end
end
end
@@ -202,6 +196,16 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do
end
end
+ describe "Group runner create page", :js do
+ before do
+ visit new_group_runner_path(group)
+ end
+
+ it_behaves_like 'creates runner and shows register page' do
+ let(:register_path_pattern) { register_group_runner_path(group, '.*') }
+ end
+ end
+
describe "Group runner show page", :js do
let_it_be(:group_runner) do
create(:ci_runner, :group, groups: [group], description: 'runner-foo')
diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb
index 5510e73ef0f..6443f4a6c38 100644
--- a/spec/features/groups/group_settings_spec.rb
+++ b/spec/features/groups/group_settings_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Edit group settings', feature_category: :subgroups do
+ include Spec::Support::Helpers::ModalHelpers
+
let(:user) { create(:user) }
let(:group) { create(:group, path: 'foo') }
@@ -72,7 +74,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
visit new_project_full_path
expect(page).to have_current_path(new_project_full_path, ignore_query: true)
- expect(find('.breadcrumbs')).to have_content(project.path)
+ expect(find('.breadcrumbs')).to have_content(project.name)
end
it 'the old project path redirects to the new path' do
@@ -80,7 +82,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
visit old_project_full_path
expect(page).to have_current_path(new_project_full_path, ignore_query: true)
- expect(find('.breadcrumbs')).to have_content(project.path)
+ expect(find('.breadcrumbs')).to have_content(project.name)
end
end
end
@@ -147,14 +149,16 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
selected_group.add_owner(user)
end
- it 'can successfully transfer the group', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/384966' do
+ it 'can successfully transfer the group' do
+ selected_group_path = selected_group.path
+
visit edit_group_path(selected_group)
page.within('[data-testid="transfer-locations-dropdown"]') do
click_button _('Select parent group')
- fill_in _('Search'), with: target_group_name
+ fill_in _('Search'), with: target_group&.name || ''
wait_for_requests
- click_button target_group_name
+ click_button(target_group&.name || 'No parent group')
end
click_button s_('GroupSettings|Transfer group')
@@ -166,8 +170,16 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
click_button 'Confirm'
end
- expect(page).to have_text "Group '#{selected_group.name}' was successfully transferred."
- expect(current_url).to include(selected_group.reload.full_path)
+ within('[data-testid="breadcrumb-links"]') do
+ expect(page).to have_content(target_group.name) if target_group
+ expect(page).to have_content(selected_group.name)
+ end
+
+ if target_group
+ expect(current_url).to include("#{target_group.path}/#{selected_group_path}")
+ else
+ expect(current_url).to include(selected_group_path)
+ end
end
end
@@ -175,14 +187,13 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
let(:selected_group) { create(:group, path: 'foo-subgroup', parent: group) }
context 'when transfering to no parent group' do
- let(:target_group_name) { 'No parent group' }
+ let(:target_group) { nil }
it_behaves_like 'can transfer the group'
end
context 'when transfering to a parent group' do
let(:target_group) { create(:group, path: 'foo-parentgroup') }
- let(:target_group_name) { target_group.name }
before do
target_group.add_owner(user)
@@ -194,7 +205,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
context 'when transfering from a root group to a parent group' do
let(:selected_group) { create(:group, path: 'foo-rootgroup') }
- let(:target_group_name) { group.name }
+ let(:target_group) { group }
it_behaves_like 'can transfer the group'
end
@@ -235,6 +246,67 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
end
end
+ describe 'group README', :js do
+ let_it_be(:group) { create(:group) }
+
+ context 'with gitlab-profile project and README.md' do
+ let_it_be(:project) { create(:project, :readme, namespace: group) }
+
+ it 'renders link to Group README and navigates to it on click' do
+ visit edit_group_path(group)
+ wait_for_requests
+
+ click_link('README')
+ wait_for_requests
+
+ expect(page).to have_current_path(project_blob_path(project, "#{project.default_branch}/README.md"))
+ expect(page).to have_text('README.md')
+ end
+ end
+
+ context 'with gitlab-profile project and no README.md' do
+ let_it_be(:project) { create(:project, path: 'gitlab-profile', namespace: group) }
+
+ it 'renders Add README button and allows user to create a README via the IDE' do
+ visit edit_group_path(group)
+ wait_for_requests
+
+ expect(page).not_to have_selector('.ide')
+
+ click_button('Add README')
+
+ accept_gl_confirm("This will create a README.md for project #{group.readme_project.present.path_with_namespace}.", button_text: 'Add README')
+ wait_for_requests
+
+ expect(page).to have_current_path("/-/ide/project/#{group.readme_project.present.path_with_namespace}/edit/main/-/README.md/")
+
+ page.within('.ide') do
+ expect(page).to have_text('README.md')
+ end
+ end
+ end
+
+ context 'with no gitlab-profile project and no README.md' do
+ it 'renders Add README button and allows user to create both the gitlab-profile project and README via the IDE' do
+ visit edit_group_path(group)
+ wait_for_requests
+
+ expect(page).not_to have_selector('.ide')
+
+ click_button('Add README')
+
+ accept_gl_confirm("This will create a project #{group.full_path}/gitlab-profile and add a README.md.", button_text: 'Create and add README')
+ wait_for_requests
+
+ expect(page).to have_current_path("/-/ide/project/#{group.full_path}/gitlab-profile/edit/main/-/README.md/")
+
+ page.within('.ide') do
+ expect(page).to have_text('README.md')
+ end
+ end
+ end
+ end
+
def update_path(new_group_path)
visit edit_group_path(group)
diff --git a/spec/features/groups/import_export/connect_instance_spec.rb b/spec/features/groups/import_export/connect_instance_spec.rb
index 8aea18a268b..f6548c035f0 100644
--- a/spec/features/groups/import_export/connect_instance_spec.rb
+++ b/spec/features/groups/import_export/connect_instance_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe 'Import/Export - Connect to another instance', :js, feature_categ
pat = 'demo-pat'
expect(page).to have_content 'Import groups by direct transfer'
- expect(page).to have_content 'Not all related objects are migrated'
+ expect(page).to have_content 'Not all group items are migrated'
fill_in :bulk_import_gitlab_url, with: source_url
fill_in :bulk_import_gitlab_access_token, with: pat
diff --git a/spec/features/groups/integrations/group_integrations_spec.rb b/spec/features/groups/integrations/group_integrations_spec.rb
index 0d65fa5964b..8cddda91e89 100644
--- a/spec/features/groups/integrations/group_integrations_spec.rb
+++ b/spec/features/groups/integrations/group_integrations_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe 'Group integrations', :js do
include_context 'group integration activation'
+ before do
+ stub_feature_flags(remove_monitor_metrics: false)
+ end
+
it_behaves_like 'integration settings form' do
let(:integrations) { Integration.find_or_initialize_all_non_project_specific(Integration.for_group(group)) }
@@ -12,4 +16,16 @@ RSpec.describe 'Group integrations', :js do
visit_group_integration(integration.title)
end
end
+
+ context 'with remove_monitor_metrics flag enabled' do
+ before do
+ stub_feature_flags(remove_monitor_metrics: true)
+ end
+
+ it 'returns a 404 for the prometheus edit page' do
+ visit edit_group_settings_integration_path(group, :prometheus)
+
+ expect(page).to have_content "Page Not Found"
+ end
+ end
end
diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb
index 00c0d4c3ebe..6d0d768d356 100644
--- a/spec/features/groups/issues_spec.rb
+++ b/spec/features/groups/issues_spec.rb
@@ -23,6 +23,10 @@ RSpec.describe 'Group issues page', feature_category: :subgroups do
context 'rss feed' do
let(:access_level) { ProjectFeature::ENABLED }
+ before do
+ click_button 'Actions'
+ end
+
context 'when signed in' do
let(:user) do
user_in_group.ensure_feed_token
@@ -30,29 +34,15 @@ RSpec.describe 'Group issues page', feature_category: :subgroups do
user_in_group
end
+ it_behaves_like "it has an RSS link with current_user's feed token"
it_behaves_like "an autodiscoverable RSS feed with current_user's feed token"
-
- # Note: The one from rss_shared_example.rb uses a css pseudo-class `:has`
- # which is VERY experimental and only supported in Nokogiri used by Capybara
- # However,`:js` option forces Capybara to use Selenium that doesn't support`:has`
- context "it has an RSS button with current_user's feed token" do
- it "shows the RSS button with current_user's feed token" do
- expect(page).to have_link 'Subscribe to RSS feed', href: /feed_token=#{user.feed_token}/
- end
- end
end
context 'when signed out' do
let(:user) { nil }
+ it_behaves_like "it has an RSS link without a feed token"
it_behaves_like "an autodiscoverable RSS feed without a feed token"
-
- # Note: please see the above
- context "it has an RSS button without a feed token" do
- it "shows the RSS button without a feed token" do
- expect(page).not_to have_link 'Subscribe to RSS feed', href: /feed_token/
- end
- end
end
end
diff --git a/spec/features/groups/labels/index_spec.rb b/spec/features/groups/labels/index_spec.rb
index ea27fa2c5d9..7b0a38a83db 100644
--- a/spec/features/groups/labels/index_spec.rb
+++ b/spec/features/groups/labels/index_spec.rb
@@ -24,6 +24,7 @@ RSpec.describe 'Group labels', feature_category: :team_planning do
end
it 'shows an edit label button', :js do
- expect(page).to have_selector('.edit')
+ click_button 'Label actions dropdown'
+ expect(page).to have_link('Edit')
end
end
diff --git a/spec/features/groups/members/filter_members_spec.rb b/spec/features/groups/members/filter_members_spec.rb
index dc33bb11bea..c2ec709576b 100644
--- a/spec/features/groups/members/filter_members_spec.rb
+++ b/spec/features/groups/members/filter_members_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Filter members', :js, feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
let(:user) { create(:user) }
let(:nested_group_user) { create(:user) }
diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb
index cfb1b24bccb..e1c2d8c0547 100644
--- a/spec/features/groups/members/leave_group_spec.rb
+++ b/spec/features/groups/members/leave_group_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Leave group', feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
include Spec::Support::Helpers::ModalHelpers
let(:user) { create(:user) }
diff --git a/spec/features/groups/members/list_members_spec.rb b/spec/features/groups/members/list_members_spec.rb
index 1aea5a76b41..6e20f92c16b 100644
--- a/spec/features/groups/members/list_members_spec.rb
+++ b/spec/features/groups/members/list_members_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > List members', :js, feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
let(:user1) { create(:user, name: 'John Doe') }
let(:user2) { create(:user, name: 'Mary Jane') }
diff --git a/spec/features/groups/members/manage_groups_spec.rb b/spec/features/groups/members/manage_groups_spec.rb
index ee8786a2e36..f9c11dd0183 100644
--- a/spec/features/groups/members/manage_groups_spec.rb
+++ b/spec/features/groups/members/manage_groups_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Manage groups', :js, feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::MembersHelpers
+ include Features::InviteMembersModalHelpers
include Spec::Support::Helpers::ModalHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb
index 5cd5908b359..2d5a3dbb8f8 100644
--- a/spec/features/groups/members/manage_members_spec.rb
+++ b/spec/features/groups/members/manage_members_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Manage members', feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::MembersHelpers
+ include Features::InviteMembersModalHelpers
include Spec::Support::Helpers::ModalHelpers
let_it_be(:user1) { create(:user, name: 'John Doe') }
diff --git a/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb
index e9f80b05fa7..4f56c807ec8 100644
--- a/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb
+++ b/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Owner adds member with expiration date', :js, feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::MembersHelpers
+ include Features::InviteMembersModalHelpers
let_it_be(:user1) { create(:user, name: 'John Doe') }
let_it_be(:group) { create(:group) }
diff --git a/spec/features/groups/members/search_members_spec.rb b/spec/features/groups/members/search_members_spec.rb
index 6b2896b194c..80de1cabd1e 100644
--- a/spec/features/groups/members/search_members_spec.rb
+++ b/spec/features/groups/members/search_members_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Search group member', :js, feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
let(:user) { create :user }
let(:member) { create :user }
diff --git a/spec/features/groups/members/sort_members_spec.rb b/spec/features/groups/members/sort_members_spec.rb
index 5634122ec16..d2e5445deae 100644
--- a/spec/features/groups/members/sort_members_spec.rb
+++ b/spec/features/groups/members/sort_members_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Sort members', :js, feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
let(:owner) { create(:user, name: 'John Doe', created_at: 5.days.ago, last_activity_on: Date.today) }
let(:developer) { create(:user, name: 'Mary Jane', created_at: 1.day.ago, last_sign_in_at: 5.days.ago, last_activity_on: Date.today - 5) }
@@ -18,7 +18,7 @@ RSpec.describe 'Groups > Members > Sort members', :js, feature_category: :subgro
def expect_sort_by(text, sort_direction)
within('[data-testid="members-sort-dropdown"]') do
- expect(page).to have_css('button[aria-haspopup="true"]', text: text)
+ expect(page).to have_css('button[aria-haspopup="menu"]', text: text)
expect(page).to have_button("Sorting Direction: #{sort_direction == :asc ? 'Ascending' : 'Descending'}")
end
end
diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb
index a70a1e2e70b..376e1e6063f 100644
--- a/spec/features/groups/milestone_spec.rb
+++ b/spec/features/groups/milestone_spec.rb
@@ -25,17 +25,17 @@ RSpec.describe 'Group milestones', feature_category: :subgroups do
description.native.send_keys('')
- click_button('Preview')
+ click_button("Preview")
preview = find('.js-md-preview')
expect(preview).to have_content('Nothing to preview.')
- click_button('Write')
+ click_button("Continue editing")
description.native.send_keys(':+1: Nice')
- click_button('Preview')
+ click_button("Preview")
expect(preview).to have_css('gl-emoji')
expect(find('#milestone_description', visible: false)).not_to be_visible
diff --git a/spec/features/groups/milestones/milestone_editing_spec.rb b/spec/features/groups/milestones/milestone_editing_spec.rb
new file mode 100644
index 00000000000..b3c7cfe88af
--- /dev/null
+++ b/spec/features/groups/milestones/milestone_editing_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe "Milestone editing", feature_category: :team_planning do
+ let_it_be(:group) { create(:group, owner: user) }
+ let_it_be(:user) { create(:group_member, :maintainer, user: create(:user), group: group).user }
+
+ let(:milestone) { create(:milestone, group: group, title: "12345676543") }
+
+ before do
+ sign_in(user)
+
+ visit(edit_group_milestone_path(group, milestone))
+ end
+
+ it_behaves_like 'milestone handling version conflicts'
+end
diff --git a/spec/features/groups/new_group_page_spec.rb b/spec/features/groups/new_group_page_spec.rb
index a07c27331d9..1efdc3fff07 100644
--- a/spec/features/groups/new_group_page_spec.rb
+++ b/spec/features/groups/new_group_page_spec.rb
@@ -3,15 +3,14 @@
require 'spec_helper'
RSpec.describe 'New group page', :js, feature_category: :subgroups do
- let(:user) { create(:user) }
- let(:group) { create(:group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:parent_group) { create(:group) }
before do
+ parent_group.add_owner(user)
sign_in(user)
end
- it_behaves_like 'a dashboard page with sidebar', :new_group_path, :groups
-
describe 'new top level group alert' do
context 'when a user visits the new group page' do
it 'shows the new top level group alert' do
@@ -22,8 +21,6 @@ RSpec.describe 'New group page', :js, feature_category: :subgroups do
end
context 'when a user visits the new sub group page' do
- let(:parent_group) { create(:group) }
-
it 'does not show the new top level group alert' do
visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane')
@@ -31,4 +28,45 @@ RSpec.describe 'New group page', :js, feature_category: :subgroups do
end
end
end
+
+ describe 'sidebar' do
+ context 'in the current navigation' do
+ before do
+ user.update!(use_new_navigation: false)
+ end
+
+ context 'for a new top-level group' do
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :new_group_path, :groups
+ end
+
+ context 'for a new subgroup' do
+ it 'shows the group sidebar of the parent group' do
+ visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane')
+ expect(page).to have_selector(
+ ".nav-sidebar[aria-label=\"Group navigation\"] .context-header[title=\"#{parent_group.name}\"]"
+ )
+ end
+ end
+ end
+
+ context 'in the new navigation' do
+ before do
+ user.update!(use_new_navigation: true)
+ end
+
+ context 'for a new top-level group' do
+ it 'shows the "Your work" navigation' do
+ visit new_group_path
+ expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: "Your work")
+ end
+ end
+
+ context 'for a new subgroup' do
+ it 'shows the group navigation of the parent group' do
+ visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane')
+ expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: parent_group.name)
+ end
+ end
+ end
+ end
end
diff --git a/spec/features/groups/packages_spec.rb b/spec/features/groups/packages_spec.rb
index dd238657fbc..b7f9cd3e93a 100644
--- a/spec/features/groups/packages_spec.rb
+++ b/spec/features/groups/packages_spec.rb
@@ -37,8 +37,8 @@ RSpec.describe 'Group Packages', feature_category: :package_registry do
end
context 'when there are packages' do
- let_it_be(:second_project) { create(:project, name: 'second-project', group: group) }
- let_it_be(:npm_package) { create(:npm_package, project: project, name: 'zzz', created_at: 1.day.ago, version: '1.0.0') }
+ let_it_be(:second_project) { create(:project, group: group) }
+ let_it_be(:npm_package) { create(:npm_package, :with_build, project: project, name: 'zzz', created_at: 1.day.ago, version: '1.0.0') }
let_it_be(:maven_package) { create(:maven_package, project: second_project, name: 'aaa', created_at: 2.days.ago, version: '2.0.0') }
let_it_be(:packages) { [npm_package, maven_package] }
@@ -47,10 +47,12 @@ RSpec.describe 'Group Packages', feature_category: :package_registry do
it_behaves_like 'packages list', check_project_name: true
+ it_behaves_like 'pipelines on packages list'
+
it_behaves_like 'package details link'
it 'allows you to navigate to the project page' do
- find('[data-testid="root-link"]', text: project.name).click
+ find('[data-testid="root-link"]', text: project.path).click
expect(page).to have_current_path(project_path(project))
expect(page).to have_content(project.name)
diff --git a/spec/features/groups/settings/access_tokens_spec.rb b/spec/features/groups/settings/access_tokens_spec.rb
index 1bee3be1ddb..cb92f9abdf5 100644
--- a/spec/features/groups/settings/access_tokens_spec.rb
+++ b/spec/features/groups/settings/access_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Group > Settings > Access Tokens', :js, feature_category: :authentication_and_authorization do
+RSpec.describe 'Group > Settings > Access Tokens', :js, feature_category: :system_access do
include Spec::Support::Helpers::ModalHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/features/groups/settings/packages_and_registries_spec.rb b/spec/features/groups/settings/packages_and_registries_spec.rb
index 80e2dcd5174..8ea8dc9219a 100644
--- a/spec/features/groups/settings/packages_and_registries_spec.rb
+++ b/spec/features/groups/settings/packages_and_registries_spec.rb
@@ -56,6 +56,15 @@ RSpec.describe 'Group Package and registry settings', feature_category: :package
expect(sidebar).to have_link _('Packages and registries')
end
+ it 'passes axe automated accessibility testing', :js do
+ visit_settings_page
+
+ wait_for_requests
+
+ expect(page).to be_axe_clean.within('[data-testid="packages-and-registries-group-settings"]')
+ .skipping :'link-in-text-block'
+ end
+
it 'has a Duplicate packages section', :js do
visit_settings_page
diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb
index 5cab79b40cf..0f936173e5d 100644
--- a/spec/features/groups/show_spec.rb
+++ b/spec/features/groups/show_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Group show page', feature_category: :subgroups do
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::InviteMembersModalHelpers
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index 8806d1c2219..088b5b11a9a 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -510,6 +510,47 @@ RSpec.describe 'Group', feature_category: :subgroups do
end
end
end
+
+ context 'when in a private group' do
+ before do
+ group.update!(
+ visibility_level: Gitlab::VisibilityLevel::PRIVATE,
+ project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS
+ )
+ end
+
+ context 'when visibility levels have been restricted to private only by an administrator' do
+ before do
+ stub_application_setting(
+ restricted_visibility_levels: [
+ Gitlab::VisibilityLevel::PRIVATE
+ ]
+ )
+ end
+
+ it 'does not display the "New project" button' do
+ visit group_path(group)
+
+ page.within '[data-testid="group-buttons"]' do
+ expect(page).not_to have_link('New project')
+ end
+ end
+ end
+ end
+ end
+
+ describe 'group README', :js do
+ context 'with gitlab-profile project and README.md' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :readme, namespace: group) }
+
+ it 'renders README block on group page' do
+ visit group_path(group)
+ wait_for_requests
+
+ expect(page).to have_text('README.md')
+ end
+ end
end
def remove_with_confirm(button_text, confirm_with)
diff --git a/spec/features/help_dropdown_spec.rb b/spec/features/help_dropdown_spec.rb
index a5c9221ad26..5f1d3a5e2b7 100644
--- a/spec/features/help_dropdown_spec.rb
+++ b/spec/features/help_dropdown_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Help Dropdown", :js, feature_category: :not_owned do
+RSpec.describe "Help Dropdown", :js, feature_category: :shared do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index 6c0901d6169..905c5e25f6e 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Help Pages', feature_category: :not_owned do
+RSpec.describe 'Help Pages', feature_category: :shared do
describe 'Get the main help page' do
before do
allow(File).to receive(:read).and_call_original
diff --git a/spec/features/ide/user_opens_merge_request_spec.rb b/spec/features/ide/user_opens_merge_request_spec.rb
index 0074b4b1eb0..dc280133a20 100644
--- a/spec/features/ide/user_opens_merge_request_spec.rb
+++ b/spec/features/ide/user_opens_merge_request_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'IDE merge request', :js, feature_category: :web_ide do
+ include CookieHelper
+
let(:merge_request) { create(:merge_request, :simple, source_project: project) }
let(:project) { create(:project, :public, :repository) }
let(:user) { project.first_owner }
@@ -12,6 +14,8 @@ RSpec.describe 'IDE merge request', :js, feature_category: :web_ide do
sign_in(user)
+ set_cookie('new-actions-popover-viewed', 'true')
+
visit(merge_request_path(merge_request))
end
diff --git a/spec/features/ide_spec.rb b/spec/features/ide_spec.rb
index 2ca8d3f7156..bdf8be95415 100644
--- a/spec/features/ide_spec.rb
+++ b/spec/features/ide_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'IDE', :js, feature_category: :web_ide do
- include WebIdeSpecHelpers
+ include Features::WebIdeSpecHelpers
let_it_be(:ide_iframe_selector) { '#ide iframe' }
let_it_be(:normal_project) { create(:project, :repository) }
@@ -48,17 +48,6 @@ RSpec.describe 'IDE', :js, feature_category: :web_ide do
it_behaves_like 'legacy Web IDE'
end
- context 'with vscode feature flag on and use_legacy_web_ide=true' do
- let(:vscode_ff) { true }
- let(:user) { create(:user, use_legacy_web_ide: true) }
-
- before do
- ide_visit(project)
- end
-
- it_behaves_like 'legacy Web IDE'
- end
-
describe 'sub-groups' do
let_it_be(:group) { create(:group) }
let_it_be(:subgroup) { create(:group, parent: group) }
diff --git a/spec/features/import/manifest_import_spec.rb b/spec/features/import/manifest_import_spec.rb
index bb3eb34637b..aba38eb0196 100644
--- a/spec/features/import/manifest_import_spec.rb
+++ b/spec/features/import/manifest_import_spec.rb
@@ -7,6 +7,8 @@ RSpec.describe 'Import multiple repositories by uploading a manifest file', :js,
let(:group) { create(:group) }
before do
+ stub_application_setting(import_sources: ['manifest'])
+
sign_in(user)
group.add_owner(user)
diff --git a/spec/features/incidents/incident_details_spec.rb b/spec/features/incidents/incident_details_spec.rb
index 709919d0196..a166ff46177 100644
--- a/spec/features/incidents/incident_details_spec.rb
+++ b/spec/features/incidents/incident_details_spec.rb
@@ -94,6 +94,7 @@ RSpec.describe 'Incident details', :js, feature_category: :incident_management d
end
it 'routes the user to the incident details page when the `issue_type` is set to incident' do
+ set_cookie('new-actions-popover-viewed', 'true')
visit project_issue_path(project, issue)
wait_for_requests
@@ -113,6 +114,7 @@ RSpec.describe 'Incident details', :js, feature_category: :incident_management d
end
it 'routes the user to the issue details page when the `issue_type` is set to issue' do
+ set_cookie('new-actions-popover-viewed', 'true')
visit incident_project_issues_path(project, incident)
wait_for_requests
diff --git a/spec/features/incidents/incident_timeline_events_spec.rb b/spec/features/incidents/incident_timeline_events_spec.rb
index 7404ac64cc9..4d51ed652c9 100644
--- a/spec/features/incidents/incident_timeline_events_spec.rb
+++ b/spec/features/incidents/incident_timeline_events_spec.rb
@@ -43,9 +43,7 @@ RSpec.describe 'Incident timeline events', :js, feature_category: :incident_mana
expect(page).to have_content(s_('Incident|No timeline items have been added yet.'))
end
- it 'submits event data on save with feature flag on' do
- stub_feature_flags(incident_event_tags: true)
-
+ it 'submits event data on save' do
# Add event
click_button(s_('Incident|Add new timeline event'))
@@ -96,5 +94,6 @@ RSpec.describe 'Incident timeline events', :js, feature_category: :incident_mana
it_behaves_like 'for each incident details route',
'add, edit, and delete timeline events',
- tab_text: s_('Incident|Timeline')
+ tab_text: s_('Incident|Timeline'),
+ tab: 'timeline'
end
diff --git a/spec/features/incidents/user_uses_quick_actions_spec.rb b/spec/features/incidents/user_uses_quick_actions_spec.rb
index 3740f2fca47..27facbcafe8 100644
--- a/spec/features/incidents/user_uses_quick_actions_spec.rb
+++ b/spec/features/incidents/user_uses_quick_actions_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Incidents > User uses quick actions', :js, feature_category: :incident_management do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
describe 'incident-only commands' do
let_it_be(:user) { create(:user) }
diff --git a/spec/features/incidents/user_views_alert_details_spec.rb b/spec/features/incidents/user_views_alert_details_spec.rb
new file mode 100644
index 00000000000..f3d0273071c
--- /dev/null
+++ b/spec/features/incidents/user_views_alert_details_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User uploads alerts to incident', :js, feature_category: :incident_management do
+ let_it_be(:incident) { create(:incident) }
+ let_it_be(:project) { incident.project }
+ let_it_be(:user) { create(:user, developer_projects: [project]) }
+
+ context 'with alert' do
+ let_it_be(:alert) { create(:alert_management_alert, issue_id: incident.id, project: project) }
+
+ shared_examples 'shows alert tab with details' do
+ specify do
+ expect(page).to have_link(s_('Incident|Alert details'))
+ expect(page).to have_content(alert.title)
+ end
+ end
+
+ it_behaves_like 'for each incident details route',
+ 'shows alert tab with details',
+ tab_text: s_('Incident|Alert details'),
+ tab: 'alerts'
+ end
+
+ context 'with no alerts' do
+ it 'hides the Alert details tab' do
+ sign_in(user)
+ visit project_issue_path(project, incident)
+
+ expect(page).not_to have_link(s_('Incident|Alert details'))
+ end
+ end
+end
diff --git a/spec/features/integrations_settings_spec.rb b/spec/features/integrations_settings_spec.rb
new file mode 100644
index 00000000000..70ce2f55161
--- /dev/null
+++ b/spec/features/integrations_settings_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Integration settings', feature_category: :integrations do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ context 'with Shimo Zentao integration records' do
+ before do
+ create(:integration, project: project, type_new: 'Integrations::Shimo', category: 'issue_tracker')
+ create(:integration, project: project, type_new: 'Integrations::Zentao', category: 'issue_tracker')
+ end
+
+ it 'shows settings without Shimo Zentao', :js do
+ visit namespace_project_settings_integrations_path(namespace_id: project.namespace.full_path,
+ project_id: project.path)
+
+ expect(page).to have_content('Add an integration')
+ expect(page).not_to have_content('ZenTao')
+ expect(page).not_to have_content('Shimo')
+ end
+ end
+end
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index 1091bea1ce3..a3d4b30b59c 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -28,14 +28,10 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_password', with: new_user.password
- click_button submit_button_text
- end
- def fill_in_sign_in_form(user)
- fill_in 'user_login', with: user.email
- fill_in 'user_password', with: user.password
- check 'user_remember_me'
- click_button 'Sign in'
+ wait_for_all_requests
+
+ click_button submit_button_text
end
def fill_in_welcome_form
@@ -73,7 +69,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
end
- context 'when invite is sent before account is created - ldap or service sign in for manual acceptance edge case' do
+ context 'when invite is sent before account is created;ldap or service sign in for manual acceptance edge case' do
let(:user) { create(:user, email: 'user@example.com') }
context 'when invite clicked and not signed in' do
@@ -84,7 +80,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
it 'sign in, grants access and redirects to group activity page' do
click_link 'Sign in'
- fill_in_sign_in_form(user)
+ gitlab_sign_in(user, remember: true, visit: false)
expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
end
@@ -151,7 +147,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
end
- context 'when inviting an unregistered user' do
+ context 'when inviting an unregistered user', :js do
let(:new_user) { build_stubbed(:user) }
let(:invite_email) { new_user.email }
let(:group_invite) { create(:group_member, :invited, group: group, invite_email: invite_email, created_by: owner) }
@@ -175,17 +171,19 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
fill_in_sign_up_form(new_user)
expect(page).to have_current_path(new_user_session_path, ignore_query: true)
- expect(page).to have_content('You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator')
+ sign_up_message = 'You have signed up successfully. However, we could not sign you in because your account ' \
+ 'is awaiting approval from your GitLab administrator.'
+ expect(page).to have_content(sign_up_message)
end
end
- context 'email confirmation disabled' do
+ context 'with email confirmation disabled' do
before do
stub_application_setting_enum('email_confirmation_setting', 'off')
end
- context 'the user signs up for an account with the invitation email address' do
- it 'redirects to the most recent membership activity page with all the projects/groups invitations automatically accepted' do
+ context 'when the user signs up for an account with the invitation email address' do
+ it 'redirects to the most recent membership activity page with all invitations automatically accepted' do
fill_in_sign_up_form(new_user)
fill_in_welcome_form
@@ -194,7 +192,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
end
- context 'the user sign-up using a different email address' do
+ context 'when the user sign-up using a different email address' do
let(:invite_email) { build_stubbed(:user).email }
it 'signs up and redirects to the activity page' do
@@ -206,9 +204,9 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
end
- context 'email confirmation enabled' do
+ context 'with email confirmation enabled' do
context 'when user is not valid in sign up form' do
- let(:new_user) { build_stubbed(:user, first_name: '', last_name: '') }
+ let(:new_user) { build_stubbed(:user, password: '11111111') }
it 'fails sign up and redirects back to sign up', :aggregate_failures do
expect { fill_in_sign_up_form(new_user) }.not_to change { User.count }
@@ -232,8 +230,8 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
end
- context 'the user signs up for an account with the invitation email address' do
- it 'redirects to the most recent membership activity page with all the projects/groups invitations automatically accepted' do
+ context 'when the user signs up for an account with the invitation email address' do
+ it 'redirects to the most recent membership activity page with all invitations automatically accepted' do
fill_in_sign_up_form(new_user)
fill_in_welcome_form
@@ -241,12 +239,11 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
end
- context 'the user sign-up using a different email address' do
+ context 'when the user signs up using a different email address' do
let(:invite_email) { build_stubbed(:user).email }
- context 'when soft email confirmation is not enabled' do
+ context 'when email confirmation is not set to `soft`' do
before do
- stub_feature_flags(soft_email_confirmation: false)
allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
stub_feature_flags(identity_verification: false)
end
@@ -254,16 +251,16 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
it 'signs up and redirects to the group activity page' do
fill_in_sign_up_form(new_user)
confirm_email(new_user)
- fill_in_sign_in_form(new_user)
+ gitlab_sign_in(new_user, remember: true, visit: false)
fill_in_welcome_form
expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
end
end
- context 'when soft email confirmation is enabled' do
+ context 'when email confirmation setting is set to `soft`' do
before do
- stub_feature_flags(soft_email_confirmation: true)
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
end
diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb
index 350b0582565..c979aff2147 100644
--- a/spec/features/issuables/issuable_list_spec.rb
+++ b/spec/features/issuables/issuable_list_spec.rb
@@ -48,7 +48,7 @@ RSpec.describe 'issuable list', :js, feature_category: :team_planning do
end
end
- it 'displays a warning if counting the number of issues times out' do
+ it 'displays a warning if counting the number of issues times out', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/393344' do
allow_any_instance_of(IssuesFinder).to receive(:count_by_state).and_raise(ActiveRecord::QueryCanceled)
visit_issuable_list(:issue)
diff --git a/spec/features/issuables/markdown_references/internal_references_spec.rb b/spec/features/issuables/markdown_references/internal_references_spec.rb
index aeae76b1b77..04950c7c7d4 100644
--- a/spec/features/issuables/markdown_references/internal_references_spec.rb
+++ b/spec/features/issuables/markdown_references/internal_references_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe "Internal references", :js, feature_category: :team_planning do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
let(:private_project_user) { private_project.first_owner }
let(:private_project) { create(:project, :private, :repository) }
diff --git a/spec/features/issuables/markdown_references/jira_spec.rb b/spec/features/issuables/markdown_references/jira_spec.rb
index 52464c6be8b..887bc7d0c87 100644
--- a/spec/features/issuables/markdown_references/jira_spec.rb
+++ b/spec/features/issuables/markdown_references/jira_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe "Jira", :js, feature_category: :team_planning do
end
it "creates a link to the referenced issue on the preview" do
- find(".js-md-preview-button").click
+ click_button("Preview")
wait_for_requests
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 0bdb5930f30..c982052fc0e 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
@@ -20,6 +20,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j
before do
stub_feature_flags(moved_mr_sidebar: false)
+ stub_feature_flags(hide_create_issue_resolve_all: false)
end
describe 'as a user with access to the project' do
@@ -33,7 +34,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j
find('.discussions-counter .dropdown-toggle').click
within('.discussions-counter') do
- expect(page).to have_link(_("Create issue to resolve all threads"), href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid))
+ expect(page).to have_link(_("Resolve all with new issue"), href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid))
end
end
@@ -44,7 +45,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j
it 'hides the link for creating a new issue' do
expect(page).not_to have_selector resolve_all_discussions_link_selector
- expect(page).not_to have_content "Create issue to resolve all threads"
+ expect(page).not_to have_content "Resolve all with new issue"
end
end
@@ -69,7 +70,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j
end
it 'does not show a link to create a new issue' do
- expect(page).not_to have_link 'Create issue to resolve all threads'
+ expect(page).not_to have_link 'Resolve all with new issue'
end
end
@@ -83,13 +84,13 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j
end
it 'has a link to resolve all threads by creating an issue' do
- expect(page).to have_link 'Create issue to resolve all threads', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
+ expect(page).to have_link 'Resolve all with new issue', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
end
context 'creating an issue for threads' do
before do
page.within '.mr-state-widget' do
- page.click_link 'Create issue to resolve all threads', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
+ page.click_link 'Resolve all with new issue', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
wait_for_all_requests
end
diff --git a/spec/features/issues/csv_spec.rb b/spec/features/issues/csv_spec.rb
index 8629201459f..21d5041b210 100644
--- a/spec/features/issues/csv_spec.rb
+++ b/spec/features/issues/csv_spec.rb
@@ -16,6 +16,7 @@ RSpec.describe 'Issues csv', :js, feature_category: :team_planning do
def request_csv(params = {})
visit project_issues_path(project, params)
+ click_button 'Actions'
click_button 'Export as CSV'
click_on 'Export issues'
end
diff --git a/spec/features/issues/discussion_lock_spec.rb b/spec/features/issues/discussion_lock_spec.rb
index 33fc9a6fd96..fb9addff1a2 100644
--- a/spec/features/issues/discussion_lock_spec.rb
+++ b/spec/features/issues/discussion_lock_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe 'Discussion Lock', :js, feature_category: :team_planning do
before do
sign_in(user)
+ stub_feature_flags(moved_mr_sidebar: false)
end
context 'when a user is a team member' do
@@ -99,7 +100,7 @@ RSpec.describe 'Discussion Lock', :js, feature_category: :team_planning do
it 'the user can not create a comment' do
page.within('#notes') do
expect(page).not_to have_selector('js-main-target-form')
- expect(page.find('.disabled-comment'))
+ expect(page.find('.disabled-comments'))
.to have_content('This issue is locked. Only project members can comment.')
end
end
diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
index 39034a40b1f..1cd8326c5fe 100644
--- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
@@ -52,8 +52,8 @@ RSpec.describe 'Dropdown hint', :js, feature_category: :team_planning do
click_filtered_search_bar
send_keys 'as'
- # Expect Assignee and Release
- expect_suggestion_count 2
+ # Expect Assignee, Release, Search for this text
+ expect_suggestion_count 3
end
end
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index f67d5c40efd..a65befc3115 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -61,7 +61,7 @@ RSpec.describe 'Filter issues', :js, feature_category: :team_planning do
it 'filters by all available tokens' do
search_term = 'issue'
select_tokens 'Assignee', '=', user.username, 'Author', '=', user.username, 'Label', '=', caps_sensitive_label.title, 'Milestone', '=', milestone.title
- send_keys search_term, :enter
+ send_keys search_term, :enter, :enter
expect_assignee_token(user.name)
expect_author_token(user.name)
@@ -261,7 +261,7 @@ RSpec.describe 'Filter issues', :js, feature_category: :team_planning do
it 'filters issues by searched label, label2, author, assignee, milestone and text' do
search_term = 'bug'
select_tokens 'Label', '=', bug_label.title, 'Label', '=', caps_sensitive_label.title, 'Author', '=', user.username, 'Assignee', '=', user.username, 'Milestone', '=', milestone.title
- send_keys search_term, :enter
+ send_keys search_term, :enter, :enter
expect_label_token(bug_label.title)
expect_label_token(caps_sensitive_label.title)
@@ -275,7 +275,7 @@ RSpec.describe 'Filter issues', :js, feature_category: :team_planning do
it 'filters issues by searched label, label2, author, assignee, not included in a milestone' do
search_term = 'bug'
select_tokens 'Label', '=', bug_label.title, 'Label', '=', caps_sensitive_label.title, 'Author', '=', user.username, 'Assignee', '=', user.username, 'Milestone', '!=', milestone.title
- send_keys search_term, :enter
+ send_keys search_term, :enter, :enter
expect_label_token(bug_label.title)
expect_label_token(caps_sensitive_label.title)
@@ -488,13 +488,13 @@ RSpec.describe 'Filter issues', :js, feature_category: :team_planning do
context 'searched text with other filters' do
it 'filters issues by searched text, author, text, assignee, text, label1, text, label2, text, milestone and text' do
click_filtered_search_bar
- send_keys 'bug '
+ send_keys 'bug', :enter
select_tokens 'Author', '=', user.username
- send_keys 'report '
+ send_keys 'report', :enter
select_tokens 'Label', '=', bug_label.title
select_tokens 'Label', '=', caps_sensitive_label.title
select_tokens 'Milestone', '=', milestone.title
- send_keys 'foo', :enter
+ send_keys 'foo', :enter, :enter
expect_issues_list_count(1)
expect_search_term('bug report foo')
diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb
index 2d9c73f2756..0efa2f49e36 100644
--- a/spec/features/issues/filtered_search/recent_searches_spec.rb
+++ b/spec/features/issues/filtered_search/recent_searches_spec.rb
@@ -100,7 +100,7 @@ RSpec.describe 'Recent searches', :js, feature_category: :team_planning do
def submit_then_clear_search(search)
click_filtered_search_bar
- send_keys(search, :enter)
+ send_keys(search, :enter, :enter)
click_button 'Clear'
end
end
diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb
index c975df2a531..35c099b29aa 100644
--- a/spec/features/issues/filtered_search/search_bar_spec.rb
+++ b/spec/features/issues/filtered_search/search_bar_spec.rb
@@ -70,7 +70,8 @@ RSpec.describe 'Search bar', :js, feature_category: :team_planning do
original_size = get_suggestion_count
send_keys 'autho'
- expect_suggestion_count 1
+ # Expect Author, Search for this text
+ expect_suggestion_count 2
click_button 'Clear'
click_filtered_search_bar
diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb
index f25925ed33d..3031b20eb7c 100644
--- a/spec/features/issues/filtered_search/visual_tokens_spec.rb
+++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb
@@ -79,10 +79,10 @@ RSpec.describe 'Visual tokens', :js, feature_category: :team_planning do
describe 'editing a search term while editing another filter token' do
before do
click_filtered_search_bar
- send_keys 'foo '
+ send_keys 'foo', :enter
select_tokens 'Assignee', '='
click_token_segment 'foo'
- send_keys ' '
+ send_keys :enter
end
it 'opens author dropdown' do
@@ -98,44 +98,6 @@ RSpec.describe 'Visual tokens', :js, feature_category: :team_planning do
end
end
- describe 'add new token after editing existing token' do
- before do
- select_tokens 'Assignee', '=', user.username, 'Label', '=', 'None'
- click_token_segment(user.name)
- send_keys ' '
- end
-
- describe 'opens dropdowns' do
- it 'opens hint dropdown' do
- expect_visible_suggestions_list
- end
-
- it 'opens token dropdown' do
- click_on 'Author'
-
- expect_visible_suggestions_list
- end
- end
-
- describe 'visual tokens' do
- it 'creates visual token' do
- click_on 'Author'
- click_on '= is'
- click_on 'The Rock'
-
- expect_author_token 'The Rock'
- end
- end
-
- it 'does not tokenize incomplete token' do
- click_on 'Author'
- find('.js-navbar').click
-
- expect_empty_search_term
- expect_token_segment 'Assignee'
- end
- end
-
describe 'search using incomplete visual tokens' do
before do
select_tokens 'Author', '=', user.username, 'Assignee', '=', 'None'
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index 585740f7782..9702e43a559 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
include ActionView::Helpers::JavaScriptHelper
+ include ListboxHelpers
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
@@ -13,9 +14,11 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
let_it_be(:label) { create(:label, project: project) }
let_it_be(:label2) { create(:label, project: project) }
let_it_be(:issue) { create(:issue, project: project, assignees: [user], milestone: milestone) }
+ let_it_be(:issue2) { create(:issue, project: project, assignees: [user], milestone: milestone) }
let_it_be(:confidential_issue) { create(:issue, project: project, assignees: [user], milestone: milestone, confidential: true) }
let(:current_user) { user }
+ let(:visible_label_selection_on_metadata) { false }
before_all do
project.add_maintainer(user)
@@ -25,6 +28,7 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
before do
stub_licensed_features(multiple_issue_assignees: false, issue_weights: false)
+ stub_feature_flags(visible_label_selection_on_metadata: visible_label_selection_on_metadata)
sign_in(current_user)
end
@@ -112,110 +116,240 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
end
end
- it 'allows user to create new issue' do
- fill_in 'issue_title', with: 'title'
- fill_in 'issue_description', with: 'title'
+ context 'with the visible_label_selection_on_metadata feature flag enabled' do
+ let(:visible_label_selection_on_metadata) { true }
- expect(find('a', text: 'Assign to me')).to be_visible
- click_button 'Unassigned'
+ it 'allows user to create new issue' do
+ fill_in 'issue_title', with: 'title'
+ fill_in 'issue_description', with: 'title'
- wait_for_requests
+ expect(find('a', text: 'Assign to me')).to be_visible
+ click_button 'Unassigned'
- page.within '.dropdown-menu-user' do
- click_link user2.name
- end
- expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s)
- page.within '.js-assignee-search' do
- expect(page).to have_content user2.name
- end
- expect(find('a', text: 'Assign to me')).to be_visible
+ wait_for_requests
+
+ page.within '.dropdown-menu-user' do
+ click_link user2.name
+ end
+ expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s)
+ page.within '.js-assignee-search' do
+ expect(page).to have_content user2.name
+ end
+ expect(find('a', text: 'Assign to me')).to be_visible
+
+ click_link 'Assign to me'
+ assignee_ids = page.all('input[name="issue[assignee_ids][]"]', visible: false)
+
+ expect(assignee_ids[0].value).to match(user.id.to_s)
+
+ page.within '.js-assignee-search' do
+ expect(page).to have_content user.name
+ end
+ expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
+
+ click_button 'Select milestone'
+ click_button milestone.title
+ expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
+ expect(page).to have_button milestone.title
+
+ click_button _('Select label')
+ wait_for_all_requests
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label.title
+ click_button label2.title
+ click_button _('Close')
+ wait_for_requests
+ page.within('[data-testid="embedded-labels-list"]') do
+ expect(page).to have_content(label.title)
+ expect(page).to have_content(label2.title)
+ end
+ end
+
+ click_button 'Create issue'
+
+ page.within '.issuable-sidebar' do
+ page.within '.assignee' do
+ expect(page).to have_content "Assignee"
+ end
- click_link 'Assign to me'
- assignee_ids = page.all('input[name="issue[assignee_ids][]"]', visible: false)
+ page.within '.milestone' do
+ expect(page).to have_content milestone.title
+ end
+
+ page.within '.labels' do
+ expect(page).to have_content label.title
+ expect(page).to have_content label2.title
+ end
+ end
- expect(assignee_ids[0].value).to match(user.id.to_s)
+ page.within '.breadcrumbs' do
+ issue = Issue.find_by(title: 'title')
- page.within '.js-assignee-search' do
- expect(page).to have_content user.name
+ expect(page).to have_text("Issues #{issue.to_reference}")
+ end
end
- expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
- click_button 'Select milestone'
- click_button milestone.title
- expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
- expect(page).to have_button milestone.title
+ it 'correctly updates the dropdown toggle when removing a label' do
+ click_button _('Select label')
+
+ wait_for_all_requests
- click_button 'Labels'
- page.within '.dropdown-menu-labels' do
- click_link label.title
- click_link label2.title
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label.title
+ click_button _('Close')
+
+ wait_for_requests
+
+ page.within('[data-testid="embedded-labels-list"]') do
+ expect(page).to have_content(label.title)
+ end
+
+ expect(page.find('.gl-dropdown-button-text')).to have_content(label.title)
+ end
+
+ click_button label.title, class: 'gl-dropdown-toggle'
+
+ wait_for_all_requests
+
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label.title, class: 'dropdown-item'
+ click_button _('Close')
+
+ wait_for_requests
+
+ expect(page).not_to have_selector('[data-testid="embedded-labels-list"]')
+ expect(page.find('.gl-dropdown-button-text')).to have_content(_('Select label'))
+ end
end
- find('.js-issuable-form-dropdown.js-label-select').click
+ it 'clears label search input field when a label is selected', :js do
+ click_button _('Select label')
- page.within '.js-label-select' do
- expect(page).to have_content label.title
+ wait_for_all_requests
+
+ page.within '[data-testid="sidebar-labels"]' do
+ search_field = find('input[type="search"]')
+
+ search_field.native.send_keys(label.title)
+
+ expect(page).to have_css('.gl-search-box-by-type-clear')
+
+ click_button label.title, class: 'dropdown-item'
+
+ expect(page).not_to have_css('.gl-search-box-by-type-clear')
+ expect(search_field.value).to eq ''
+ end
end
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
+ end
- click_button 'Create issue'
+ context 'with the visible_label_selection_on_metadata feature flag disabled' do
+ let(:visible_label_selection_on_metadata) { false }
+
+ it 'allows user to create new issue' do
+ fill_in 'issue_title', with: 'title'
+ fill_in 'issue_description', with: 'title'
- page.within '.issuable-sidebar' do
- page.within '.assignee' do
- expect(page).to have_content "Assignee"
+ expect(find('a', text: 'Assign to me')).to be_visible
+ click_button 'Unassigned'
+
+ wait_for_requests
+
+ page.within '.dropdown-menu-user' do
+ click_link user2.name
end
+ expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s)
+ page.within '.js-assignee-search' do
+ expect(page).to have_content user2.name
+ end
+ expect(find('a', text: 'Assign to me')).to be_visible
+
+ click_link 'Assign to me'
+ assignee_ids = page.all('input[name="issue[assignee_ids][]"]', visible: false)
+
+ expect(assignee_ids[0].value).to match(user.id.to_s)
+
+ page.within '.js-assignee-search' do
+ expect(page).to have_content user.name
+ end
+ expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
- page.within '.milestone' do
- expect(page).to have_content milestone.title
+ click_button 'Select milestone'
+ click_button milestone.title
+ expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
+ expect(page).to have_button milestone.title
+
+ click_button 'Labels'
+ page.within '.dropdown-menu-labels' do
+ click_link label.title
+ click_link label2.title
end
- page.within '.labels' do
+ find('.js-issuable-form-dropdown.js-label-select').click
+
+ page.within '.js-label-select' do
expect(page).to have_content label.title
- expect(page).to have_content label2.title
end
- end
+ expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
+ expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
- page.within '.breadcrumbs' do
- issue = Issue.find_by(title: 'title')
+ click_button 'Create issue'
- expect(page).to have_text("Issues #{issue.to_reference}")
- end
- end
+ page.within '.issuable-sidebar' do
+ page.within '.assignee' do
+ expect(page).to have_content "Assignee"
+ end
- it 'displays an error message when submitting an invalid form' do
- click_button 'Create issue'
+ page.within '.milestone' do
+ expect(page).to have_content milestone.title
+ end
- page.within('[data-testid="issue-title-input-field"]') do
- expect(page).to have_text(_('This field is required.'))
- end
- end
+ page.within '.labels' do
+ expect(page).to have_content label.title
+ expect(page).to have_content label2.title
+ end
+ end
- it 'correctly updates the dropdown toggle when removing a label' do
- click_button 'Labels'
+ page.within '.breadcrumbs' do
+ issue = Issue.find_by(title: 'title')
- page.within '.dropdown-menu-labels' do
- click_link label.title
+ expect(page).to have_text("Issues #{issue.to_reference}")
+ end
end
- expect(find('.js-label-select')).to have_content(label.title)
+ it 'correctly updates the dropdown toggle when removing a label' do
+ click_button 'Labels'
+
+ page.within '.dropdown-menu-labels' do
+ click_link label.title
+ end
+
+ expect(find('.js-label-select')).to have_content(label.title)
+
+ page.within '.dropdown-menu-labels' do
+ click_link label.title
+ end
- page.within '.dropdown-menu-labels' do
- click_link label.title
+ expect(find('.js-label-select')).to have_content('Labels')
end
- expect(find('.js-label-select')).to have_content('Labels')
- end
+ it 'clears label search input field when a label is selected' do
+ click_button 'Labels'
+
+ page.within '.dropdown-menu-labels' do
+ search_field = find('input[type="search"]')
- it 'clears label search input field when a label is selected' do
- click_button 'Labels'
+ search_field.set(label2.title)
+ click_link label2.title
+ expect(search_field.value).to eq ''
+ end
+ end
+ end
- page.within '.dropdown-menu-labels' do
- search_field = find('input[type="search"]')
+ it 'displays an error message when submitting an invalid form' do
+ click_button 'Create issue'
- search_field.set(label2.title)
- click_link label2.title
- expect(search_field.value).to eq ''
+ page.within('[data-testid="issue-title-input-field"]') do
+ expect(page).to have_text(_('This field is required.'))
end
end
@@ -248,19 +382,15 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
describe 'displays issue type options in the dropdown' do
shared_examples 'type option is visible' do |label:, identifier:|
it "shows #{identifier} option", :aggregate_failures do
- page.within('[data-testid="issue-type-select-dropdown"]') do
- expect(page).to have_selector(%([data-testid="issue-type-#{identifier}-icon"]))
- expect(page).to have_content(label)
- end
+ wait_for_requests
+ expect_listbox_item(label)
end
end
shared_examples 'type option is missing' do |label:, identifier:|
it "does not show #{identifier} option", :aggregate_failures do
- page.within('[data-testid="issue-type-select-dropdown"]') do
- expect(page).not_to have_selector(%([data-testid="issue-type-#{identifier}-icon"]))
- expect(page).not_to have_content(label)
- end
+ wait_for_requests
+ expect_no_listbox_item(label)
end
end
@@ -428,42 +558,100 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
visit edit_project_issue_path(project, issue)
end
- it 'allows user to update issue' do
- expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user.id.to_s)
- expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
- expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
+ context 'with the visible_label_selection_on_metadata feature flag enabled' do
+ let(:visible_label_selection_on_metadata) { true }
- page.within '.js-user-search' do
- expect(page).to have_content user.name
- end
+ it 'allows user to update issue' do
+ expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user.id.to_s)
+ expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
+ expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
+
+ page.within '.js-user-search' do
+ expect(page).to have_content user.name
+ end
- expect(page).to have_button milestone.title
+ expect(page).to have_button milestone.title
- click_button 'Labels'
- page.within '.dropdown-menu-labels' do
- click_link label.title
- click_link label2.title
- end
- page.within '.js-label-select' do
- expect(page).to have_content label.title
+ click_button _('Select label')
+
+ wait_for_all_requests
+
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label.title
+ click_button label2.title
+ click_button _('Close')
+
+ wait_for_requests
+
+ page.within('[data-testid="embedded-labels-list"]') do
+ expect(page).to have_content(label.title)
+ expect(page).to have_content(label2.title)
+ end
+ end
+
+ expect(page.all('input[name="issue[label_ids][]"]', visible: false)
+ .map(&:value))
+ .to contain_exactly(label.id.to_s, label2.id.to_s)
+
+ click_button 'Save changes'
+
+ page.within '.issuable-sidebar' do
+ page.within '.assignee' do
+ expect(page).to have_content user.name
+ end
+
+ page.within '.milestone' do
+ expect(page).to have_content milestone.title
+ end
+
+ page.within '.labels' do
+ expect(page).to have_content label.title
+ expect(page).to have_content label2.title
+ end
+ end
end
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
+ end
+
+ context 'with the visible_label_selection_on_metadata feature flag disabled' do
+ let(:visible_label_selection_on_metadata) { false }
- click_button 'Save changes'
+ it 'allows user to update issue' do
+ expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user.id.to_s)
+ expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
+ expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
- page.within '.issuable-sidebar' do
- page.within '.assignee' do
+ page.within '.js-user-search' do
expect(page).to have_content user.name
end
- page.within '.milestone' do
- expect(page).to have_content milestone.title
- end
+ expect(page).to have_button milestone.title
- page.within '.labels' do
+ click_button 'Labels'
+ page.within '.dropdown-menu-labels' do
+ click_link label.title
+ click_link label2.title
+ end
+ page.within '.js-label-select' do
expect(page).to have_content label.title
- expect(page).to have_content label2.title
+ end
+ expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
+ expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
+
+ click_button 'Save changes'
+
+ page.within '.issuable-sidebar' do
+ page.within '.assignee' do
+ expect(page).to have_content user.name
+ end
+
+ page.within '.milestone' do
+ expect(page).to have_content milestone.title
+ end
+
+ page.within '.labels' do
+ expect(page).to have_content label.title
+ expect(page).to have_content label2.title
+ end
end
end
end
@@ -477,14 +665,69 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
end
describe 'inline edit' do
- before do
- visit project_issue_path(project, issue)
+ context 'within issue 1' do
+ before do
+ visit project_issue_path(project, issue)
+ wait_for_requests
+ end
+
+ it 'opens inline edit form with shortcut' do
+ find('body').send_keys('e')
+
+ expect(page).to have_selector('.detail-page-description form')
+ end
+
+ describe 'when user has made no changes' do
+ it 'let user leave the page without warnings' do
+ expected_content = 'Issue created'
+ expect(page).to have_content(expected_content)
+
+ find('body').send_keys('e')
+
+ click_link 'Boards'
+
+ expect(page).not_to have_content(expected_content)
+ end
+ end
+
+ describe 'when user has made changes' do
+ it 'shows a warning and can stay on page', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/397683' do
+ content = 'new issue content'
+
+ find('body').send_keys('e')
+ fill_in 'issue-description', with: content
+
+ click_link 'Boards'
+
+ page.driver.browser.switch_to.alert.dismiss
+
+ click_button 'Save changes'
+ wait_for_requests
+
+ expect(page).to have_content(content)
+ end
+ end
end
- it 'opens inline edit form with shortcut' do
- find('body').send_keys('e')
+ context 'within issue 2' do
+ before do
+ visit project_issue_path(project, issue2)
+ wait_for_requests
+ end
- expect(page).to have_selector('.detail-page-description form')
+ describe 'when user has made changes' do
+ it 'shows a warning and can leave page', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410497' do
+ content = 'new issue content'
+ find('body').send_keys('e')
+ fill_in 'issue-description', with: content
+
+ click_link 'Boards'
+
+ page.driver.browser.switch_to.alert.accept
+
+ expect(page).not_to have_content(content)
+ end
+ end
end
end
@@ -499,22 +742,55 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
visit new_project_issue_path(sub_group_project)
end
- it 'creates project label from dropdown' do
- click_button 'Labels'
+ context 'with the visible_label_selection_on_metadata feature flag enabled', :js do
+ let(:visible_label_selection_on_metadata) { true }
- click_link 'Create project label'
+ it 'creates project label from dropdown' do
+ find('[data-testid="labels-select-dropdown-contents"] button').click
- page.within '.dropdown-new-label' do
- fill_in 'new_label_name', with: 'test label'
- first('.suggest-colors-dropdown a').click
+ wait_for_all_requests
- click_button 'Create'
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button _('Create project label')
- wait_for_requests
+ wait_for_requests
+ end
+
+ page.within '.js-labels-create' do
+ find('[data-testid="label-title-input"]').fill_in with: 'test label'
+ first('.suggest-colors-dropdown a').click
+
+ click_button 'Create'
+
+ wait_for_all_requests
+ end
+
+ page.within '.js-labels-list' do
+ expect(page).to have_button 'test label'
+ end
end
+ end
+
+ context 'with the visible_label_selection_on_metadata feature flag disabled' do
+ let(:visible_label_selection_on_metadata) { false }
+
+ it 'creates project label from dropdown' do
+ click_button 'Labels'
+
+ click_link 'Create project label'
- page.within '.dropdown-menu-labels' do
- expect(page).to have_link 'test label'
+ page.within '.dropdown-new-label' do
+ fill_in 'new_label_name', with: 'test label'
+ first('.suggest-colors-dropdown a').click
+
+ click_button 'Create'
+
+ wait_for_requests
+ end
+
+ page.within '.dropdown-menu-labels' do
+ expect(page).to have_link 'test label'
+ end
end
end
end
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index 2bd5373b715..665c7307231 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'GFM autocomplete', :js, feature_category: :team_planning do
+ include CookieHelper
+
let_it_be(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let_it_be(:user2) { create(:user, name: 'Marge Simpson', username: 'msimpson') }
@@ -45,6 +47,7 @@ RSpec.describe 'GFM autocomplete', :js, feature_category: :team_planning do
before do
sign_in(user)
+ set_cookie('new-actions-popover-viewed', 'true')
visit project_issue_path(project, issue_to_edit)
wait_for_requests
diff --git a/spec/features/issues/incident_issue_spec.rb b/spec/features/issues/incident_issue_spec.rb
index 41bbd79202f..145b51d207a 100644
--- a/spec/features/issues/incident_issue_spec.rb
+++ b/spec/features/issues/incident_issue_spec.rb
@@ -51,8 +51,8 @@ RSpec.describe 'Incident Detail', :js, feature_category: :team_planning do
aggregate_failures 'when on summary tab (default tab)' do
hidden_items = find_all('.js-issue-widgets')
- # Linked Issues/MRs and comment box and emoji block
- expect(hidden_items.count).to eq(3)
+ # Description footer + Linked Issues/MRs + comment box + emoji block
+ expect(hidden_items.count).to eq(4)
expect(hidden_items).to all(be_visible)
edit_button = find_all('[aria-label="Edit title and description"]')
diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb
index 20a69c61871..29a61d584ee 100644
--- a/spec/features/issues/issue_detail_spec.rb
+++ b/spec/features/issues/issue_detail_spec.rb
@@ -48,6 +48,30 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do
end
end
+ context 'when issue description has task list items' do
+ before do
+ description = '- [ ] I am a task
+
+| Table |
+|-------|
+| <ul><li>[ ] I am inside a table</li><ul> |'
+ issue.update!(description: description)
+
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ end
+
+ it 'shows task actions ellipsis button when hovering over the task list item, but not within a table', :aggregate_failures do
+ find('li', text: 'I am a task').hover
+
+ expect(page).to have_button 'Task actions'
+
+ find('li', text: 'I am inside a table').hover
+
+ expect(page).not_to have_button 'Task actions'
+ end
+ end
+
context 'when issue description has xss snippet' do
before do
issue.update!(description: '![xss" onload=alert(1);//](a)')
@@ -74,6 +98,7 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do
project.add_developer(user_to_be_deleted)
sign_in(user_to_be_deleted)
+ stub_feature_flags(moved_mr_sidebar: false)
visit project_issue_path(project, issue)
wait_for_requests
@@ -105,7 +130,7 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do
describe 'when an issue `issue_type` is edited' do
before do
sign_in(user)
-
+ set_cookie('new-actions-popover-viewed', 'true')
visit project_issue_path(project, issue)
wait_for_requests
end
@@ -139,7 +164,7 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do
describe 'when an incident `issue_type` is edited' do
before do
sign_in(user)
-
+ set_cookie('new-actions-popover-viewed', 'true')
visit project_issue_path(project, incident)
wait_for_requests
end
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index 686074f7412..ee71181fba2 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -4,7 +4,8 @@ require 'spec_helper'
RSpec.describe 'Issue Sidebar', feature_category: :team_planning do
include MobileHelpers
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::InviteMembersModalHelpers
+ include CookieHelper
let_it_be(:group) { create(:group, :nested) }
let_it_be(:project) { create(:project, :public, namespace: group) }
@@ -20,6 +21,7 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do
context 'when signed in' do
before do
sign_in(user)
+ set_cookie('new-actions-popover-viewed', 'true')
end
context 'when concerning the assignee', :js do
@@ -86,12 +88,12 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do
end
within '.js-right-sidebar' do
- find('.block.assignee').click(x: 0, y: 0)
+ find('.block.assignee').click(x: 0, y: 0, offset: 0)
find('.block.assignee .edit-link').click
end
- expect(page.all('.dropdown-menu-user li').length).to eq(1)
- expect(find('.dropdown-input-field').value).to eq(user2.name)
+ expect(page.all('.dropdown-menu-user li').length).to eq(6)
+ expect(find('.dropdown-input-field').value).to eq('')
end
it 'shows label text as "Apply" when assignees are changed' do
@@ -119,8 +121,6 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do
page.within '.dropdown-menu-user' do
expect(page).to have_link('Invite members')
- expect(page).to have_selector('[data-track-action="click_invite_members"]')
- expect(page).to have_selector('[data-track-label="edit_assignee"]')
click_link 'Invite members'
end
@@ -207,6 +207,7 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do
context 'as an allowed user' do
before do
+ stub_feature_flags(moved_mr_sidebar: false)
project.add_developer(user)
visit_issue(project, issue)
end
@@ -295,6 +296,7 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do
context 'as a guest' do
before do
+ stub_feature_flags(moved_mr_sidebar: false)
project.add_guest(user)
visit_issue(project, issue)
end
diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb
index ea68f2266b3..4512e88ae72 100644
--- a/spec/features/issues/move_spec.rb
+++ b/spec/features/issues/move_spec.rb
@@ -97,7 +97,7 @@ RSpec.describe 'issue move to another project', feature_category: :team_planning
end
end
- context 'service desk issue moved to a project with service desk disabled', :js do
+ context 'service desk issue moved to a project with service desk disabled', :saas, :js do
let(:project_title) { 'service desk disabled project' }
let(:warning_selector) { '.js-alert-moved-from-service-desk-warning' }
let(:namespace) { create(:namespace) }
@@ -106,9 +106,8 @@ RSpec.describe 'issue move to another project', feature_category: :team_planning
let(:service_desk_issue) { create(:issue, project: service_desk_project, author: ::User.support_bot) }
before do
- allow(Gitlab).to receive(:com?).and_return(true)
- allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true)
- allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
+ allow(Gitlab::Email::IncomingEmail).to receive(:enabled?).and_return(true)
+ allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
regular_project.add_reporter(user)
service_desk_project.add_reporter(user)
diff --git a/spec/features/issues/rss_spec.rb b/spec/features/issues/rss_spec.rb
index 36dffeded50..eb45d3c8d8b 100644
--- a/spec/features/issues/rss_spec.rb
+++ b/spec/features/issues/rss_spec.rb
@@ -23,24 +23,20 @@ RSpec.describe 'Project Issues RSS', :js, feature_category: :team_planning do
before do
sign_in(user)
visit path
+ click_button 'Actions'
end
- it "shows the RSS button with current_user's feed token" do
- expect(page).to have_link 'Subscribe to RSS feed', href: /feed_token=#{user.feed_token}/
- end
-
+ it_behaves_like "it has an RSS link with current_user's feed token"
it_behaves_like "an autodiscoverable RSS feed with current_user's feed token"
end
context 'when signed out' do
before do
visit path
+ click_button 'Actions'
end
- it "shows the RSS button without a feed token" do
- expect(page).not_to have_link 'Subscribe to RSS feed', href: /feed_token/
- end
-
+ it_behaves_like "it has an RSS link without a feed token"
it_behaves_like "an autodiscoverable RSS feed without a feed token"
end
diff --git a/spec/features/issues/service_desk_spec.rb b/spec/features/issues/service_desk_spec.rb
index 922ab95538b..0cadeb62fa2 100644
--- a/spec/features/issues/service_desk_spec.rb
+++ b/spec/features/issues/service_desk_spec.rb
@@ -10,8 +10,8 @@ RSpec.describe 'Service Desk Issue Tracker', :js, feature_category: :team_planni
before do
# The following two conditions equate to Gitlab::ServiceDesk.supported == true
- allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true)
- allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
+ allow(Gitlab::Email::IncomingEmail).to receive(:enabled?).and_return(true)
+ allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/issues/user_bulk_edits_issues_labels_spec.rb b/spec/features/issues/user_bulk_edits_issues_labels_spec.rb
index 1fc6609d1f5..a01ae9ae0c2 100644
--- a/spec/features/issues/user_bulk_edits_issues_labels_spec.rb
+++ b/spec/features/issues/user_bulk_edits_issues_labels_spec.rb
@@ -406,7 +406,7 @@ RSpec.describe 'Issues > Labels bulk assignment', feature_category: :team_planni
context 'cannot bulk assign labels' do
it do
- expect(page).not_to have_button 'Edit issues'
+ expect(page).not_to have_button 'Bulk edit'
expect(page).not_to have_unchecked_field 'Select all'
expect(page).not_to have_unchecked_field issue1.title
end
@@ -462,7 +462,7 @@ RSpec.describe 'Issues > Labels bulk assignment', feature_category: :team_planni
def enable_bulk_update
visit project_issues_path(project)
wait_for_requests
- click_button 'Edit issues'
+ click_button 'Bulk edit'
end
def disable_bulk_update
diff --git a/spec/features/issues/user_bulk_edits_issues_spec.rb b/spec/features/issues/user_bulk_edits_issues_spec.rb
index 5696bde4069..3e119d86c05 100644
--- a/spec/features/issues/user_bulk_edits_issues_spec.rb
+++ b/spec/features/issues/user_bulk_edits_issues_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor
it 'sets to closed', :js do
visit project_issues_path(project)
- click_button 'Edit issues'
+ click_button 'Bulk edit'
check 'Select all'
click_button 'Select status'
click_button 'Closed'
@@ -29,7 +29,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor
create_closed
visit project_issues_path(project, state: 'closed')
- click_button 'Edit issues'
+ click_button 'Bulk edit'
check 'Select all'
click_button 'Select status'
click_button 'Open'
@@ -43,7 +43,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor
it 'updates to current user' do
visit project_issues_path(project)
- click_button 'Edit issues'
+ click_button 'Bulk edit'
check 'Select all'
click_update_assignee_button
click_button user.username
@@ -61,7 +61,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor
expect(find('.issue:first-of-type')).to have_link "Assigned to #{user.name}"
- click_button 'Edit issues'
+ click_button 'Bulk edit'
check 'Select all'
click_update_assignee_button
click_button 'Unassigned'
@@ -77,7 +77,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor
it 'updates milestone' do
visit project_issues_path(project)
- click_button 'Edit issues'
+ click_button 'Bulk edit'
check 'Select all'
click_button 'Select milestone'
click_button milestone.title
@@ -94,7 +94,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor
expect(find('.issue:first-of-type')).to have_text milestone.title
- click_button 'Edit issues'
+ click_button 'Bulk edit'
check 'Select all'
click_button 'Select milestone'
click_button 'No milestone'
@@ -110,7 +110,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor
it 'after selecting all issues, unchecking one issue only unselects that one issue' do
visit project_issues_path(project)
- click_button 'Edit issues'
+ click_button 'Bulk edit'
check 'Select all'
uncheck issue.title
diff --git a/spec/features/issues/user_comments_on_issue_spec.rb b/spec/features/issues/user_comments_on_issue_spec.rb
index 59e1413fc97..3ace560fb40 100644
--- a/spec/features/issues/user_comments_on_issue_spec.rb
+++ b/spec/features/issues/user_comments_on_issue_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
RSpec.describe "User comments on issue", :js, feature_category: :team_planning do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) }
@@ -32,6 +32,8 @@ RSpec.describe "User comments on issue", :js, feature_category: :team_planning d
end
end
+ it_behaves_like 'edits content using the content editor'
+
it "adds comment with code block" do
code_block_content = "Command [1]: /usr/local/bin/git , see [text](doc/text)"
comment = "```\n#{code_block_content}\n```"
diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
index bbc14368d82..6d9eb3a7191 100644
--- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
+++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
@@ -73,8 +73,8 @@ RSpec.describe 'User creates branch and merge request on issue page', :js, featu
expect(page).to have_content('New merge request')
expect(page).to have_content("From #{issue.to_branch_name} into #{project.default_branch}")
- expect(page).to have_content("Closes ##{issue.iid}")
expect(page).to have_field("Title", with: "Draft: Resolve \"Cherry-Coloured Funk\"")
+ expect(page).to have_field("Description", with: "Closes ##{issue.iid}")
expect(page).to have_current_path(project_new_merge_request_path(project, merge_request: { source_branch: issue.to_branch_name, target_branch: project.default_branch, issue_iid: issue.iid }))
end
end
@@ -98,8 +98,8 @@ RSpec.describe 'User creates branch and merge request on issue page', :js, featu
expect(page).to have_content('New merge request')
expect(page).to have_content("From #{branch_name} into #{project.default_branch}")
- expect(page).to have_content("Closes ##{issue.iid}")
expect(page).to have_field("Title", with: "Draft: Resolve \"Cherry-Coloured Funk\"")
+ expect(page).to have_field("Description", with: "Closes ##{issue.iid}")
expect(page).to have_current_path(project_new_merge_request_path(project, merge_request: { source_branch: branch_name, target_branch: project.default_branch, issue_iid: issue.iid }))
end
end
@@ -113,6 +113,26 @@ RSpec.describe 'User creates branch and merge request on issue page', :js, featu
expect(page).to have_current_path project_tree_path(project, branch_name), ignore_query: true
end
end
+
+ context 'when branch name is invalid' do
+ shared_examples 'has error message' do |dropdown|
+ it 'has error message' do
+ select_dropdown_option(dropdown, 'custom-branch-name w~th ^bad chars?')
+
+ wait_for_requests
+
+ expect(page).to have_text("Can't contain spaces, ~, ^, ?")
+ end
+ end
+
+ context 'when creating a merge request', :sidekiq_might_not_need_inline do
+ it_behaves_like 'has error message', 'create-mr'
+ end
+
+ context 'when creating a branch', :sidekiq_might_not_need_inline do
+ it_behaves_like 'has error message', 'create-branch'
+ end
+ end
end
context "when there is a referenced merge request" do
diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb
index c5d0791dc57..d4148717f0a 100644
--- a/spec/features/issues/user_creates_issue_spec.rb
+++ b/spec/features/issues/user_creates_issue_spec.rb
@@ -8,16 +8,20 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
let_it_be(:project) { create(:project_empty_repo, :public) }
let_it_be(:user) { create(:user) }
+ let(:visible_label_selection_on_metadata) { false }
+
context "when unauthenticated" do
before do
sign_out(:user)
end
- it "redirects to signin then back to new issue after signin", :js do
+ it "redirects to signin then back to new issue after signin", :js, quarantine: 'https://gitlab.com/gitlab-org/quality/engineering-productivity/master-broken-incidents/-/issues/1486' do
create(:issue, project: project)
visit project_issues_path(project)
+ wait_for_all_requests
+
page.within ".nav-controls" do
click_link "New issue"
end
@@ -32,6 +36,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
context "when signed in as guest", :js do
before do
+ stub_feature_flags(visible_label_selection_on_metadata: visible_label_selection_on_metadata)
project.add_guest(user)
sign_in(user)
@@ -61,18 +66,18 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
page.within(form) do
click_button("Preview")
- preview = find(".js-md-preview") # this element is findable only when the "Preview" link is clicked.
+ preview = find(".js-vue-md-preview") # this element is findable only when the "Preview" link is clicked.
expect(preview).to have_content("Nothing to preview.")
- click_button("Write")
+ click_button("Continue editing")
fill_in("Description", with: "Bug fixed :smile:")
click_button("Preview")
expect(preview).to have_css("gl-emoji")
expect(textarea).not_to be_visible
- click_button("Write")
+ click_button("Continue editing")
fill_in("Description", with: "/confidential")
click_button("Preview")
@@ -90,18 +95,50 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
end
end
- it "creates issue" do
- issue_title = "500 error on profile"
+ context 'with the visible_label_selection_on_metadata feature flag enabled' do
+ let(:visible_label_selection_on_metadata) { true }
+
+ it "creates issue" do
+ issue_title = "500 error on profile"
+
+ fill_in("Title", with: issue_title)
+
+ click_button _('Select label')
+
+ wait_for_all_requests
+
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label_titles.first
+ click_button _('Close')
+
+ wait_for_requests
+ end
+
+ click_button("Create issue")
+
+ expect(page).to have_content(issue_title)
+ .and have_content(user.name)
+ .and have_content(project.name)
+ .and have_content(label_titles.first)
+ end
+ end
+
+ context 'with the visible_label_selection_on_metadata feature flag disabled' do
+ let(:visible_label_selection_on_metadata) { false }
+
+ it "creates issue" do
+ issue_title = "500 error on profile"
- fill_in("Title", with: issue_title)
- click_button("Label")
- click_link(label_titles.first)
- click_button("Create issue")
+ fill_in("Title", with: issue_title)
+ click_button("Label")
+ click_link(label_titles.first)
+ click_button("Create issue")
- expect(page).to have_content(issue_title)
- .and have_content(user.name)
- .and have_content(project.name)
- .and have_content(label_titles.first)
+ expect(page).to have_content(issue_title)
+ .and have_content(user.name)
+ .and have_content(project.name)
+ .and have_content(label_titles.first)
+ end
end
end
@@ -127,6 +164,8 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
end
end
+ it_behaves_like 'edits content using the content editor'
+
context 'dropzone upload file', :js do
before do
visit new_project_issue_path(project)
@@ -184,7 +223,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
end
it 'pre-fills the issue type dropdown with issue type' do
- expect(find('.js-issuable-type-filter-dropdown-wrap .dropdown-toggle-text')).to have_content('Issue')
+ expect(find('.js-issuable-type-filter-dropdown-wrap .gl-button-text')).to have_content('Issue')
end
it 'does not hide the milestone select' do
@@ -200,7 +239,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
end
it 'does not pre-fill the issue type dropdown with incident type' do
- expect(find('.js-issuable-type-filter-dropdown-wrap .dropdown-toggle-text')).not_to have_content('Incident')
+ expect(find('.js-issuable-type-filter-dropdown-wrap .gl-button-text')).not_to have_content('Incident')
end
it 'shows the milestone select' do
@@ -231,6 +270,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
wait_for_requests
expect(page).to have_field('Title', with: '')
+ expect(page).to have_field('Description', with: '')
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
@@ -238,6 +278,21 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
click_button 'Create issue'
end
end
+
+ it 'clears local storage after cancelling a new issue creation', :js do
+ 2.times do
+ visit new_project_issue_path(project)
+ wait_for_requests
+
+ expect(page).to have_field('Title', with: '')
+ expect(page).to have_field('Description', with: '')
+
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
+
+ click_link 'Cancel'
+ end
+ end
end
context 'when signed in as reporter', :js do
@@ -257,7 +312,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
end
it 'pre-fills the issue type dropdown with incident type' do
- expect(find('.js-issuable-type-filter-dropdown-wrap .dropdown-toggle-text')).to have_content('Incident')
+ expect(find('.js-issuable-type-filter-dropdown-wrap .gl-button-text')).to have_content('Incident')
end
it 'hides the epic select' do
diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb
index bf2af918f39..bc20660d2a0 100644
--- a/spec/features/issues/user_edits_issue_spec.rb
+++ b/spec/features/issues/user_edits_issue_spec.rb
@@ -3,6 +3,8 @@
require "spec_helper"
RSpec.describe "Issues > User edits issue", :js, feature_category: :team_planning do
+ include CookieHelper
+
let_it_be(:project) { create(:project_empty_repo, :public) }
let_it_be(:project_with_milestones) { create(:project_empty_repo, :public) }
let_it_be(:user) { create(:user) }
@@ -18,6 +20,7 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin
project.add_developer(user)
project_with_milestones.add_developer(user)
sign_in(user)
+ set_cookie('new-actions-popover-viewed', 'true')
end
context "from edit page" do
@@ -26,6 +29,8 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin
visit edit_project_issue_path(project, issue)
end
+ it_behaves_like 'edits content using the content editor'
+
it "previews content", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391757' do
form = first(".gfm-form")
@@ -34,9 +39,7 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin
click_button("Preview")
end
- expect(form).to have_button("Write")
-
- click_button("Write")
+ click_button("Continue editing")
fill_in("Description", with: "/confidential")
click_button("Preview")
@@ -51,7 +54,7 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin
first('.js-user-search').click
click_link 'Unassigned'
- click_button 'Save changes'
+ click_button _('Save changes')
page.within('.assignee') do
expect(page).to have_content 'None - assign yourself'
@@ -76,7 +79,7 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin
expect(find('#issuable-due-date').value).to eq date.to_s
- click_button 'Save changes'
+ click_button _('Save changes')
page.within '.issuable-sidebar' do
expect(page).to have_content date.to_s(:medium)
@@ -89,9 +92,15 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
- click_button 'Save changes'
+ click_button _('Save changes')
- expect(page).to have_content 'Someone edited the issue the same time you did'
+ expect(page).to have_content(
+ format(
+ _("Someone edited this %{model_name} at the same time you did. Please check out the %{link_to_model} and make sure your changes will not unintentionally remove theirs."), # rubocop:disable Layout/LineLength
+ model_name: _('issue'),
+ link_to_model: _('issue')
+ )
+ )
end
end
end
@@ -111,23 +120,27 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin
markdown_field_focused_selector = 'textarea:focus'
click_edit_issue_description
- expect(page).to have_selector(markdown_field_focused_selector)
+ issuable_form = find('[data-testid="issuable-form"]')
- click_on _('View rich text')
- click_on _('Rich text')
+ expect(issuable_form).to have_selector(markdown_field_focused_selector)
- expect(page).not_to have_selector(content_editor_focused_selector)
+ page.within issuable_form do
+ click_button("Switch to rich text")
+ end
+
+ expect(issuable_form).not_to have_selector(content_editor_focused_selector)
refresh
click_edit_issue_description
- expect(page).to have_selector(content_editor_focused_selector)
+ expect(issuable_form).to have_selector(content_editor_focused_selector)
- click_on _('View markdown')
- click_on _('Markdown')
+ page.within issuable_form do
+ click_button("Switch to Markdown")
+ end
- expect(page).not_to have_selector(markdown_field_focused_selector)
+ expect(issuable_form).not_to have_selector(markdown_field_focused_selector)
end
end
diff --git a/spec/features/issues/user_sorts_issue_comments_spec.rb b/spec/features/issues/user_sorts_issue_comments_spec.rb
index ca52e620ea7..153066343f2 100644
--- a/spec/features/issues/user_sorts_issue_comments_spec.rb
+++ b/spec/features/issues/user_sorts_issue_comments_spec.rb
@@ -16,9 +16,8 @@ RSpec.describe 'Comment sort direction', feature_category: :team_planning do
it 'saves sort order' do
# open dropdown, and select 'Newest first'
page.within('.issuable-details') do
- find('#discussion-preferences-dropdown').click
+ click_button('Sort or filter')
click_button('Oldest first')
- find('#discussion-preferences-dropdown').click
click_button('Newest first')
end
diff --git a/spec/features/issues/user_toggles_subscription_spec.rb b/spec/features/issues/user_toggles_subscription_spec.rb
index 904fafdf56a..00b04c10d33 100644
--- a/spec/features/issues/user_toggles_subscription_spec.rb
+++ b/spec/features/issues/user_toggles_subscription_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe "User toggles subscription", :js, feature_category: :team_plannin
context 'user is not logged in' do
before do
+ stub_feature_flags(moved_mr_sidebar: false)
visit(project_issue_path(project, issue))
end
@@ -20,9 +21,9 @@ RSpec.describe "User toggles subscription", :js, feature_category: :team_plannin
context 'user is logged in' do
before do
+ stub_feature_flags(moved_mr_sidebar: false)
project.add_developer(user)
sign_in(user)
-
visit(project_issue_path(project, issue))
end
@@ -52,6 +53,7 @@ RSpec.describe "User toggles subscription", :js, feature_category: :team_plannin
context 'user is logged in without edit permission' do
before do
+ stub_feature_flags(moved_mr_sidebar: false)
sign_in(user2)
visit(project_issue_path(project, issue))
diff --git a/spec/features/issues/user_uses_quick_actions_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb
index 963f1c56fef..e85a521e242 100644
--- a/spec/features/issues/user_uses_quick_actions_spec.rb
+++ b/spec/features/issues/user_uses_quick_actions_spec.rb
@@ -8,7 +8,7 @@ require 'spec_helper'
# Because this kind of spec takes more time to run there is no need to add new ones
# for each existing quick action unless they test something not tested by existing tests.
RSpec.describe 'Issues > User uses quick actions', :js, feature_category: :team_planning do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
context "issuable common quick actions" do
let(:new_url_opts) { {} }
diff --git a/spec/features/jira_connect/branches_spec.rb b/spec/features/jira_connect/branches_spec.rb
index c90c0d2dda9..25dc14a1dc9 100644
--- a/spec/features/jira_connect/branches_spec.rb
+++ b/spec/features/jira_connect/branches_spec.rb
@@ -75,7 +75,7 @@ RSpec.describe 'Create GitLab branches from Jira', :js, feature_category: :integ
select_listbox_item(source_branch)
fill_in 'Branch name', with: new_branch
- click_on 'Create branch'
+ click_button 'Create branch'
expect(page).to have_text('New branch was successfully created. You can now close this window and return to Jira.')
diff --git a/spec/features/jira_oauth_provider_authorize_spec.rb b/spec/features/jira_oauth_provider_authorize_spec.rb
index a542aaa7619..e873d9c219f 100644
--- a/spec/features/jira_oauth_provider_authorize_spec.rb
+++ b/spec/features/jira_oauth_provider_authorize_spec.rb
@@ -4,18 +4,39 @@ require 'spec_helper'
RSpec.describe 'JIRA OAuth Provider', feature_category: :integrations do
describe 'JIRA DVCS OAuth Authorization' do
- let(:application) { create(:oauth_application, redirect_uri: oauth_jira_dvcs_callback_url, scopes: 'read_user') }
+ let_it_be(:application) do
+ create(:oauth_application, redirect_uri: oauth_jira_dvcs_callback_url, scopes: 'read_user')
+ end
+
+ let(:authorize_path) do
+ oauth_jira_dvcs_authorize_path(client_id: application.uid,
+ redirect_uri: oauth_jira_dvcs_callback_url,
+ response_type: 'code',
+ state: 'my_state',
+ scope: 'read_user')
+ end
before do
sign_in(user)
+ end
- visit oauth_jira_dvcs_authorize_path(client_id: application.uid,
- redirect_uri: oauth_jira_dvcs_callback_url,
- response_type: 'code',
- state: 'my_state',
- scope: 'read_user')
+ it_behaves_like 'Secure OAuth Authorizations' do
+ before do
+ visit authorize_path
+ end
end
- it_behaves_like 'Secure OAuth Authorizations'
+ context 'when the flag is disabled' do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ stub_feature_flags(jira_dvcs_end_of_life_amnesty: false)
+ visit authorize_path
+ end
+
+ it 'presents as an endpoint that does not exist' do
+ expect(page).to have_gitlab_http_status(:not_found)
+ end
+ end
end
end
diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb
index d6e607e80df..e8f40a1ceab 100644
--- a/spec/features/labels_hierarchy_spec.rb
+++ b/spec/features/labels_hierarchy_spec.rb
@@ -157,28 +157,71 @@ RSpec.describe 'Labels Hierarchy', :js, feature_category: :team_planning do
end
end
- context 'when creating new issuable' do
+ context 'with the visible_label_selection_on_metadata feature flag enabled' do
before do
- visit new_project_issue_path(project_1)
+ stub_feature_flags(visible_label_selection_on_metadata: true)
end
- it 'is able to assign ancestor group labels' do
- fill_in 'issue_title', with: 'new created issue'
- fill_in 'issue_description', with: 'new issue description'
+ context 'when creating new issuable' do
+ before do
+ visit new_project_issue_path(project_1)
+ end
+
+ it 'is able to assign ancestor group labels' do
+ fill_in 'issue_title', with: 'new created issue'
+ fill_in 'issue_description', with: 'new issue description'
+
+ click_button _('Select label')
+
+ wait_for_all_requests
+
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button grandparent_group_label.title
+ click_button parent_group_label.title
+ click_button project_label_1.title
+ click_button _('Close')
+
+ wait_for_requests
+ end
+
+ find('.btn-confirm').click
+
+ expect(page.find('.issue-details h1.title')).to have_content('new created issue')
+ expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title)
+ expect(page).to have_selector('span.gl-label-text', text: parent_group_label.title)
+ expect(page).to have_selector('span.gl-label-text', text: project_label_1.title)
+ end
+ end
+ end
- find(".js-label-select").click
- wait_for_requests
+ context 'with the visible_label_selection_on_metadata feature flag disabled' do
+ before do
+ stub_feature_flags(visible_label_selection_on_metadata: false)
+ end
- find('a.label-item', text: grandparent_group_label.title).click
- find('a.label-item', text: parent_group_label.title).click
- find('a.label-item', text: project_label_1.title).click
+ context 'when creating new issuable' do
+ before do
+ visit new_project_issue_path(project_1)
+ end
+
+ it 'is able to assign ancestor group labels' do
+ fill_in 'issue_title', with: 'new created issue'
+ fill_in 'issue_description', with: 'new issue description'
+
+ find(".js-label-select").click
+ wait_for_requests
- find('.btn-confirm').click
+ find('a.label-item', text: grandparent_group_label.title).click
+ find('a.label-item', text: parent_group_label.title).click
+ find('a.label-item', text: project_label_1.title).click
- expect(page.find('.issue-details h1.title')).to have_content('new created issue')
- expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title)
- expect(page).to have_selector('span.gl-label-text', text: parent_group_label.title)
- expect(page).to have_selector('span.gl-label-text', text: project_label_1.title)
+ find('.btn-confirm').click
+
+ expect(page.find('.issue-details h1.title')).to have_content('new created issue')
+ expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title)
+ expect(page).to have_selector('span.gl-label-text', text: parent_group_label.title)
+ expect(page).to have_selector('span.gl-label-text', text: project_label_1.title)
+ end
end
end
diff --git a/spec/features/markdown/markdown_spec.rb b/spec/features/markdown/markdown_spec.rb
index 6e62aa892bb..a31ad5a868e 100644
--- a/spec/features/markdown/markdown_spec.rb
+++ b/spec/features/markdown/markdown_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures, feature_category: :team_p
end
aggregate_failures 'parses mermaid code block' do
- expect(doc).to have_selector('pre[lang=mermaid] > code.js-render-mermaid')
+ expect(doc).to have_selector('pre[data-canonical-lang=mermaid] > code.js-render-mermaid')
end
aggregate_failures 'parses strikethroughs' do
@@ -250,6 +250,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures, feature_category: :team_p
aggregate_failures 'all reference filters' do
expect(doc).to reference_users
expect(doc).to reference_issues
+ expect(doc).to reference_work_items
expect(doc).to reference_merge_requests
expect(doc).to reference_snippets
expect(doc).to reference_commit_ranges
@@ -345,6 +346,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures, feature_category: :team_p
aggregate_failures 'all reference filters' do
expect(doc).to reference_users
expect(doc).to reference_issues
+ expect(doc).to reference_work_items
expect(doc).to reference_merge_requests
expect(doc).to reference_snippets
expect(doc).to reference_commit_ranges
diff --git a/spec/features/markdown/metrics_spec.rb b/spec/features/markdown/metrics_spec.rb
index b5e42b16f87..1b68f78e993 100644
--- a/spec/features/markdown/metrics_spec.rb
+++ b/spec/features/markdown/metrics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_store_caching, :sidekiq_inline, feature_category: :team_planning do
+RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_store_caching, :sidekiq_inline, feature_category: :metrics do
include PrometheusHelpers
include KubernetesHelpers
include GrafanaApiHelpers
@@ -17,6 +17,7 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st
let(:metrics_url) { urls.metrics_project_environment_url(project, environment) }
before do
+ stub_feature_flags(remove_monitor_metrics: false)
clear_host_from_memoized_variables
stub_gitlab_domain
@@ -28,6 +29,20 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st
clear_host_from_memoized_variables
end
+ shared_examples_for 'metrics dashboard unavailable' do
+ context 'when metrics dashboard feature is unavailable' do
+ before do
+ stub_feature_flags(remove_monitor_metrics: true)
+ end
+
+ it 'shows no embedded metrics' do
+ visit project_issue_path(project, issue)
+
+ expect(page).to have_no_css('div.prometheus-graph')
+ end
+ end
+ end
+
context 'internal metrics embeds' do
before do
import_common_metrics
@@ -36,6 +51,8 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st
allow(Prometheus::ProxyService).to receive(:new).and_call_original
end
+ include_examples 'metrics dashboard unavailable'
+
it 'shows embedded metrics' do
visit project_issue_path(project, issue)
@@ -50,6 +67,20 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st
.at_least(:once)
end
+ context 'with remove_monitor_metrics flag enabled' do
+ before do
+ stub_feature_flags(remove_monitor_metrics: true)
+ end
+
+ it 'does not show embedded metrics' do
+ visit project_issue_path(project, issue)
+
+ expect(page).not_to have_css('div.prometheus-graph')
+ expect(page).not_to have_text('Memory Usage (Total)')
+ expect(page).not_to have_text('Core Usage (Total)')
+ end
+ end
+
context 'when dashboard params are in included the url' do
let(:metrics_url) { urls.metrics_project_environment_url(project, environment, **chart_params) }
@@ -120,7 +151,9 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st
allow(Grafana::ProxyService).to receive(:new).and_call_original
end
- it 'shows embedded metrics' do
+ include_examples 'metrics dashboard unavailable'
+
+ it 'shows embedded metrics', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/402973' do
visit project_issue_path(project, issue)
expect(page).to have_css('div.prometheus-graph')
@@ -157,6 +190,8 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st
stub_any_prometheus_request_with_response
end
+ include_examples 'metrics dashboard unavailable'
+
it 'shows embedded metrics' do
visit project_issue_path(project, issue)
@@ -186,6 +221,8 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st
let(:metrics_url) { urls.namespace_project_cluster_url(*params, **query_params) }
let(:description) { "# Summary \n[](#{metrics_url})" }
+ include_examples 'metrics dashboard unavailable'
+
it 'shows embedded metrics' do
visit project_issue_path(project, issue)
diff --git a/spec/features/markdown/observability_spec.rb b/spec/features/markdown/observability_spec.rb
index 86caf3eb1b1..ec414d4396e 100644
--- a/spec/features/markdown/observability_spec.rb
+++ b/spec/features/markdown/observability_spec.rb
@@ -2,82 +2,44 @@
require 'spec_helper'
-RSpec.describe 'Observability rendering', :js do
+RSpec.describe 'Observability rendering', :js, feature_category: :metrics do
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :repository, group: group) }
let_it_be(:user) { create(:user) }
- let_it_be(:observable_url) { "https://observe.gitlab.com/" }
-
- let_it_be(:expected) do
- %(<iframe src="#{observable_url}?theme=light&amp;kiosk" frameborder="0")
- end
+ let_it_be(:observable_url) { "https://www.gitlab.com/groups/#{group.path}/-/observability/explore?observability_path=/explore?foo=bar" }
+ let_it_be(:expected_observable_url) { "https://observe.gitlab.com/-/#{group.id}/explore?foo=bar" }
before do
- project.add_maintainer(user)
+ stub_config_setting(url: "https://www.gitlab.com")
+ group.add_developer(user)
sign_in(user)
end
- context 'when embedding in an issue' do
- let(:issue) do
- create(:issue, project: project, description: observable_url)
- end
-
- before do
- visit project_issue_path(project, issue)
- wait_for_requests
- end
-
- it 'renders iframe in description' do
- page.within('.description') do
- expect(page.html).to include(expected)
- end
- end
-
- it 'renders iframe in comment' do
- expect(page).not_to have_css('.note-text')
-
- page.within('.js-main-target-form') do
- fill_in('note[note]', with: observable_url)
- click_button('Comment')
+ context 'when user is a developer of the embedded group' do
+ context 'when embedding in an issue' do
+ let(:issue) do
+ create(:issue, project: project, description: observable_url)
end
- wait_for_requests
-
- page.within('.note-text') do
- expect(page.html).to include(expected)
+ before do
+ visit project_issue_path(project, issue)
+ wait_for_requests
end
- end
- end
-
- context 'when embedding in an MR' do
- let(:merge_request) do
- create(:merge_request, source_project: project, target_project: project, description: observable_url)
- end
- before do
- visit merge_request_path(merge_request)
- wait_for_requests
+ it_behaves_like 'embeds observability'
end
- it 'renders iframe in description' do
- page.within('.description') do
- expect(page.html).to include(expected)
+ context 'when embedding in an MR' do
+ let(:merge_request) do
+ create(:merge_request, source_project: project, target_project: project, description: observable_url)
end
- end
- it 'renders iframe in comment' do
- expect(page).not_to have_css('.note-text')
-
- page.within('.js-main-target-form') do
- fill_in('note[note]', with: observable_url)
- click_button('Comment')
+ before do
+ visit merge_request_path(merge_request)
+ wait_for_requests
end
- wait_for_requests
-
- page.within('.note-text') do
- expect(page.html).to include(expected)
- end
+ it_behaves_like 'embeds observability'
end
end
@@ -96,28 +58,7 @@ RSpec.describe 'Observability rendering', :js do
wait_for_requests
end
- it 'does not render iframe in description' do
- page.within('.description') do
- expect(page.html).not_to include(expected)
- expect(page.html).to include(observable_url)
- end
- end
-
- it 'does not render iframe in comment' do
- expect(page).not_to have_css('.note-text')
-
- page.within('.js-main-target-form') do
- fill_in('note[note]', with: observable_url)
- click_button('Comment')
- end
-
- wait_for_requests
-
- page.within('.note-text') do
- expect(page.html).not_to include(expected)
- expect(page.html).to include(observable_url)
- end
- end
+ it_behaves_like 'does not embed observability'
end
context 'when embedding in an MR' do
@@ -130,28 +71,7 @@ RSpec.describe 'Observability rendering', :js do
wait_for_requests
end
- it 'does not render iframe in description' do
- page.within('.description') do
- expect(page.html).not_to include(expected)
- expect(page.html).to include(observable_url)
- end
- end
-
- it 'does not render iframe in comment' do
- expect(page).not_to have_css('.note-text')
-
- page.within('.js-main-target-form') do
- fill_in('note[note]', with: observable_url)
- click_button('Comment')
- end
-
- wait_for_requests
-
- page.within('.note-text') do
- expect(page.html).not_to include(expected)
- expect(page.html).to include(observable_url)
- end
- end
+ it_behaves_like 'does not embed observability'
end
end
end
diff --git a/spec/features/markdown/sandboxed_mermaid_spec.rb b/spec/features/markdown/sandboxed_mermaid_spec.rb
index 0282d02d809..f8a535191da 100644
--- a/spec/features/markdown/sandboxed_mermaid_spec.rb
+++ b/spec/features/markdown/sandboxed_mermaid_spec.rb
@@ -53,4 +53,28 @@ RSpec.describe 'Sandboxed Mermaid rendering', :js, feature_category: :team_plann
end
end
end
+
+ context 'in a project milestone' do
+ let(:milestone) { create(:project_milestone, project: project, description: description) }
+
+ it 'includes mermaid frame correctly', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408560' do
+ visit(project_milestone_path(project, milestone))
+
+ wait_for_requests
+
+ expect(page.html).to include(expected)
+ end
+ end
+
+ context 'in a group milestone' do
+ let(:group_milestone) { create(:group_milestone, description: description) }
+
+ it 'includes mermaid frame correctly' do
+ visit(group_milestone_path(group_milestone.group, group_milestone))
+
+ wait_for_requests
+
+ expect(page.html).to include(expected)
+ end
+ end
end
diff --git a/spec/features/merge_request/batch_comments_spec.rb b/spec/features/merge_request/batch_comments_spec.rb
index ddbcb04fa80..6e98812753a 100644
--- a/spec/features/merge_request/batch_comments_spec.rb
+++ b/spec/features/merge_request/batch_comments_spec.rb
@@ -52,6 +52,8 @@ RSpec.describe 'Merge request > Batch comments', :js, feature_category: :code_re
find('.js-note-delete').click
+ wait_for_requests
+
page.within('.modal') do
click_button('Delete comment', match: :first)
end
@@ -66,6 +68,8 @@ RSpec.describe 'Merge request > Batch comments', :js, feature_category: :code_re
find('.js-note-edit').click
+ wait_for_requests
+
# make sure comment form is in view
execute_script("window.scrollBy(0, 200)")
diff --git a/spec/features/merge_request/maintainer_edits_fork_spec.rb b/spec/features/merge_request/maintainer_edits_fork_spec.rb
index b8dc3af8a6a..c9aa22e396b 100644
--- a/spec/features/merge_request/maintainer_edits_fork_spec.rb
+++ b/spec/features/merge_request/maintainer_edits_fork_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'a maintainer edits files on a source-branch of an MR from a fork', :js, :sidekiq_might_not_need_inline,
feature_category: :code_review_workflow do
- include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
+ include Features::SourceEditorSpecHelpers
include ProjectForksHelper
let(:user) { create(:user, username: 'the-maintainer') }
let(:target_project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_accepts_merge_request_spec.rb b/spec/features/merge_request/user_accepts_merge_request_spec.rb
index 8ff0c294b24..e3989a8a192 100644
--- a/spec/features/merge_request/user_accepts_merge_request_spec.rb
+++ b/spec/features/merge_request/user_accepts_merge_request_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe 'User accepts a merge request', :js, :sidekiq_might_not_need_inli
it 'when merge method is set to merge commit' do
visit(merge_request_path(merge_request))
- click_button('Merge')
+ click_merge_button
puts merge_request.short_merged_commit_sha
@@ -31,7 +31,7 @@ RSpec.describe 'User accepts a merge request', :js, :sidekiq_might_not_need_inli
visit(merge_request_path(merge_request))
- click_button('Merge')
+ click_merge_button
expect(page).to have_content("Changes merged into #{merge_request.target_branch} with #{merge_request.short_merged_commit_sha}")
end
@@ -41,7 +41,7 @@ RSpec.describe 'User accepts a merge request', :js, :sidekiq_might_not_need_inli
visit(merge_request_path(merge_request))
- click_button('Merge')
+ click_merge_button
expect(page).to have_content("Changes merged into #{merge_request.target_branch} with #{merge_request.short_merged_commit_sha}")
end
@@ -55,7 +55,7 @@ RSpec.describe 'User accepts a merge request', :js, :sidekiq_might_not_need_inli
it 'accepts a merge request' do
check('Delete source branch')
- click_button('Merge')
+ click_merge_button
expect(page).to have_content('Changes merged into')
expect(page).not_to have_selector('.js-remove-branch-button')
@@ -72,7 +72,7 @@ RSpec.describe 'User accepts a merge request', :js, :sidekiq_might_not_need_inli
end
it 'accepts a merge request' do
- click_button('Merge')
+ click_merge_button
expect(page).to have_content('Changes merged into')
expect(page).to have_selector('.js-remove-branch-button')
@@ -90,7 +90,7 @@ RSpec.describe 'User accepts a merge request', :js, :sidekiq_might_not_need_inli
it 'accepts a merge request' do
check('Delete source branch')
- click_button('Merge')
+ click_merge_button
expect(page).to have_content('Changes merged into')
expect(page).not_to have_selector('.js-remove-branch-button')
@@ -112,9 +112,15 @@ RSpec.describe 'User accepts a merge request', :js, :sidekiq_might_not_need_inli
find('[data-testid="widget_edit_commit_message"]').click
fill_in('merge-message-edit', with: 'wow such merge')
- click_button('Merge')
+ click_merge_button
expect(page).to have_selector('.gl-badge', text: 'Merged')
end
end
+
+ def click_merge_button
+ page.within('.mr-state-widget') do
+ click_button 'Merge'
+ end
+ end
end
diff --git a/spec/features/merge_request/user_comments_on_diff_spec.rb b/spec/features/merge_request/user_comments_on_diff_spec.rb
index 66b87148eb2..35e2fa2f89c 100644
--- a/spec/features/merge_request/user_comments_on_diff_spec.rb
+++ b/spec/features/merge_request/user_comments_on_diff_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe 'User comments on a diff', :js, feature_category: :code_review_wo
end
context 'in multiple files' do
- it 'toggles comments' do
+ it 'toggles comments', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/393518' do
first_line_element = find_by_scrolling("[id='#{sample_compare.changes[0][:line_code]}']").find(:xpath, "..")
first_root_element = first_line_element.ancestor('[data-path]')
click_diff_line(first_line_element)
@@ -248,7 +248,7 @@ RSpec.describe 'User comments on a diff', :js, feature_category: :code_review_wo
page.within('.diff-file:nth-of-type(1) .discussion .note') do
find('.more-actions').click
- find('.more-actions .dropdown-menu li', match: :first)
+ find('.more-actions li', match: :first)
find('.js-note-delete').click
end
diff --git a/spec/features/merge_request/user_comments_on_merge_request_spec.rb b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
index 9335615b4c7..e113e305af5 100644
--- a/spec/features/merge_request/user_comments_on_merge_request_spec.rb
+++ b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
@@ -30,6 +30,8 @@ RSpec.describe 'User comments on a merge request', :js, feature_category: :code_
end
end
+ it_behaves_like 'edits content using the content editor'
+
it 'replys to a new comment' do
page.within('.js-main-target-form') do
fill_in('note[note]', with: 'comment 1')
diff --git a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
index 1d7a3fae371..6d3268ffe3a 100644
--- a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
@@ -174,7 +174,7 @@ RSpec.describe 'Merge request > User creates image diff notes', :js, feature_cat
end
shared_examples 'onion skin' do
- it 'resets opacity when toggling between view modes' do
+ it 'resets opacity when toggling between view modes', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/393331' do
# Simulate dragging onion-skin slider
drag_and_drop_by(find('.dragger'), -30, 0)
diff --git a/spec/features/merge_request/user_creates_mr_spec.rb b/spec/features/merge_request/user_creates_mr_spec.rb
index 6ee20a08a47..f48315a1636 100644
--- a/spec/features/merge_request/user_creates_mr_spec.rb
+++ b/spec/features/merge_request/user_creates_mr_spec.rb
@@ -9,35 +9,158 @@ RSpec.describe 'Merge request > User creates MR', feature_category: :code_review
stub_licensed_features(multiple_merge_request_assignees: false)
end
- context 'non-fork merge request' do
- include_context 'merge request create context'
- it_behaves_like 'a creatable merge request'
- end
+ shared_examples 'a creatable merge request with visible selected labels' do
+ include WaitForRequests
+ include ListboxHelpers
+
+ it 'creates new merge request', :js do
+ find('[data-testid="assignee-ids-dropdown-toggle"]').click
+ page.within '.dropdown-menu-user' do
+ click_link user2.name
+ end
+
+ expect(find('input[name="merge_request[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s)
+ page.within '[data-testid="assignee-ids-dropdown-toggle"]' do
+ expect(page).to have_content user2.name
+ end
+
+ click_link 'Assign to me'
+
+ expect(find('input[name="merge_request[assignee_ids][]"]', visible: false).value).to match(user.id.to_s)
+ page.within '[data-testid="assignee-ids-dropdown-toggle"]' do
+ expect(page).to have_content user.name
+ end
+
+ click_button 'Select milestone'
+ click_button milestone.title
+ expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
+ expect(page).to have_button milestone.title
+
+ click_button _('Select label')
+ wait_for_all_requests
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label.title
+ click_button label2.title
+ click_button _('Close')
+ wait_for_requests
+ page.within('[data-testid="embedded-labels-list"]') do
+ expect(page).to have_content(label.title)
+ expect(page).to have_content(label2.title)
+ end
+ end
+
+ click_button 'Create merge request'
+
+ page.within '.issuable-sidebar' do
+ page.within '.assignee' do
+ expect(page).to have_content user.name
+ end
- context 'from a forked project' do
- let(:canonical_project) { create(:project, :public, :repository) }
+ page.within '.milestone' do
+ expect(page).to have_content milestone.title
+ end
- let(:source_project) do
- fork_project(canonical_project, user,
- repository: true,
- namespace: user.namespace)
+ page.within '.labels' do
+ expect(page).to have_content label.title
+ expect(page).to have_content label2.title
+ end
+ end
end
- context 'to canonical project' do
+ it 'updates the branches when selecting a new target project', :js do
+ target_project_member = target_project.first_owner
+ ::Branches::CreateService.new(target_project, target_project_member)
+ .execute('a-brand-new-branch-to-test', 'master')
+
+ visit project_new_merge_request_path(source_project)
+
+ first('.js-target-project').click
+ select_listbox_item(target_project.full_path)
+
+ wait_for_requests
+
+ first('.js-target-branch').click
+
+ find('.gl-listbox-search-input').set('a-brand-new-branch-to-test')
+
+ wait_for_requests
+
+ expect_listbox_item('a-brand-new-branch-to-test')
+ end
+ end
+
+ context 'with the visible_label_selection_on_metadata feature flag enabled' do
+ before do
+ stub_feature_flags(visible_label_selection_on_metadata: true)
+ end
+
+ context 'non-fork merge request' do
include_context 'merge request create context'
- it_behaves_like 'a creatable merge request'
+ it_behaves_like 'a creatable merge request with visible selected labels'
end
- context 'to another forked project' do
- let(:target_project) do
+ context 'from a forked project' do
+ let(:canonical_project) { create(:project, :public, :repository) }
+
+ let(:source_project) do
fork_project(canonical_project, user,
repository: true,
namespace: user.namespace)
end
+ context 'to canonical project' do
+ include_context 'merge request create context'
+ it_behaves_like 'a creatable merge request with visible selected labels'
+ end
+
+ context 'to another forked project' do
+ let(:target_project) do
+ fork_project(canonical_project, user,
+ repository: true,
+ namespace: user.namespace)
+ end
+
+ include_context 'merge request create context'
+ it_behaves_like 'a creatable merge request with visible selected labels'
+ end
+ end
+ end
+
+ context 'with the visible_label_selection_on_metadata feature flag disabled' do
+ before do
+ stub_feature_flags(visible_label_selection_on_metadata: false)
+ end
+
+ context 'non-fork merge request' do
include_context 'merge request create context'
it_behaves_like 'a creatable merge request'
end
+
+ context 'from a forked project' do
+ let(:canonical_project) { create(:project, :public, :repository) }
+
+ let(:source_project) do
+ fork_project(canonical_project, user,
+ repository: true,
+ namespace: user.namespace)
+ end
+
+ context 'to canonical project' do
+ include_context 'merge request create context'
+ it_behaves_like 'a creatable merge request'
+ end
+
+ context 'to another forked project' do
+ let(:target_project) do
+ fork_project(canonical_project, user,
+ repository: true,
+ namespace: user.namespace)
+ end
+
+ include_context 'merge request create context'
+ it_behaves_like 'a creatable merge request'
+ end
+ end
end
context 'source project', :js do
diff --git a/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb b/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
index cf5024ad59e..faef4f6f517 100644
--- a/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
+++ b/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Merge request > User edits assignees sidebar', :js, feature_category: :code_review_workflow do
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::InviteMembersModalHelpers
let(:project) { create(:project, :public, :repository) }
let(:protected_branch) { create(:protected_branch, :maintainers_can_push, name: 'master', project: project) }
@@ -162,8 +162,6 @@ RSpec.describe 'Merge request > User edits assignees sidebar', :js, feature_cate
page.within '.dropdown-menu-user' do
expect(page).to have_link('Invite members')
- expect(page).to have_selector('[data-track-action="click_invite_members"]')
- expect(page).to have_selector('[data-track-label="edit_assignee"]')
click_link 'Invite members'
end
diff --git a/spec/features/merge_request/user_edits_merge_request_spec.rb b/spec/features/merge_request/user_edits_merge_request_spec.rb
index 839081d00dc..584a17ae33d 100644
--- a/spec/features/merge_request/user_edits_merge_request_spec.rb
+++ b/spec/features/merge_request/user_edits_merge_request_spec.rb
@@ -108,4 +108,6 @@ RSpec.describe 'User edits a merge request', :js, feature_category: :code_review
end
end
end
+
+ it_behaves_like 'edits content using the content editor'
end
diff --git a/spec/features/merge_request/user_edits_mr_spec.rb b/spec/features/merge_request/user_edits_mr_spec.rb
index 6fcbfd309e2..76588832ee1 100644
--- a/spec/features/merge_request/user_edits_mr_spec.rb
+++ b/spec/features/merge_request/user_edits_mr_spec.rb
@@ -5,19 +5,233 @@ require 'spec_helper'
RSpec.describe 'Merge request > User edits MR', feature_category: :code_review_workflow do
include ProjectForksHelper
+ shared_examples 'an editable merge request with visible selected labels' do
+ it 'updates merge request', :js do
+ find('.js-assignee-search').click
+ page.within '.dropdown-menu-user' do
+ click_link user.name
+ end
+ expect(find('input[name="merge_request[assignee_ids][]"]', visible: false).value).to match(user.id.to_s)
+ page.within '.js-assignee-search' do
+ expect(page).to have_content user.name
+ end
+
+ find('.js-reviewer-search').click
+ page.within '.dropdown-menu-user' do
+ click_link user.name
+ end
+ expect(find('input[name="merge_request[reviewer_ids][]"]', visible: false).value).to match(user.id.to_s)
+ page.within '.js-reviewer-search' do
+ expect(page).to have_content user.name
+ end
+
+ click_button 'Select milestone'
+ click_button milestone.title
+ expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
+ expect(page).to have_button milestone.title
+
+ click_button _('Select label')
+ wait_for_all_requests
+ page.within '[data-testid="sidebar-labels"]' do
+ click_button label.title
+ click_button label2.title
+ click_button _('Close')
+ wait_for_requests
+ page.within('[data-testid="embedded-labels-list"]') do
+ expect(page).to have_content(label.title)
+ expect(page).to have_content(label2.title)
+ end
+ end
+
+ click_button 'Save changes'
+
+ page.within '.issuable-sidebar' do
+ page.within '.assignee' do
+ expect(page).to have_content user.name
+ end
+
+ page.within '.reviewer' do
+ expect(page).to have_content user.name
+ end
+
+ page.within '.milestone' do
+ expect(page).to have_content milestone.title
+ end
+
+ page.within '.labels' do
+ expect(page).to have_content label.title
+ expect(page).to have_content label2.title
+ end
+ end
+ end
+
+ it 'description has autocomplete', :js do
+ find('#merge_request_description').native.send_keys('')
+ fill_in 'merge_request_description', with: user.to_reference[0..4]
+
+ page.within('.atwho-view') do
+ expect(page).to have_content(user2.name)
+ end
+ end
+
+ it 'description has quick action autocomplete', :js do
+ find('#merge_request_description').native.send_keys('/')
+
+ expect(page).to have_selector('.atwho-container')
+ end
+
+ it 'has class js-quick-submit in form' do
+ expect(page).to have_selector('.js-quick-submit')
+ end
+
+ it 'warns about version conflict', :js do
+ merge_request.update!(title: "New title")
+
+ fill_in 'merge_request_title', with: 'bug 345'
+ fill_in 'merge_request_description', with: 'bug description'
+
+ click_button _('Save changes')
+
+ expect(page).to have_content(
+ format(
+ _("Someone edited this %{model_name} at the same time you did. Please check out the %{link_to_model} and make sure your changes will not unintentionally remove theirs."), # rubocop:disable Layout/LineLength
+ model_name: _('merge request'),
+ link_to_model: _('merge request')
+ )
+ )
+ end
+
+ it 'preserves description textarea height', :js do
+ long_description = %q(
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ Etiam ac ornare ligula, ut tempus arcu.
+ Etiam ultricies accumsan dolor vitae faucibus.
+ Donec at elit lacus.
+ Mauris orci ante, aliquam quis lorem eget, convallis faucibus arcu.
+ Aenean at pulvinar lacus.
+ Ut viverra quam massa, molestie ornare tortor dignissim a.
+ Suspendisse tristique pellentesque tellus, id lacinia metus elementum id.
+ Nam tristique, arcu rhoncus faucibus viverra, lacus ipsum sagittis ligula, vitae convallis odio lacus a nibh.
+ Ut tincidunt est purus, ac vestibulum augue maximus in.
+ Suspendisse vel erat et mi ultricies semper.
+ Pellentesque volutpat pellentesque consequat.
+
+ Cras congue nec ligula tristique viverra.
+ Curabitur fringilla fringilla fringilla.
+ Donec rhoncus dignissim orci ut accumsan.
+ Ut rutrum urna a rhoncus varius.
+ Maecenas blandit, mauris nec accumsan gravida, augue nibh finibus magna, sed maximus turpis libero nec neque
+ Suspendisse at semper est.
+ Nunc imperdiet dapibus dui, varius sollicitudin erat luctus non.
+ Sed pellentesque ligula eget posuere facilisis.
+ Donec dictum commodo volutpat.
+ Donec egestas dui ac magna sollicitudin bibendum.
+ Vivamus purus neque, ullamcorper ac feugiat et, tempus sit amet metus.
+ Praesent quis viverra neque.
+ Sed bibendum viverra est, eu aliquam mi ornare vitae.
+ Proin et dapibus ipsum.
+ Nunc tortor diam, malesuada nec interdum vel, placerat quis justo.
+ Ut viverra at erat eu laoreet.
+
+ Pellentesque commodo, diam sit amet dignissim condimentum, tortor justo pretium est,
+ non venenatis metus eros ut nunc.
+ Etiam ut neque eget sem dapibus aliquam.
+ Curabitur vel elit lorem.
+ Nulla nec enim elit.
+ Sed ut ex id justo facilisis convallis at ac augue.
+ Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+ Nullam cursus egestas turpis non tristique.
+ Suspendisse in erat sem.
+ Fusce libero elit, fermentum gravida mauris id, auctor iaculis felis.
+ Nullam vulputate tempor laoreet.
+
+ Nam tempor et magna sed convallis.
+ Fusce sit amet sollicitudin risus, a ullamcorper lacus.
+ Morbi gravida quis sem eget porttitor.
+ Donec eu egestas mauris, in elementum tortor.
+ Sed eget ex mi.
+ Mauris iaculis tortor ut est auctor, nec dignissim quam sagittis.
+ Suspendisse vel metus non quam suscipit tincidunt.
+ Cras molestie lacus non justo finibus sodales quis vitae erat.
+ In a porttitor nisi, id sollicitudin urna.
+ Ut at felis tellus.
+ Suspendisse potenti.
+
+ Maecenas leo ligula, varius at neque vitae, ornare maximus justo.
+ Nullam convallis luctus risus et vulputate.
+ Duis suscipit faucibus iaculis.
+ Etiam quis tortor faucibus, tristique tellus sit amet, sodales neque.
+ Nulla dapibus nisi vel aliquet consequat.
+ Etiam faucibus, metus eget condimentum iaculis, enim urna lobortis sem, id efficitur eros sapien nec nisi.
+ Aenean ut finibus ex.
+ )
+
+ fill_in 'merge_request_description', with: long_description
+
+ height = get_textarea_height
+ click_button("Preview")
+ click_button("Continue editing")
+ new_height = get_textarea_height
+
+ expect(height).to eq(new_height)
+ end
+
+ context 'when "Remove source branch" is set' do
+ before do
+ merge_request.update!(merge_params: { 'force_remove_source_branch' => '1' })
+ end
+
+ it 'allows to unselect "Remove source branch"', :js do
+ expect(merge_request.merge_params['force_remove_source_branch']).to be_truthy
+
+ visit edit_project_merge_request_path(target_project, merge_request)
+ uncheck 'Delete source branch when merge request is accepted'
+
+ click_button 'Save changes'
+
+ expect(page).to have_unchecked_field 'remove-source-branch-input'
+ expect(page).to have_content 'Delete source branch'
+ end
+ end
+ end
+
before do
stub_licensed_features(multiple_merge_request_assignees: false)
end
- context 'non-fork merge request' do
- include_context 'merge request edit context'
- it_behaves_like 'an editable merge request'
+ context 'with the visible_label_selection_on_metadata feature flag enabled' do
+ before do
+ stub_feature_flags(visible_label_selection_on_metadata: true)
+ end
+
+ context 'non-fork merge request' do
+ include_context 'merge request edit context'
+ it_behaves_like 'an editable merge request with visible selected labels'
+ end
+
+ context 'for a forked project' do
+ let(:source_project) { fork_project(target_project, nil, repository: true) }
+
+ include_context 'merge request edit context'
+ it_behaves_like 'an editable merge request with visible selected labels'
+ end
end
- context 'for a forked project' do
- let(:source_project) { fork_project(target_project, nil, repository: true) }
+ context 'with the visible_label_selection_on_metadata feature flag disabled' do
+ before do
+ stub_feature_flags(visible_label_selection_on_metadata: false)
+ end
+
+ context 'non-fork merge request' do
+ include_context 'merge request edit context'
+ it_behaves_like 'an editable merge request'
+ end
+
+ context 'for a forked project' do
+ let(:source_project) { fork_project(target_project, nil, repository: true) }
- include_context 'merge request edit context'
- it_behaves_like 'an editable merge request'
+ include_context 'merge request edit context'
+ it_behaves_like 'an editable merge request'
+ end
end
end
diff --git a/spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb b/spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb
index 26a9b955e2d..52d058aeabc 100644
--- a/spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb
+++ b/spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb
@@ -26,8 +26,6 @@ RSpec.describe 'Merge request > User edits reviewers sidebar', :js, feature_cate
page.within '.dropdown-menu-user' do
expect(page).to have_link('Invite Members')
- expect(page).to have_selector('[data-track-action="click_invite_members"]')
- expect(page).to have_selector('[data-track-label="edit_reviewer"]')
end
click_link 'Invite Members'
diff --git a/spec/features/merge_request/user_manages_subscription_spec.rb b/spec/features/merge_request/user_manages_subscription_spec.rb
index d4ccc4a93b5..3bcc8255ab7 100644
--- a/spec/features/merge_request/user_manages_subscription_spec.rb
+++ b/spec/features/merge_request/user_manages_subscription_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'User manages subscription', :js, feature_category: :code_review_workflow do
+ include CookieHelper
+
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:user) { create(:user) }
@@ -10,7 +12,7 @@ RSpec.describe 'User manages subscription', :js, feature_category: :code_review_
before do
stub_feature_flags(moved_mr_sidebar: moved_mr_sidebar_enabled)
-
+ set_cookie('new-actions-popover-viewed', 'true')
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb
index cdc00017ab3..19b5ad0fa84 100644
--- a/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb
+++ b/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb
@@ -13,11 +13,29 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js, fea
context 'project does not have CI enabled' do
it 'allows MR to be merged' do
+ stub_feature_flags(auto_merge_labels_mr_widget: false)
+
visit project_merge_request_path(project, merge_request)
wait_for_requests
- expect(page).to have_button 'Merge'
+ page.within('.mr-state-widget') do
+ expect(page).to have_button 'Merge'
+ end
+ end
+ end
+
+ context 'project does not have CI enabled and auto_merge_labels_mr_widget on' do
+ it 'allows MR to be merged' do
+ stub_feature_flags(auto_merge_labels_mr_widget: true)
+
+ visit project_merge_request_path(project, merge_request)
+
+ wait_for_requests
+
+ page.within('.mr-state-widget') do
+ expect(page).to have_button 'Merge'
+ end
end
end
@@ -33,6 +51,8 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js, fea
context 'when merge requests can only be merged if the pipeline succeeds' do
before do
project.update_attribute(:only_allow_merge_if_pipeline_succeeds, true)
+
+ stub_feature_flags(auto_merge_labels_mr_widget: false)
end
context 'when CI is running' do
@@ -56,7 +76,78 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js, fea
wait_for_requests
- expect(page).not_to have_button('Merge')
+ expect(page).not_to have_button('Merge', exact: true)
+ expect(page).to have_content('Merge blocked: pipeline must succeed. Push a commit that fixes the failure or learn about other solutions.')
+ end
+ end
+
+ context 'when CI canceled' do
+ let(:status) { :canceled }
+
+ it 'does not allow MR to be merged' do
+ visit project_merge_request_path(project, merge_request)
+
+ wait_for_requests
+
+ expect(page).not_to have_button('Merge', exact: true)
+ expect(page).to have_content('Merge blocked: pipeline must succeed. Push a commit that fixes the failure or learn about other solutions.')
+ end
+ end
+
+ context 'when CI succeeded' do
+ let(:status) { :success }
+
+ it 'allows MR to be merged' do
+ visit project_merge_request_path(project, merge_request)
+
+ wait_for_requests
+
+ expect(page).to have_button('Merge', exact: true)
+ end
+ end
+
+ context 'when CI skipped' do
+ let(:status) { :skipped }
+
+ it 'does not allow MR to be merged' do
+ visit project_merge_request_path(project, merge_request)
+
+ wait_for_requests
+
+ expect(page).not_to have_button('Merge', exact: true)
+ end
+ end
+ end
+
+ context 'when merge requests can only be merged if the pipeline succeeds with auto_merge_labels_mr_widget on' do
+ before do
+ project.update_attribute(:only_allow_merge_if_pipeline_succeeds, true)
+
+ stub_feature_flags(auto_merge_labels_mr_widget: true)
+ end
+
+ context 'when CI is running' do
+ let(:status) { :running }
+
+ it 'does not allow to merge immediately' do
+ visit project_merge_request_path(project, merge_request)
+
+ wait_for_requests
+
+ expect(page).to have_button 'Set to auto-merge'
+ expect(page).not_to have_button '.js-merge-moment'
+ end
+ end
+
+ context 'when CI failed' do
+ let(:status) { :failed }
+
+ it 'does not allow MR to be merged' do
+ visit project_merge_request_path(project, merge_request)
+
+ wait_for_requests
+
+ expect(page).not_to have_button('Merge', exact: true)
expect(page).to have_content('Merge blocked: pipeline must succeed. Push a commit that fixes the failure or learn about other solutions.')
end
end
@@ -69,7 +160,7 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js, fea
wait_for_requests
- expect(page).not_to have_button 'Merge'
+ expect(page).not_to have_button('Merge', exact: true)
expect(page).to have_content('Merge blocked: pipeline must succeed. Push a commit that fixes the failure or learn about other solutions.')
end
end
@@ -82,7 +173,7 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js, fea
wait_for_requests
- expect(page).to have_button 'Merge'
+ expect(page).to have_button('Merge', exact: true)
end
end
@@ -94,7 +185,7 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js, fea
wait_for_requests
- expect(page).not_to have_button 'Merge'
+ expect(page).not_to have_button('Merge', exact: true)
end
end
end
@@ -102,6 +193,8 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js, fea
context 'when merge requests can be merged when the build failed' do
before do
project.update_attribute(:only_allow_merge_if_pipeline_succeeds, false)
+
+ stub_feature_flags(auto_merge_labels_mr_widget: false)
end
context 'when CI is running' do
@@ -126,8 +219,59 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js, fea
visit project_merge_request_path(project, merge_request)
wait_for_requests
+ page.within('.mr-state-widget') do
+ expect(page).to have_button 'Merge'
+ end
+ end
+ end
- expect(page).to have_button 'Merge'
+ context 'when CI succeeded' do
+ let(:status) { :success }
+
+ it 'allows MR to be merged' do
+ visit project_merge_request_path(project, merge_request)
+
+ wait_for_requests
+
+ page.within('.mr-state-widget') do
+ expect(page).to have_button 'Merge'
+ end
+ end
+ end
+ end
+
+ context 'when merge requests can be merged when the build failed with auto_merge_labels_mr_widget on' do
+ before do
+ project.update_attribute(:only_allow_merge_if_pipeline_succeeds, false)
+
+ stub_feature_flags(auto_merge_labels_mr_widget: true)
+ end
+
+ context 'when CI is running' do
+ let(:status) { :running }
+
+ it 'allows MR to be merged immediately' do
+ visit project_merge_request_path(project, merge_request)
+
+ wait_for_requests
+
+ expect(page).to have_button 'Set to auto-merge'
+
+ page.find('.js-merge-moment').click
+ expect(page).to have_content 'Merge immediately'
+ end
+ end
+
+ context 'when CI failed' do
+ let(:status) { :failed }
+
+ it 'allows MR to be merged' do
+ visit project_merge_request_path(project, merge_request)
+
+ wait_for_requests
+ page.within('.mr-state-widget') do
+ expect(page).to have_button 'Merge'
+ end
end
end
@@ -139,7 +283,9 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js, fea
wait_for_requests
- expect(page).to have_button 'Merge'
+ page.within('.mr-state-widget') do
+ expect(page).to have_button 'Merge'
+ end
end
end
end
diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
index 6d2c8f15a82..5c00da1f569 100644
--- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
+++ b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
@@ -26,13 +26,15 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js, featur
context 'when there is active pipeline for merge request' do
before do
create(:ci_build, pipeline: pipeline)
+ stub_feature_flags(auto_merge_labels_mr_widget: false)
+
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
describe 'enabling Merge when pipeline succeeds' do
shared_examples 'Merge when pipeline succeeds activator' do
- it 'activates the Merge when pipeline succeeds feature' do
+ it 'activates the Merge when pipeline succeeds feature', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410105' do
click_button "Merge when pipeline succeeds"
expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds"
@@ -98,6 +100,69 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js, featur
end
end
+ context 'when there is active pipeline for merge request with auto_merge_labels_mr_widget on' do
+ before do
+ create(:ci_build, pipeline: pipeline)
+ stub_feature_flags(auto_merge_labels_mr_widget: true)
+
+ sign_in(user)
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ describe 'enabling Merge when pipeline succeeds' do
+ shared_examples 'Set to auto-merge activator' do
+ it 'activates the Merge when pipeline succeeds feature' do
+ click_button "Set to auto-merge"
+
+ expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds"
+ expect(page).to have_content "Source branch will not be deleted"
+ expect(page).to have_selector ".js-cancel-auto-merge"
+ visit project_merge_request_path(project, merge_request) # Needed to refresh the page
+ expect(page).to have_content /enabled an automatic merge when the pipeline for \h{8} succeeds/i
+ end
+ end
+
+ context "when enabled immediately" do
+ it_behaves_like 'Set to auto-merge activator'
+ end
+
+ context 'when enabled after it was previously canceled' do
+ before do
+ click_button "Set to auto-merge"
+
+ wait_for_requests
+
+ click_button "Cancel auto-merge"
+
+ wait_for_requests
+
+ expect(page).to have_content 'Set to auto-merge'
+ end
+
+ it_behaves_like 'Set to auto-merge activator'
+ end
+
+ context 'when it was enabled and then canceled' do
+ let(:merge_request) do
+ create(:merge_request_with_diffs,
+ :merge_when_pipeline_succeeds,
+ source_project: project,
+ title: 'Bug NS-04',
+ author: user,
+ merge_user: user)
+ end
+
+ before do
+ merge_request.merge_params['force_remove_source_branch'] = '0'
+ merge_request.save!
+ click_button "Cancel auto-merge"
+ end
+
+ it_behaves_like 'Set to auto-merge activator'
+ end
+ end
+ end
+
context 'when merge when pipeline succeeds is enabled' do
let(:merge_request) do
create(:merge_request_with_diffs, :simple, :merge_when_pipeline_succeeds,
@@ -112,6 +177,7 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js, featur
end
before do
+ stub_feature_flags(auto_merge_labels_mr_widget: false)
sign_in user
visit project_merge_request_path(project, merge_request)
end
@@ -177,11 +243,53 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js, featur
end
end
+ context 'when merge when pipeline succeeds is enabled and auto_merge_labels_mr_widget on' do
+ let(:merge_request) do
+ create(:merge_request_with_diffs, :simple, :merge_when_pipeline_succeeds,
+ source_project: project,
+ author: user,
+ merge_user: user,
+ title: 'MepMep')
+ end
+
+ let!(:build) do
+ create(:ci_build, pipeline: pipeline)
+ end
+
+ before do
+ stub_feature_flags(auto_merge_labels_mr_widget: true)
+ sign_in user
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'allows to cancel the automatic merge', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410494' do
+ click_button "Cancel auto-merge"
+
+ expect(page).to have_button "Set to auto-merge"
+
+ refresh
+
+ expect(page).to have_content "canceled the automatic merge"
+ end
+ end
+
context 'when pipeline is not active' do
it 'does not allow to enable merge when pipeline succeeds' do
+ stub_feature_flags(auto_merge_labels_mr_widget: false)
+
visit project_merge_request_path(project, merge_request)
expect(page).not_to have_link 'Merge when pipeline succeeds'
end
end
+
+ context 'when pipeline is not active and auto_merge_labels_mr_widget on' do
+ it 'does not allow to enable merge when pipeline succeeds' do
+ stub_feature_flags(auto_merge_labels_mr_widget: true)
+
+ visit project_merge_request_path(project, merge_request)
+
+ expect(page).not_to have_link 'Set to auto-merge'
+ end
+ end
end
diff --git a/spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb b/spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb
index 7cb1c95f6dc..601310cbacf 100644
--- a/spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb
+++ b/spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Merge request > User opens checkout branch modal', :js, feature_category: :code_review_workflow do
include ProjectForksHelper
+ include CookieHelper
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
@@ -11,6 +12,7 @@ RSpec.describe 'Merge request > User opens checkout branch modal', :js, feature_
before do
project.add_maintainer(user)
sign_in(user)
+ set_cookie('new-actions-popover-viewed', 'true')
end
describe 'for fork' do
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 a74a8b1cd5a..f13c68a60ee 100644
--- a/spec/features/merge_request/user_posts_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb
@@ -103,7 +103,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js, feature_category: :
should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
accept_gl_confirm(button_text: 'Delete comment') do
- first('button.more-actions-toggle').click
+ first('.more-actions-toggle button').click
first('.js-note-delete').click
end
diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb
index f167ab8fe8a..03b01ef4b7a 100644
--- a/spec/features/merge_request/user_posts_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_notes_spec.rb
@@ -62,7 +62,7 @@ RSpec.describe 'Merge request > User posts notes', :js, feature_category: :code_
before do
page.within('.js-main-target-form') do
fill_in 'note[note]', with: 'This is awesome!'
- find('.js-md-preview-button').click
+ click_button("Preview")
click_button 'Comment'
end
end
@@ -138,7 +138,7 @@ RSpec.describe 'Merge request > User posts notes', :js, feature_category: :code_
it 'hides the toolbar buttons when previewing a note' do
wait_for_requests
- find('.js-md-preview-button').click
+ click_button("Preview")
page.within('.js-main-target-form') do
expect(page).not_to have_css('.md-header-toolbar')
end
diff --git a/spec/features/merge_request/user_resolves_conflicts_spec.rb b/spec/features/merge_request/user_resolves_conflicts_spec.rb
index 7b1afd786f7..0f283f1194f 100644
--- a/spec/features/merge_request/user_resolves_conflicts_spec.rb
+++ b/spec/features/merge_request/user_resolves_conflicts_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Merge request > User resolves conflicts', :js, feature_category: :code_review_workflow do
- include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
+ include Features::SourceEditorSpecHelpers
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
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 c3b9068d708..5da9f4a1f19 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
@@ -218,7 +218,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js, feat
end
end
- it 'allows user to quickly scroll to next unresolved thread' do
+ it 'allows user to quickly scroll to next unresolved thread', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410109' do
page.within '.discussions-counter' do
page.find('.discussion-next-btn').click
end
diff --git a/spec/features/merge_request/user_reverts_merge_request_spec.rb b/spec/features/merge_request/user_reverts_merge_request_spec.rb
index 43ce473b407..8c782056aa4 100644
--- a/spec/features/merge_request/user_reverts_merge_request_spec.rb
+++ b/spec/features/merge_request/user_reverts_merge_request_spec.rb
@@ -8,12 +8,15 @@ RSpec.describe 'User reverts a merge request', :js, feature_category: :code_revi
let(:user) { create(:user) }
before do
+ stub_feature_flags(unbatch_graphql_queries: false)
project.add_developer(user)
sign_in(user)
visit(merge_request_path(merge_request))
- click_button('Merge')
+ page.within('.mr-state-widget') do
+ click_button 'Merge'
+ end
wait_for_requests
@@ -34,7 +37,7 @@ RSpec.describe 'User reverts a merge request', :js, feature_category: :code_revi
revert_commit
- expect(page).to have_content('Sorry, we cannot revert this merge request automatically.')
+ expect(page).to have_content('Merge request revert failed:')
end
it 'reverts a merge request in a new merge request', :sidekiq_might_not_need_inline do
diff --git a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb
index ad2ceeb23e2..21c62b0d0d8 100644
--- a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb
+++ b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Merge request > User sees check out branch modal', :js, feature_category: :code_review_workflow do
+ include CookieHelper
+
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project) }
@@ -10,6 +12,7 @@ RSpec.describe 'Merge request > User sees check out branch modal', :js, feature_
before do
sign_in(user)
+ set_cookie('new-actions-popover-viewed', 'true')
visit project_merge_request_path(project, merge_request)
wait_for_requests
diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb
index 12fdcf4859e..3fb3ef12fcc 100644
--- a/spec/features/merge_request/user_sees_diff_spec.rb
+++ b/spec/features/merge_request/user_sees_diff_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe 'Merge request > User sees diff', :js, feature_category: :code_re
visit diffs_project_merge_request_path(project, merge_request)
page.within('.gl-alert') do
- expect(page).to have_text("Too many changes to show. To preserve performance only 3 of 3+ files are displayed. Plain diff Email patch")
+ expect(page).to have_text("Some changes are not shown. For a faster browsing experience, only 3 of 3+ files are shown. Download one of the files below to see all changes. Plain diff Patches")
end
end
end
diff --git a/spec/features/merge_request/user_sees_discussions_navigation_spec.rb b/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
index 6e6c2cddfbf..5f815bffb22 100644
--- a/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
+++ b/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
@@ -2,7 +2,9 @@
require 'spec_helper'
-RSpec.describe 'Merge request > User sees discussions navigation', :js, feature_category: :code_review_workflow do
+RSpec.describe 'Merge request > User sees discussions navigation',
+ :js, feature_category: :code_review_workflow,
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410678' do
let_it_be(:project) { create(:project, :public, :repository) }
let_it_be(:user) { project.creator }
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
@@ -42,7 +44,7 @@ RSpec.describe 'Merge request > User sees discussions navigation', :js, feature_
shared_examples 'a page with a thread navigation' do
context 'with active threads' do
- it 'navigates to the first thread' do
+ it 'navigates to the first thread', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410144' do
goto_next_thread
expect(page).to have_selector(first_discussion_selector, obscured: false)
end
@@ -52,7 +54,7 @@ RSpec.describe 'Merge request > User sees discussions navigation', :js, feature_
expect(page).to have_selector(second_discussion_selector, obscured: false)
end
- it 'navigates through active threads' do
+ it 'navigates through active threads', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391912' do
goto_next_thread
goto_next_thread
expect(page).to have_selector(second_discussion_selector, obscured: false)
diff --git a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb
index b83580565e4..476be5ab599 100644
--- a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb
@@ -21,7 +21,7 @@ feature_category: :code_review_workflow do
context 'with unresolved threads' do
it 'does not allow to merge' do
- expect(page).not_to have_button 'Merge'
+ expect(page).not_to have_button('Merge', exact: true)
expect(page).to have_content('all threads must be resolved')
end
end
@@ -33,7 +33,7 @@ feature_category: :code_review_workflow do
end
it 'allows MR to be merged' do
- expect(page).to have_button 'Merge'
+ expect(page).to have_button('Merge', exact: true)
end
end
end
@@ -46,7 +46,7 @@ feature_category: :code_review_workflow do
context 'with unresolved threads' do
it 'does not allow to merge' do
- expect(page).to have_button 'Merge'
+ expect(page).to have_button('Merge', exact: true)
end
end
@@ -57,7 +57,7 @@ feature_category: :code_review_workflow do
end
it 'allows MR to be merged' do
- expect(page).to have_button 'Merge'
+ expect(page).to have_button('Merge', exact: true)
end
end
end
diff --git a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
index 458746f0854..7d024103943 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
@@ -56,6 +56,8 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
end
before do
+ stub_feature_flags(auto_merge_labels_mr_widget: false)
+
visit project_merge_request_path(project, merge_request)
page.within('.merge-request-tabs') do
@@ -185,6 +187,48 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
end
end
+ context 'when a user created a merge request in the parent project with auto_merge_labels_mr_widget on' do
+ before do
+ stub_feature_flags(auto_merge_labels_mr_widget: true)
+
+ visit project_merge_request_path(project, merge_request)
+
+ page.within('.merge-request-tabs') do
+ click_link('Pipelines')
+ end
+ end
+
+ context 'when a user merges a merge request in the parent project', :sidekiq_might_not_need_inline do
+ before do
+ click_link 'Overview'
+ click_button 'Set to auto-merge'
+
+ wait_for_requests
+ end
+
+ context 'when detached merge request pipeline is pending' do
+ it 'waits the head pipeline' do
+ expect(page).to have_content('to be merged automatically when the pipeline succeeds')
+ expect(page).to have_button('Cancel auto-merge')
+ end
+ end
+
+ context 'when branch pipeline succeeds' do
+ before do
+ click_link 'Overview'
+ push_pipeline.reload.succeed!
+
+ wait_for_requests
+ end
+
+ it 'waits the head pipeline' do
+ expect(page).to have_content('to be merged automatically when the pipeline succeeds')
+ expect(page).to have_button('Cancel auto-merge')
+ end
+ end
+ end
+ end
+
context 'when there are no `merge_requests` keyword in .gitlab-ci.yml' do
let(:config) do
{
@@ -244,6 +288,8 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
before do
forked_project.add_maintainer(user2)
+ stub_feature_flags(auto_merge_labels_mr_widget: false)
+
visit project_merge_request_path(project, merge_request)
page.within('.merge-request-tabs') do
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 acf2893b513..cb56e79fcc0 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -53,6 +53,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
let!(:deployment) { build.deployment }
before do
+ stub_feature_flags(unbatch_graphql_queries: false)
merge_request.update!(head_pipeline: pipeline)
deployment.update!(status: :success)
visit project_merge_request_path(project, merge_request)
@@ -396,7 +397,9 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
end
it 'updates the MR widget', :sidekiq_might_not_need_inline do
- click_button 'Merge'
+ page.within('.mr-state-widget') do
+ click_button 'Merge'
+ end
expect(page).to have_content('An error occurred while merging')
end
@@ -452,7 +455,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
wait_for_requests
- expect(page).not_to have_button('Merge')
+ expect(page).not_to have_button('Merge', exact: true)
expect(page).to have_content('Merging!')
end
end
diff --git a/spec/features/merge_request/user_sees_pipelines_spec.rb b/spec/features/merge_request/user_sees_pipelines_spec.rb
index cab940ba704..f92ce3865a9 100644
--- a/spec/features/merge_request/user_sees_pipelines_spec.rb
+++ b/spec/features/merge_request/user_sees_pipelines_spec.rb
@@ -15,27 +15,40 @@ RSpec.describe 'Merge request > User sees pipelines', :js, feature_category: :co
context 'with pipelines' do
let!(:pipeline) do
- create(:ci_empty_pipeline,
+ create(:ci_pipeline,
+ :success,
project: merge_request.source_project,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha)
end
+ let!(:manual_job) { create(:ci_build, :manual, name: 'job1', stage: 'deploy', pipeline: pipeline) }
+
+ let!(:job) { create(:ci_build, :success, name: 'job2', stage: 'test', pipeline: pipeline) }
+
before do
merge_request.update_attribute(:head_pipeline_id, pipeline.id)
end
- it 'user visits merge request pipelines tab' do
+ it 'pipelines table displays correctly' do
visit project_merge_request_path(project, merge_request)
- expect(page.find('.ci-widget')).to have_content('pending')
+ expect(page.find('.ci-widget')).to have_content('passed')
page.within('.merge-request-tabs') do
click_link('Pipelines')
end
+
wait_for_requests
- expect(page).to have_css('[data-testid="pipeline-mini-graph"]')
+ page.within('[data-testid="pipeline-table-row"]') do
+ expect(page).to have_selector('.ci-success')
+ expect(page).to have_content(pipeline.id)
+ expect(page).to have_content('API')
+ expect(page).to have_css('[data-testid="pipeline-mini-graph"]')
+ expect(page).to have_css('[data-testid="pipelines-manual-actions-dropdown"]')
+ expect(page).to have_css('[data-testid="pipeline-multi-actions-dropdown"]')
+ end
end
context 'with a detached merge request pipeline' do
diff --git a/spec/features/merge_request/user_sees_real_time_reviewers_spec.rb b/spec/features/merge_request/user_sees_real_time_reviewers_spec.rb
new file mode 100644
index 00000000000..e967787d2c7
--- /dev/null
+++ b/spec/features/merge_request/user_sees_real_time_reviewers_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge request > Real-time reviewers', feature_category: :code_review_workflow do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let(:user) { project.creator }
+ let(:merge_request) { create(:merge_request, :simple, source_project: project, author: user) }
+
+ before do
+ sign_in(user)
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'updates in real-time', :js do
+ wait_for_requests
+
+ # Simulate a real-time update of reviewers
+ merge_request.update!(reviewer_ids: [user.id])
+ GraphqlTriggers.merge_request_reviewers_updated(merge_request)
+
+ expect(find('.reviewer')).to have_content(user.name)
+ end
+end
diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb
index f94b288300a..91f8fd13681 100644
--- a/spec/features/merge_request/user_sees_versions_spec.rb
+++ b/spec/features/merge_request/user_sees_versions_spec.rb
@@ -232,7 +232,7 @@ RSpec.describe 'Merge request > User sees versions', :js, feature_category: :cod
end
it 'only shows diffs from the commit' do
- diff_commit_ids = find_all('.diff-file [data-commit-id]').map { |diff| diff['data-commit-id'] }
+ diff_commit_ids = find_all('.diff-file [data-commit-id]').pluck('data-commit-id')
expect(diff_commit_ids).not_to be_empty
expect(diff_commit_ids).to all(eq(params[:commit_id]))
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 0de59ea21c5..dae28cbb05c 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
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Merge request > User selects branches for new MR', :js, feature_category: :code_review_workflow do
include ListboxHelpers
+ include CookieHelper
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
@@ -17,6 +18,7 @@ RSpec.describe 'Merge request > User selects branches for new MR', :js, feature_
before do
project.add_maintainer(user)
sign_in(user)
+ set_cookie('new-actions-popover-viewed', 'true')
end
it 'selects the source branch sha when a tag with the same name exists' do
diff --git a/spec/features/merge_request/user_uses_quick_actions_spec.rb b/spec/features/merge_request/user_uses_quick_actions_spec.rb
index 1a88918da65..1ec86948065 100644
--- a/spec/features/merge_request/user_uses_quick_actions_spec.rb
+++ b/spec/features/merge_request/user_uses_quick_actions_spec.rb
@@ -9,7 +9,7 @@ require 'spec_helper'
# for each existing quick action unless they test something not tested by existing tests.
RSpec.describe 'Merge request > User uses quick actions', :js, :use_clean_rails_redis_caching,
feature_category: :code_review_workflow do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
diff --git a/spec/features/merge_request/user_views_open_merge_request_spec.rb b/spec/features/merge_request/user_views_open_merge_request_spec.rb
index e481e3f2dfb..1a9d40ae926 100644
--- a/spec/features/merge_request/user_views_open_merge_request_spec.rb
+++ b/spec/features/merge_request/user_views_open_merge_request_spec.rb
@@ -7,6 +7,18 @@ RSpec.describe 'User views an open merge request', feature_category: :code_revie
create(:merge_request, source_project: project, target_project: project, description: '# Description header')
end
+ context 'feature flags' do
+ let_it_be(:project) { create(:project, :public, :repository) }
+
+ it 'pushes content_editor_on_issues feature flag to frontend' do
+ stub_feature_flags(content_editor_on_issues: true)
+
+ visit merge_request_path(merge_request)
+
+ expect(page).to have_pushed_frontend_feature_flags(contentEditorOnIssues: true)
+ end
+ end
+
context 'when a merge request does not have repository' do
let(:project) { create(:project, :public, :repository) }
@@ -44,25 +56,25 @@ RSpec.describe 'User views an open merge request', feature_category: :code_revie
end
it 'renders empty description preview' do
- find('.gfm-form').fill_in(:merge_request_description, with: '')
+ fill_in(:merge_request_description, with: '')
- page.within('.gfm-form') do
- click_button('Preview')
+ page.within('.js-vue-markdown-field') do
+ click_button("Preview")
- expect(find('.js-md-preview')).to have_content('Nothing to preview.')
+ expect(find('.js-vue-md-preview')).to have_content('Nothing to preview.')
end
end
it 'renders description preview' do
- find('.gfm-form').fill_in(:merge_request_description, with: ':+1: Nice')
+ fill_in(:merge_request_description, with: ':+1: Nice')
- page.within('.gfm-form') do
- click_button('Preview')
+ page.within('.js-vue-markdown-field') do
+ click_button("Preview")
- expect(find('.js-md-preview')).to have_css('gl-emoji')
+ expect(find('.js-vue-md-preview')).to have_css('gl-emoji')
end
- expect(find('.gfm-form')).to have_css('.js-md-preview').and have_button('Write')
+ expect(find('.js-vue-markdown-field')).to have_css('.js-md-preview-button')
expect(find('#merge_request_description', visible: false)).not_to be_visible
end
end
@@ -92,7 +104,7 @@ RSpec.describe 'User views an open merge request', feature_category: :code_revie
visit(merge_request_path(merge_request))
end
- it 'shows diverged commits count' do
+ it 'shows diverged commits count', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408223' do
expect(page).not_to have_content(/([0-9]+ commits? behind)/)
end
end
diff --git a/spec/features/merge_requests/filters_generic_behavior_spec.rb b/spec/features/merge_requests/filters_generic_behavior_spec.rb
index 197b9fa770d..4dbbde5168b 100644
--- a/spec/features/merge_requests/filters_generic_behavior_spec.rb
+++ b/spec/features/merge_requests/filters_generic_behavior_spec.rb
@@ -71,7 +71,7 @@ RSpec.describe 'Merge Requests > Filters generic behavior', :js, feature_categor
context 'filter dropdown' do
it 'filters by label name' do
- init_label_search
+ filtered_search.set('label:=')
filtered_search.send_keys('~bug')
page.within '.filter-dropdown' do
diff --git a/spec/features/merge_requests/rss_spec.rb b/spec/features/merge_requests/rss_spec.rb
index 9c9f46278f6..5f697a4f79d 100644
--- a/spec/features/merge_requests/rss_spec.rb
+++ b/spec/features/merge_requests/rss_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'Project Merge Requests RSS', feature_category: :code_review_work
visit path
end
- it_behaves_like "it has an RSS button with current_user's feed token"
+ it_behaves_like "it has an RSS link with current_user's feed token"
it_behaves_like "an autodiscoverable RSS feed with current_user's feed token"
end
@@ -34,7 +34,7 @@ RSpec.describe 'Project Merge Requests RSS', feature_category: :code_review_work
visit path
end
- it_behaves_like "it has an RSS button without a feed token"
+ it_behaves_like "it has an RSS link without a feed token"
it_behaves_like "an autodiscoverable RSS feed without a feed token"
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 23ac1b264ad..57d6ee69923 100644
--- a/spec/features/merge_requests/user_exports_as_csv_spec.rb
+++ b/spec/features/merge_requests/user_exports_as_csv_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe 'Merge Requests > Exports as CSV', :js, feature_category: :code_r
context 'button is clicked' do
before do
+ click_button 'Actions'
click_button 'Export as CSV'
end
diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
index 3171ae89fe6..371c40b40a5 100644
--- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb
+++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
milestone: create(:milestone, project: project, due_date: '2013-12-11'),
created_at: 1.minute.ago,
updated_at: 1.minute.ago)
- @fix.metrics.update!(merged_at: 10.seconds.ago, latest_closed_at: 10.seconds.ago)
+ @fix.metrics.update!(merged_at: 10.seconds.ago, latest_closed_at: 20.seconds.ago)
@markdown = create(:merge_request,
title: 'markdown',
@@ -33,7 +33,8 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
reviewers: [user, user2, user3, user4],
milestone: create(:milestone, project: project, due_date: '2013-12-12'),
created_at: 2.minutes.ago,
- updated_at: 2.minutes.ago)
+ updated_at: 2.minutes.ago,
+ state: 'merged')
@markdown.metrics.update!(merged_at: 10.minutes.ago, latest_closed_at: 10.seconds.ago)
@merge_test = create(:merge_request,
@@ -49,7 +50,8 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
source_project: project,
source_branch: 'feautre',
created_at: 2.minutes.ago,
- updated_at: 1.minute.ago)
+ updated_at: 1.minute.ago,
+ state: 'merged')
@feature.metrics.update!(merged_at: 10.seconds.ago, latest_closed_at: 10.minutes.ago)
end
@@ -79,10 +81,9 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
expect(page).to have_current_path(project_merge_requests_path(project), ignore_query: true)
expect(page).to have_content 'merge-test'
- expect(page).to have_content 'feature'
expect(page).not_to have_content 'fix'
expect(page).not_to have_content 'markdown'
- expect(count_merge_requests).to eq(2)
+ expect(count_merge_requests).to eq(1)
end
it 'filters on a specific assignee' do
@@ -90,8 +91,7 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
expect(page).not_to have_content 'merge-test'
expect(page).to have_content 'fix'
- expect(page).to have_content 'markdown'
- expect(count_merge_requests).to eq(2)
+ expect(count_merge_requests).to eq(1)
end
it 'sorts by newest' do
@@ -99,35 +99,35 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
expect(first_merge_request).to include('fix')
expect(last_merge_request).to include('merge-test')
- expect(count_merge_requests).to eq(4)
+ expect(count_merge_requests).to eq(2)
end
it 'sorts by last updated' do
visit_merge_requests(project, sort: sort_value_recently_updated)
expect(first_merge_request).to include('merge-test')
- expect(count_merge_requests).to eq(4)
+ expect(count_merge_requests).to eq(2)
end
it 'sorts by milestone due date' do
visit_merge_requests(project, sort: sort_value_milestone)
expect(first_merge_request).to include('fix')
- expect(count_merge_requests).to eq(4)
+ expect(count_merge_requests).to eq(2)
end
- it 'sorts by merged at' do
+ it 'ignores sorting by merged at' do
visit_merge_requests(project, sort: sort_value_merged_date)
- expect(first_merge_request).to include('markdown')
- expect(count_merge_requests).to eq(4)
+ expect(first_merge_request).to include('fix')
+ expect(count_merge_requests).to eq(2)
end
it 'sorts by closed at' do
visit_merge_requests(project, sort: sort_value_closed_date)
- expect(first_merge_request).to include('feature')
- expect(count_merge_requests).to eq(4)
+ expect(first_merge_request).to include('fix')
+ expect(count_merge_requests).to eq(2)
end
it 'filters on one label and sorts by milestone due date' do
@@ -141,6 +141,15 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
expect(count_merge_requests).to eq(1)
end
+ context 'when viewing merged merge requests' do
+ it 'sorts by merged at' do
+ visit_merge_requests(project, state: 'merged', sort: sort_value_merged_date)
+
+ expect(first_merge_request).to include('markdown')
+ expect(count_merge_requests).to eq(2)
+ end
+ end
+
context 'while filtering on two labels' do
let(:label) { create(:label, project: project) }
let(:label2) { create(:label, project: project) }
diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb
index b0be76d386a..45d57cf8374 100644
--- a/spec/features/merge_requests/user_mass_updates_spec.rb
+++ b/spec/features/merge_requests/user_mass_updates_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe 'Merge requests > User mass updates', :js, feature_category: :cod
merge_request.close
visit project_merge_requests_path(project, state: 'merged')
- click_button 'Edit merge requests'
+ click_button 'Bulk edit'
expect(page).not_to have_button 'Select status'
end
@@ -108,7 +108,7 @@ RSpec.describe 'Merge requests > User mass updates', :js, feature_category: :cod
end
def change_status(text)
- click_button 'Edit merge requests'
+ click_button 'Bulk edit'
check 'Select all'
click_button 'Select status'
click_button text
@@ -116,7 +116,7 @@ RSpec.describe 'Merge requests > User mass updates', :js, feature_category: :cod
end
def change_assignee(text)
- click_button 'Edit merge requests'
+ click_button 'Bulk edit'
check 'Select all'
within 'aside[aria-label="Bulk update"]' do
click_button 'Select assignee'
@@ -127,7 +127,7 @@ RSpec.describe 'Merge requests > User mass updates', :js, feature_category: :cod
end
def change_milestone(text)
- click_button 'Edit merge requests'
+ click_button 'Bulk edit'
check 'Select all'
click_button 'Select milestone'
click_button text
diff --git a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb
index 58d796f8288..5ccc24ebca1 100644
--- a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb
+++ b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'User sorts merge requests', :js, feature_category: :code_review_workflow do
include CookieHelper
- include Spec::Support::Helpers::Features::SortingHelpers
+ include Features::SortingHelpers
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let!(:merge_request2) do
diff --git a/spec/features/milestones/user_deletes_milestone_spec.rb b/spec/features/milestones/user_deletes_milestone_spec.rb
index 141e626c6f3..a7f2457de04 100644
--- a/spec/features/milestones/user_deletes_milestone_spec.rb
+++ b/spec/features/milestones/user_deletes_milestone_spec.rb
@@ -18,6 +18,7 @@ RSpec.describe "User deletes milestone", :js, feature_category: :team_planning d
project.add_developer(user)
visit(project_milestones_path(project))
click_link(milestone.title)
+ click_button("Milestone actions")
click_button("Delete")
click_button("Delete milestone")
@@ -38,6 +39,7 @@ RSpec.describe "User deletes milestone", :js, feature_category: :team_planning d
visit(group_milestones_path(group))
click_link(milestone_to_be_deleted.title)
+ click_button("Milestone actions")
click_button("Delete")
click_button("Delete milestone")
diff --git a/spec/features/monitor_sidebar_link_spec.rb b/spec/features/monitor_sidebar_link_spec.rb
index d5f987d15c2..6a1413c04f6 100644
--- a/spec/features/monitor_sidebar_link_spec.rb
+++ b/spec/features/monitor_sidebar_link_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures, feature_category: :not_owned do
+RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures, feature_category: :shared do
let_it_be_with_reload(:project) { create(:project, :internal, :repository) }
let_it_be(:user) { create(:user) }
@@ -11,6 +11,7 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures, feature_category
before do
project.add_role(user, role) if role
sign_in(user)
+ stub_feature_flags(remove_monitor_metrics: false)
end
shared_examples 'shows Monitor menu based on the access level' do
diff --git a/spec/features/nav/new_nav_invite_members_spec.rb b/spec/features/nav/new_nav_invite_members_spec.rb
new file mode 100644
index 00000000000..4c37d6b4760
--- /dev/null
+++ b/spec/features/nav/new_nav_invite_members_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'new navigation toggle', :js, feature_category: :navigation do
+ include Features::InviteMembersModalHelpers
+
+ let_it_be(:user) { create(:user, use_new_navigation: true) }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when inside a group' do
+ let_it_be(:group) { create(:group).tap { |record| record.add_owner(user) } }
+
+ before do
+ visit group_path(group)
+ end
+
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
+ invite_members_from_menu
+
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{group.name} group")
+ end
+ end
+ end
+
+ context 'when inside a project' do
+ let_it_be(:project) { create(:project, :repository).tap { |record| record.add_owner(user) } }
+
+ before do
+ visit project_path(project)
+ end
+
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
+ invite_members_from_menu
+
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{project.name} project")
+ end
+ end
+ end
+
+ def invite_members_from_menu
+ page.find('[data-testid="new-menu-toggle"] button').click
+ click_button('Invite team members')
+ end
+end
diff --git a/spec/features/nav/new_nav_toggle_spec.rb b/spec/features/nav/new_nav_toggle_spec.rb
index 8e5cc7df053..2cdaf12bb15 100644
--- a/spec/features/nav/new_nav_toggle_spec.rb
+++ b/spec/features/nav/new_nav_toggle_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe 'new navigation toggle', :js, feature_category: :navigation do
it 'allows to disable new nav', :aggregate_failures do
within '[data-testid="super-sidebar"] [data-testid="user-dropdown"]' do
- find('button').click
+ click_button "#{user.name} user’s menu"
expect(page).to have_content('Navigation redesign')
toggle = page.find('.gl-toggle.is-checked')
diff --git a/spec/features/nav/pinned_nav_items_spec.rb b/spec/features/nav/pinned_nav_items_spec.rb
new file mode 100644
index 00000000000..308350d5166
--- /dev/null
+++ b/spec/features/nav/pinned_nav_items_spec.rb
@@ -0,0 +1,195 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Navigation menu item pinning', :js, feature_category: :navigation do
+ let_it_be(:user) { create(:user, use_new_navigation: true) }
+
+ before do
+ sign_in(user)
+ end
+
+ describe 'non-pinnable navigation menu' do
+ before do
+ visit explore_projects_path
+ end
+
+ it 'does not show the Pinned section' do
+ within '#super-sidebar' do
+ expect(page).not_to have_content 'Pinned'
+ end
+ end
+
+ it 'does not show the buttons to pin items' do
+ within '#super-sidebar' do
+ expect(page).not_to have_css 'button svg[data-testid="thumbtack-icon"]'
+ end
+ end
+ end
+
+ describe 'pinnable navigation menu' do
+ let_it_be(:project) { create(:project) }
+
+ before do
+ project.add_member(user, :owner)
+ visit project_path(project)
+ end
+
+ it 'adds sensible defaults' do
+ within '[data-testid="pinned-nav-items"]' do
+ expect(page).to have_link 'Issues'
+ end
+ end
+
+ it 'shows the Pinned section' do
+ within '#super-sidebar' do
+ expect(page).to have_content 'Pinned'
+ end
+ end
+
+ it 'allows to pin items' do
+ within '#super-sidebar' do
+ click_on 'Manage'
+ add_pin('Activity')
+ add_pin('Members')
+ end
+
+ within '[data-testid="pinned-nav-items"]' do
+ expect(page).to have_link 'Issues'
+ expect(page).to have_link 'Activity'
+ expect(page).to have_link 'Members'
+ end
+ end
+
+ describe 'when all pins are removed' do
+ before do
+ remove_pin('Issues')
+ end
+
+ it 'shows the Pinned section as expanded by default' do
+ within '#super-sidebar' do
+ expect(page).to have_content 'Your pinned items appear here.'
+ end
+ end
+
+ it 'maintains the collapsed/expanded state between page loads' do
+ within '#super-sidebar' do
+ click_on 'Pinned'
+ visit project_path(project)
+ expect(page).not_to have_content 'Your pinned items appear here.'
+
+ click_on 'Pinned'
+ visit project_path(project)
+ expect(page).to have_content 'Your pinned items appear here.'
+ end
+ end
+ end
+
+ describe 'pinned items' do
+ before do
+ within '#super-sidebar' do
+ click_on 'Operate'
+ add_pin('Package Registry')
+ add_pin('Terraform modules')
+ wait_for_requests
+ end
+ end
+
+ it 'can be unpinned from within the pinned section' do
+ within '[data-testid="pinned-nav-items"]' do
+ remove_pin('Package Registry')
+ expect(page).not_to have_content 'Package Registry'
+ end
+ end
+
+ it 'can be unpinned from within its section' do
+ section = find("button", text: 'Operate')
+
+ within(section.sibling('ul')) do
+ remove_pin('Terraform modules')
+ end
+
+ within '[data-testid="pinned-nav-items"]' do
+ expect(page).not_to have_content 'Terraform modules'
+ end
+ end
+
+ it 'can be reordered' do
+ within '[data-testid="pinned-nav-items"]' do
+ pinned_items = page.find_all('a').map(&:text)
+ item2 = page.find('a', text: 'Package Registry')
+ item3 = page.find('a', text: 'Terraform modules')
+ expect(pinned_items[1..2]).to eq [item2.text, item3.text]
+ drag_item(item3, to: item2)
+
+ pinned_items = page.find_all('a').map(&:text)
+ expect(pinned_items[1..2]).to eq [item3.text, item2.text]
+ end
+ end
+ end
+ end
+
+ describe 'reordering pins with hidden pins from non-available features' do
+ let_it_be(:project_with_repo) { create(:project, :repository) }
+ let_it_be(:project_without_repo) { create(:project, :repository_disabled) }
+
+ before do
+ project_with_repo.add_member(user, :owner)
+ project_without_repo.add_member(user, :owner)
+
+ visit project_path(project_with_repo)
+ within '#super-sidebar' do
+ click_on 'Code'
+ add_pin('Commits')
+ click_on 'Manage'
+ add_pin('Activity')
+ add_pin('Members')
+ end
+
+ visit project_path(project_without_repo)
+ within '[data-testid="pinned-nav-items"]' do
+ activity_item = page.find('a', text: 'Activity')
+ members_item = page.find('a', text: 'Members')
+ drag_item(members_item, to: activity_item)
+ end
+
+ visit project_path(project_with_repo)
+ end
+
+ it 'keeps pins of non-available features' do
+ within '[data-testid="pinned-nav-items"]' do
+ pinned_items = page.find_all('a')
+ .map(&:text)
+ .map { |text| text.split("\n").first } # to drop the counter badge text from "Issues\n0"
+ expect(pinned_items).to eq ["Issues", "Merge requests", "Commits", "Members", "Activity"]
+ end
+ end
+ end
+
+ private
+
+ def add_pin(menu_item_title)
+ menu_item = find("[data-testid=\"nav-item-link\"]", text: menu_item_title)
+ menu_item.hover
+ menu_item.find("[data-testid=\"thumbtack-icon\"]").click
+ wait_for_requests
+ end
+
+ def remove_pin(menu_item_title)
+ menu_item = find("[data-testid=\"nav-item-link\"]", text: menu_item_title)
+ menu_item.hover
+ menu_item.find("[data-testid=\"thumbtack-solid-icon\"]").click
+ wait_for_requests
+ end
+
+ def drag_item(item, to:)
+ item.hover
+ drag_handle = item.find('[data-testid="grip-icon"]')
+
+ # Reduce delay to make it less likely for draggables to
+ # change position during drag operation, which reduces
+ # flakiness.
+ drag_handle.drag_to(to, delay: 0.01)
+ wait_for_requests
+ end
+end
diff --git a/spec/features/nav/top_nav_responsive_spec.rb b/spec/features/nav/top_nav_responsive_spec.rb
index 56f9d373f00..ff8132dc087 100644
--- a/spec/features/nav/top_nav_responsive_spec.rb
+++ b/spec/features/nav/top_nav_responsive_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
include MobileHelpers
+ include Features::InviteMembersModalHelpers
let_it_be(:user) { create(:user) }
@@ -20,8 +21,8 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
context 'when menu is closed' do
it 'has page content and hides responsive menu', :aggregate_failures do
- expect(page).to have_css('.page-title', text: 'Projects')
- expect(page).to have_link('Dashboard', id: 'logo')
+ expect(page).to have_css('.page-title', text: 'Explore projects')
+ expect(page).to have_link('Homepage', id: 'logo')
expect(page).to have_no_css('.top-nav-responsive')
end
@@ -33,14 +34,15 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
end
it 'hides everything and shows responsive menu', :aggregate_failures do
- expect(page).to have_no_css('.page-title', text: 'Projects')
- expect(page).to have_no_link('Dashboard', id: 'logo')
+ expect(page).to have_no_css('.page-title', text: 'Explore projects')
+ expect(page).to have_no_link('Homepage', id: 'logo')
within '.top-nav-responsive' do
expect(page).to have_link(nil, href: search_path)
expect(page).to have_button('Projects')
expect(page).to have_button('Groups')
- expect(page).to have_link('Snippets', href: dashboard_snippets_path)
+ expect(page).to have_link('Your work', href: dashboard_projects_path)
+ expect(page).to have_link('Explore', href: explore_projects_path)
end
end
@@ -61,10 +63,12 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
visit project_path(project)
end
- it 'the add menu contains invite members dropdown option and goes to the members page' do
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
invite_members_from_menu
- expect(page).to have_current_path(project_project_members_path(project))
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{project.name} project")
+ end
end
end
@@ -75,10 +79,12 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
visit group_path(group)
end
- it 'the add menu contains invite members dropdown option and goes to the members page' do
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
invite_members_from_menu
- expect(page).to have_current_path(group_group_members_path(group))
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{group.name} group")
+ end
end
end
@@ -86,7 +92,7 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
click_button('Menu')
create_new_button.click
- click_link('Invite members')
+ click_button('Invite members')
end
def create_new_button
diff --git a/spec/features/nav/top_nav_spec.rb b/spec/features/nav/top_nav_spec.rb
index cc20b626e30..74022a4a976 100644
--- a/spec/features/nav/top_nav_spec.rb
+++ b/spec/features/nav/top_nav_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
+ include Features::InviteMembersModalHelpers
+
let_it_be(:user) { create(:user) }
before do
@@ -16,10 +18,12 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
visit project_path(project)
end
- it 'the add menu contains invite members dropdown option and goes to the members page' do
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
invite_members_from_menu
- expect(page).to have_current_path(project_project_members_path(project))
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{project.name} project")
+ end
end
end
@@ -30,10 +34,12 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
visit group_path(group)
end
- it 'the add menu contains invite members dropdown option and goes to the members page' do
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
invite_members_from_menu
- expect(page).to have_current_path(group_group_members_path(group))
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{group.name} group")
+ end
end
end
diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb
index bd96d65f984..ca20a1cd81b 100644
--- a/spec/features/oauth_login_spec.rb
+++ b/spec/features/oauth_login_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe 'OAuth Login', :allow_forgery_protection, feature_category: :syst
end
providers = [:github, :twitter, :bitbucket, :gitlab, :google_oauth2,
- :facebook, :cas3, :auth0, :salesforce, :dingtalk, :alicloud]
+ :facebook, :auth0, :salesforce, :dingtalk, :alicloud]
around do |example|
with_omniauth_full_host { example.run }
diff --git a/spec/features/oauth_registration_spec.rb b/spec/features/oauth_registration_spec.rb
index 3c1004e452f..c88a018a592 100644
--- a/spec/features/oauth_registration_spec.rb
+++ b/spec/features/oauth_registration_spec.rb
@@ -21,7 +21,6 @@ RSpec.describe 'OAuth Registration', :js, :allow_forgery_protection, feature_cat
:gitlab | {}
:google_oauth2 | {}
:facebook | {}
- :cas3 | {}
:auth0 | {}
:salesforce | { extra: { email_verified: true } }
:dingtalk | {}
diff --git a/spec/features/populate_new_pipeline_vars_with_params_spec.rb b/spec/features/populate_new_pipeline_vars_with_params_spec.rb
index a83b5a81a41..bcda30ccb84 100644
--- a/spec/features/populate_new_pipeline_vars_with_params_spec.rb
+++ b/spec/features/populate_new_pipeline_vars_with_params_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Populate new pipeline CI variables with url params", :js, feature_category: :pipeline_authoring do
+RSpec.describe "Populate new pipeline CI variables with url params", :js, feature_category: :secrets_management do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:page_path) { new_project_pipeline_path(project) }
diff --git a/spec/features/profiles/chat_names_spec.rb b/spec/features/profiles/chat_names_spec.rb
index 299ecdb6032..aa3f4a90298 100644
--- a/spec/features/profiles/chat_names_spec.rb
+++ b/spec/features/profiles/chat_names_spec.rb
@@ -2,9 +2,8 @@
require 'spec_helper'
-RSpec.describe 'Profile > Chat', feature_category: :user_profile do
- let(:user) { create(:user) }
- let(:integration) { create(:integration) }
+RSpec.describe 'Profile > Chat', feature_category: :integrations do
+ let_it_be(:user) { create(:user) }
before do
sign_in(user)
@@ -12,7 +11,12 @@ RSpec.describe 'Profile > Chat', feature_category: :user_profile do
describe 'uses authorization link' do
let(:params) do
- { team_id: 'T00', team_domain: 'my_chat_team', user_id: 'U01', user_name: 'my_chat_user' }
+ {
+ team_id: 'f1924a8db44ff3bb41c96424cdc20676',
+ team_domain: 'my_chat_team',
+ user_id: 'ay5sq51sebfh58ktrce5ijtcwy',
+ user_name: 'my_chat_user'
+ }
end
let!(:authorize_url) { ChatNames::AuthorizeUserService.new(params).execute }
@@ -22,6 +26,36 @@ RSpec.describe 'Profile > Chat', feature_category: :user_profile do
visit authorize_path
end
+ it 'names the Mattermost integration correctly' do
+ expect(page).to have_content(
+ 'An application called Mattermost slash commands is requesting access to your GitLab account'
+ )
+ expect(page).to have_content('Authorize Mattermost slash commands')
+ end
+
+ context 'when params are of the GitLab for Slack app' do
+ let(:params) do
+ { team_id: 'T00', team_domain: 'my_chat_team', user_id: 'U01', user_name: 'my_chat_user' }
+ end
+
+ shared_examples 'names the GitLab for Slack app integration correctly' do
+ specify do
+ expect(page).to have_content(
+ 'An application called GitLab for Slack app is requesting access to your GitLab account'
+ )
+ expect(page).to have_content('Authorize GitLab for Slack app')
+ end
+ end
+
+ include_examples 'names the GitLab for Slack app integration correctly'
+
+ context 'with a Slack enterprise-enabled team' do
+ let(:params) { super().merge(user_id: 'W01') }
+
+ include_examples 'names the GitLab for Slack app integration correctly'
+ end
+ end
+
context 'clicks authorize' do
before do
click_button 'Authorize'
@@ -60,7 +94,7 @@ RSpec.describe 'Profile > Chat', feature_category: :user_profile do
end
describe 'visits chat accounts' do
- let!(:chat_name) { create(:chat_name, user: user, integration: integration) }
+ let_it_be(:chat_name) { create(:chat_name, user: user) }
before do
visit profile_chat_names_path
diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb
index 0fc59f21489..f39d9ddaf56 100644
--- a/spec/features/profiles/gpg_keys_spec.rb
+++ b/spec/features/profiles/gpg_keys_spec.rb
@@ -37,12 +37,13 @@ RSpec.describe 'Profile > GPG Keys', feature_category: :user_profile do
end
it 'user sees their key' do
- create(:gpg_key, user: user, key: GpgHelpers::User2.public_key)
+ gpg_key = create(:gpg_key, user: user, key: GpgHelpers::User2.public_key)
visit profile_gpg_keys_path
expect(page).to have_content('bette.cartwright@example.com Verified')
expect(page).to have_content('bette.cartwright@example.net Unverified')
expect(page).to have_content(GpgHelpers::User2.fingerprint)
+ expect(page).to have_selector('time.js-timeago', text: gpg_key.created_at.strftime('%b %d, %Y'))
end
it 'user removes a key via the key index' do
diff --git a/spec/features/profiles/list_users_saved_replies_spec.rb b/spec/features/profiles/list_users_comment_template_spec.rb
index 4f3678f8051..85e455ba988 100644
--- a/spec/features/profiles/list_users_saved_replies_spec.rb
+++ b/spec/features/profiles/list_users_comment_template_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Profile > Notifications > List users saved replies', :js,
+RSpec.describe 'Profile > Comment templates > List users comment templates', :js,
feature_category: :user_profile do
let_it_be(:user) { create(:user) }
let_it_be(:saved_reply) { create(:saved_reply, user: user) }
@@ -11,10 +11,10 @@ RSpec.describe 'Profile > Notifications > List users saved replies', :js,
sign_in(user)
end
- it 'shows the user a list of their saved replies' do
- visit profile_saved_replies_path
+ it 'shows the user a list of their comment templates' do
+ visit profile_comment_templates_path
- expect(page).to have_content('My saved replies (1)')
+ expect(page).to have_content('My comment templates (1)')
expect(page).to have_content(saved_reply.name)
expect(page).to have_content(saved_reply.content)
end
diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb
index a050e87241b..65fe1330be2 100644
--- a/spec/features/profiles/personal_access_tokens_spec.rb
+++ b/spec/features/profiles/personal_access_tokens_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Profile > Personal Access Tokens', :js, feature_category: :user_profile do
include Spec::Support::Helpers::ModalHelpers
- include Spec::Support::Helpers::AccessTokenHelpers
+ include Features::AccessTokenHelpers
let(:user) { create(:user) }
let(:pat_create_service) { double('PersonalAccessTokens::CreateService', execute: ServiceResponse.error(message: 'error', payload: { personal_access_token: PersonalAccessToken.new })) }
diff --git a/spec/features/profiles/user_creates_comment_template_spec.rb b/spec/features/profiles/user_creates_comment_template_spec.rb
new file mode 100644
index 00000000000..44e2b932c00
--- /dev/null
+++ b/spec/features/profiles/user_creates_comment_template_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Profile > Comment templates > User creates comment template', :js,
+ feature_category: :user_profile do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+
+ visit profile_comment_templates_path
+
+ wait_for_requests
+ end
+
+ it 'shows the user a list of their saved replies' do
+ find('[data-testid="comment-template-name-input"]').set('test')
+ find('[data-testid="comment-template-content-input"]').set('Test content')
+
+ click_button 'Save'
+
+ wait_for_requests
+
+ expect(page).to have_content('My comment templates (1)')
+ expect(page).to have_content('test')
+ expect(page).to have_content('Test content')
+ end
+end
diff --git a/spec/features/profiles/user_deletes_comment_template_spec.rb b/spec/features/profiles/user_deletes_comment_template_spec.rb
new file mode 100644
index 00000000000..7ef857e9622
--- /dev/null
+++ b/spec/features/profiles/user_deletes_comment_template_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Profile > Comment templates > User deletes comment template', :js,
+ feature_category: :user_profile do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:saved_reply) { create(:saved_reply, user: user) }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'shows the user a list of their comment template' do
+ visit profile_comment_templates_path
+
+ click_button 'Comment template actions'
+ find('[data-testid="comment-template-delete-btn"]').click
+
+ page.within('.gl-modal') do
+ click_button 'Delete'
+ end
+
+ wait_for_requests
+
+ expect(page).not_to have_content(saved_reply.name)
+ end
+end
diff --git a/spec/features/profiles/user_edit_preferences_spec.rb b/spec/features/profiles/user_edit_preferences_spec.rb
index f7a9850355a..6cc926ed017 100644
--- a/spec/features/profiles/user_edit_preferences_spec.rb
+++ b/spec/features/profiles/user_edit_preferences_spec.rb
@@ -12,22 +12,11 @@ RSpec.describe 'User edit preferences profile', :js, feature_category: :user_pro
before do
stub_languages_translation_percentage(language_percentage_levels)
- stub_feature_flags(user_time_settings: true)
stub_feature_flags(vscode_web_ide: vscode_web_ide)
sign_in(user)
visit(profile_preferences_path)
end
- it 'allows the user to toggle their time format preference' do
- field = page.find_field("user[time_format_in_24h]")
-
- expect(field).not_to be_checked
-
- field.click
-
- expect(field).to be_checked
- end
-
it 'allows the user to toggle their time display preference' do
field = page.find_field("user[time_display_relative]")
@@ -38,24 +27,6 @@ RSpec.describe 'User edit preferences profile', :js, feature_category: :user_pro
expect(field).not_to be_checked
end
- it 'allows the user to toggle using the legacy web ide' do
- field = page.find_field("user[use_legacy_web_ide]")
-
- expect(field).not_to be_checked
-
- field.click
-
- expect(field).to be_checked
- end
-
- describe 'when vscode_web_ide feature flag is disabled' do
- let(:vscode_web_ide) { false }
-
- it 'does not display the legacy web ide user preference' do
- expect(page).not_to have_field("user[use_legacy_web_ide]")
- end
- end
-
describe 'User changes tab width to acceptable value' do
it 'shows success message' do
fill_in 'Tab width', with: 9
diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb
index 3819723cc09..a6dcbc31dc4 100644
--- a/spec/features/profiles/user_edit_profile_spec.rb
+++ b/spec/features/profiles/user_edit_profile_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User edit profile', feature_category: :user_profile do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
let_it_be(:user) { create(:user) }
@@ -97,6 +97,26 @@ RSpec.describe 'User edit profile', feature_category: :user_profile do
expect(page).to have_content('Website url is not a valid URL')
end
+ it 'validates that the discord id has a valid length', :js do
+ valid_discord_id = '123456789123456789'
+ too_short_discord_id = '123456'
+ too_long_discord_id = '123456789abcdefghijkl'
+
+ fill_in 'user_discord', with: too_short_discord_id
+ expect(page).to have_content('Discord ID is too short')
+
+ fill_in 'user_discord', with: too_long_discord_id
+ expect(page).to have_content('Discord ID is too long')
+
+ fill_in 'user_discord', with: valid_discord_id
+
+ submit_settings
+
+ expect(user.reload).to have_attributes(
+ discord: valid_discord_id
+ )
+ end
+
describe 'when I change my email', :js do
before do
user.send_reset_password_instructions
@@ -277,7 +297,7 @@ RSpec.describe 'User edit profile', feature_category: :user_profile do
end
page.within '.dropdown-menu-user' do
- expect(page).to have_content("#{user.name} (Busy)")
+ expect(page).to have_content("#{user.name} Busy")
end
end
@@ -288,7 +308,7 @@ RSpec.describe 'User edit profile', feature_category: :user_profile do
visit project_issue_path(project, issue)
wait_for_requests
- expect(page.find('.issuable-assignees')).to have_content("#{user.name} (Busy)")
+ expect(page.find('.issuable-assignees')).to have_content("#{user.name} Busy")
end
end
end
@@ -504,10 +524,6 @@ RSpec.describe 'User edit profile', feature_category: :user_profile do
let(:issue) { create(:issue, project: project) }
let(:project) { create(:project) }
- before do
- stub_feature_flags(user_time_settings: true)
- end
-
it 'shows the user time preferences form' do
expect(page).to have_content('Time settings')
end
diff --git a/spec/features/profiles/user_updates_comment_template_spec.rb b/spec/features/profiles/user_updates_comment_template_spec.rb
new file mode 100644
index 00000000000..2e6bfdcc407
--- /dev/null
+++ b/spec/features/profiles/user_updates_comment_template_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Profile > Comment templates > User updated comment template', :js,
+ feature_category: :user_profile do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:saved_reply) { create(:saved_reply, user: user) }
+
+ before do
+ sign_in(user)
+
+ visit profile_comment_templates_path
+
+ wait_for_requests
+ end
+
+ it 'shows the user a list of their comment template' do
+ click_button 'Comment template actions'
+
+ find('[data-testid="comment-template-edit-btn"]').click
+ find('[data-testid="comment-template-name-input"]').set('test')
+
+ click_button 'Save'
+
+ wait_for_requests
+
+ expect(page).to have_selector('[data-testid="comment-template-name"]', text: 'test')
+ end
+end
diff --git a/spec/features/profiles/user_uses_comment_template_spec.rb b/spec/features/profiles/user_uses_comment_template_spec.rb
new file mode 100644
index 00000000000..704d02e94f4
--- /dev/null
+++ b/spec/features/profiles/user_uses_comment_template_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User uses comment template', :js,
+ feature_category: :user_profile do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:saved_reply) { create(:saved_reply, user: user) }
+
+ before do
+ project.add_owner(user)
+
+ sign_in(user)
+ end
+
+ it 'applies comment template' do
+ visit project_merge_request_path(merge_request.project, merge_request)
+
+ find('.js-comment-template-toggle').click
+
+ wait_for_requests
+
+ find('.gl-new-dropdown-item').click
+
+ expect(find('.note-textarea').value).to eq(saved_reply.content)
+ end
+end
diff --git a/spec/features/profiles/user_visits_profile_authentication_log_spec.rb b/spec/features/profiles/user_visits_profile_authentication_log_spec.rb
index 90f24c5b866..ac0ed91468c 100644
--- a/spec/features/profiles/user_visits_profile_authentication_log_spec.rb
+++ b/spec/features/profiles/user_visits_profile_authentication_log_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe 'User visits the authentication log', feature_category: :user_pro
it 'shows correct menu item' do
visit(audit_log_profile_path)
- expect(page).to have_active_navigation('Authentication log')
+ expect(page).to have_active_navigation('Authentication Log')
end
end
diff --git a/spec/features/project_group_variables_spec.rb b/spec/features/project_group_variables_spec.rb
index 0e1e6e49c6d..966c05bb4cb 100644
--- a/spec/features/project_group_variables_spec.rb
+++ b/spec/features/project_group_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project group variables', :js, feature_category: :pipeline_authoring do
+RSpec.describe 'Project group variables', :js, feature_category: :secrets_management do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
diff --git a/spec/features/project_variables_spec.rb b/spec/features/project_variables_spec.rb
index 1a951980141..c4f78bf4ea3 100644
--- a/spec/features/project_variables_spec.rb
+++ b/spec/features/project_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project variables', :js, feature_category: :pipeline_authoring do
+RSpec.describe 'Project variables', :js, feature_category: :secrets_management do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:variable) { create(:ci_variable, key: 'test_key', value: 'test_value', masked: true) }
@@ -16,7 +16,18 @@ RSpec.describe 'Project variables', :js, feature_category: :pipeline_authoring d
wait_for_requests
end
- it_behaves_like 'variable list'
+ context 'when ci_variables_pages FF is enabled' do
+ it_behaves_like 'variable list'
+ it_behaves_like 'variable list pagination', :ci_variable
+ end
+
+ context 'when ci_variables_pages FF is disabled' do
+ before do
+ stub_feature_flags(ci_variables_pages: false)
+ end
+
+ it_behaves_like 'variable list'
+ end
it 'adds a new variable with an environment scope' do
click_button('Add variable')
diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb
index e6bd4b22b0a..c9e4aabe72a 100644
--- a/spec/features/projects/badges/list_spec.rb
+++ b/spec/features/projects/badges/list_spec.rb
@@ -43,13 +43,46 @@ RSpec.describe 'list of badges', feature_category: :continuous_integration do
it 'user changes current ref of build status badge', :js do
page.within('.pipeline-status') do
- first('.js-project-refs-dropdown').click
+ find('.ref-selector').click
+ wait_for_requests
- page.within '.project-refs-form' do
- click_link 'improve/awesome'
+ page.within('.ref-selector') do
+ fill_in 'Search by Git revision', with: 'improve/awesome'
+ wait_for_requests
+ find('li', text: 'improve/awesome', match: :prefer_exact).click
end
expect(page).to have_content 'badges/improve/awesome/pipeline.svg'
end
end
+
+ it 'user changes current ref of coverage status badge', :js do
+ page.within('.coverage-report') do
+ find('.ref-selector').click
+ wait_for_requests
+
+ page.within('.ref-selector') do
+ fill_in 'Search by Git revision', with: 'improve/awesome'
+ wait_for_requests
+ find('li', text: 'improve/awesome', match: :prefer_exact).click
+ end
+
+ expect(page).to have_content 'badges/improve/awesome/coverage.svg'
+ end
+ end
+
+ it 'user changes current ref of latest release status badge', :js do
+ page.within('.Latest-Release') do
+ find('.ref-selector').click
+ wait_for_requests
+
+ page.within('.ref-selector') do
+ fill_in 'Search by Git revision', with: 'improve/awesome'
+ wait_for_requests
+ find('li', text: 'improve/awesome', match: :prefer_exact).click
+ end
+
+ expect(page).to have_content '-/badges/release.svg'
+ end
+ end
end
diff --git a/spec/features/projects/blobs/blame_spec.rb b/spec/features/projects/blobs/blame_spec.rb
index 27b7c6ef2d5..9f061a2ff14 100644
--- a/spec/features/projects/blobs/blame_spec.rb
+++ b/spec/features/projects/blobs/blame_spec.rb
@@ -38,13 +38,13 @@ RSpec.describe 'File blame', :js, feature_category: :projects do
within '[data-testid="blob-content-holder"]' do
expect(page).to have_css('.blame-commit')
expect(page).not_to have_css('.gl-pagination')
- expect(page).not_to have_link _('View entire blame')
+ expect(page).not_to have_link _('Show full blame')
end
end
context 'when blob length is over the blame range limit' do
before do
- stub_const('Projects::BlameService::PER_PAGE', 2)
+ stub_const('Gitlab::Git::BlamePagination::PAGINATION_PER_PAGE', 2)
end
it 'displays two first lines of the file with pagination' do
@@ -53,7 +53,7 @@ RSpec.describe 'File blame', :js, feature_category: :projects do
within '[data-testid="blob-content-holder"]' do
expect(page).to have_css('.blame-commit')
expect(page).to have_css('.gl-pagination')
- expect(page).to have_link _('View entire blame')
+ expect(page).to have_link _('Show full blame')
expect(page).to have_css('#L1')
expect(page).not_to have_css('#L3')
@@ -85,19 +85,34 @@ RSpec.describe 'File blame', :js, feature_category: :projects do
end
end
- context 'when user clicks on View entire blame button' do
+ shared_examples 'a full blame page' do
+ context 'when user clicks on Show full blame button' do
+ before do
+ visit_blob_blame(path)
+ click_link _('Show full blame')
+ end
+
+ it 'displays the blame page without pagination' do
+ within '[data-testid="blob-content-holder"]' do
+ expect(page).to have_css('#L1')
+ expect(page).to have_css('#L667')
+ expect(page).not_to have_css('.gl-pagination')
+ end
+ end
+ end
+ end
+
+ context 'when streaming is enabled' do
before do
- visit_blob_blame(path)
+ stub_const('Gitlab::Git::BlamePagination::STREAMING_PER_PAGE', 50)
end
- it 'displays the blame page without pagination' do
- within '[data-testid="blob-content-holder"]' do
- click_link _('View entire blame')
+ it_behaves_like 'a full blame page'
- expect(page).to have_css('#L1')
- expect(page).to have_css('#L3')
- expect(page).not_to have_css('.gl-pagination')
- end
+ it 'shows loading text', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410499' do
+ visit_blob_blame(path)
+ click_link _('Show full blame')
+ expect(page).to have_text('Loading full blame...')
end
end
@@ -112,7 +127,7 @@ RSpec.describe 'File blame', :js, feature_category: :projects do
within '[data-testid="blob-content-holder"]' do
expect(page).to have_css('.blame-commit')
expect(page).not_to have_css('.gl-pagination')
- expect(page).not_to have_link _('View entire blame')
+ expect(page).not_to have_link _('Show full blame')
end
end
end
@@ -120,7 +135,7 @@ RSpec.describe 'File blame', :js, feature_category: :projects do
context 'when blob length is over global max page limit' do
before do
- stub_const('Projects::BlameService::PER_PAGE', 200)
+ stub_const('Gitlab::Git::BlamePagination::PAGINATION_PER_PAGE', 200)
end
let(:path) { 'files/markdown/ruby-style-guide.md' }
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index 7faf0e1a6b1..cd1dde55e30 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -137,11 +137,13 @@ RSpec.describe 'File blob', :js, feature_category: :projects do
context 'when ref switch' do
def switch_ref_to(ref_name)
- first('[data-testid="branches-select"]').click
+ find('.ref-selector').click
+ wait_for_requests
- page.within '.project-refs-form' do
- click_link ref_name
+ page.within('.ref-selector') do
+ fill_in 'Search by Git revision', with: ref_name
wait_for_requests
+ find('li', text: ref_name, match: :prefer_exact).click
end
end
@@ -193,10 +195,11 @@ RSpec.describe 'File blob', :js, feature_category: :projects do
end
end
- it 'successfully changes ref when the ref name matches the project name' do
- project.repository.create_branch(project.name)
+ # Regression test for https://gitlab.com/gitlab-org/gitlab/-/issues/330947
+ it 'successfully changes ref when the ref name matches the project path' do
+ project.repository.create_branch(project.path)
- visit_blob('files/js/application.js', ref: project.name)
+ visit_blob('files/js/application.js', ref: project.path)
switch_ref_to('master')
aggregate_failures do
@@ -577,7 +580,11 @@ RSpec.describe 'File blob', :js, feature_category: :projects do
end
describe '.gitlab/dashboards/custom-dashboard.yml' do
+ let(:remove_monitor_metrics) { false }
+
before do
+ stub_feature_flags(remove_monitor_metrics: remove_monitor_metrics)
+
project.add_maintainer(project.creator)
Files::CreateService.new(
@@ -605,6 +612,15 @@ RSpec.describe 'File blob', :js, feature_category: :projects do
expect(page).to have_link('Learn more')
end
end
+
+ context 'when metrics dashboard feature is unavailable' do
+ let(:remove_monitor_metrics) { true }
+
+ it 'displays the blob without an auxiliary viewer' do
+ expect(page).to have_content('Environment metrics')
+ expect(page).not_to have_content('Metrics Dashboard YAML definition', wait: 0)
+ end
+ end
end
context 'invalid dashboard file' do
diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb
index 144b4ed85cd..6e335871ed1 100644
--- a/spec/features/projects/blobs/edit_spec.rb
+++ b/spec/features/projects/blobs/edit_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'Editing file blob', :js, feature_category: :projects do
- include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
+ include Features::SourceEditorSpecHelpers
include TreeHelper
- include BlobSpecHelpers
+ include Features::BlobSpecHelpers
let_it_be(:project) { create(:project, :public, :repository) }
let_it_be(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') }
@@ -142,7 +142,7 @@ RSpec.describe 'Editing file blob', :js, feature_category: :projects do
it 'renders content with CommonMark' do
visit project_edit_blob_path(project, tree_join(branch, readme_file_path))
fill_editor(content: '1. one\\n - sublist\\n')
- click_link 'Preview'
+ click_on "Preview"
wait_for_requests
# the above generates two separate lists (not embedded) in CommonMark
diff --git a/spec/features/projects/blobs/user_views_pipeline_editor_button_spec.rb b/spec/features/projects/blobs/user_views_pipeline_editor_button_spec.rb
index 2f67e909543..3b383793de2 100644
--- a/spec/features/projects/blobs/user_views_pipeline_editor_button_spec.rb
+++ b/spec/features/projects/blobs/user_views_pipeline_editor_button_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User views pipeline editor button on root ci config file', :js, feature_category: :projects do
- include BlobSpecHelpers
+ include Features::BlobSpecHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/projects/branches/user_creates_branch_spec.rb b/spec/features/projects/branches/user_creates_branch_spec.rb
index 60bd77393e9..5aa10a8d4b0 100644
--- a/spec/features/projects/branches/user_creates_branch_spec.rb
+++ b/spec/features/projects/branches/user_creates_branch_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User creates branch', :js, feature_category: :projects do
- include Spec::Support::Helpers::Features::BranchesHelpers
+ include Features::BranchesHelpers
let_it_be(:group) { create(:group, :public) }
let_it_be(:user) { create(:user) }
@@ -81,7 +81,9 @@ RSpec.describe 'User creates branch', :js, feature_category: :projects do
it 'does not create new branch' do
invalid_branch_name = '1.0 stable'
- create_branch(invalid_branch_name)
+ fill_in("branch_name", with: invalid_branch_name)
+ find('body').click
+ click_button("Create branch")
expect(page).to have_content('Branch name is invalid')
expect(page).to have_content("can't contain spaces")
diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb
index fc7833809b3..e1f1a63565c 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -201,6 +201,12 @@ RSpec.describe 'Branches', feature_category: :projects do
end
end
+ describe 'Link to branch rules' do
+ it 'does not have possibility to navigate to branch rules', :js do
+ expect(page).not_to have_content(s_("Branches|View branch rules"))
+ end
+ end
+
context 'on project with 0 branch' do
let(:project) { create(:project, :public, :empty_repo) }
let(:repository) { project.repository }
@@ -239,6 +245,17 @@ RSpec.describe 'Branches', feature_category: :projects do
expect(page).not_to have_content 'Merge request'
end
end
+
+ describe 'Navigate to branch rules from branches page' do
+ it 'shows repository settings page with Branch rules section expanded' do
+ visit project_branches_path(project)
+
+ view_branch_rules
+
+ expect(page).to have_content(
+ _('Define rules for who can push, merge, and the required approvals for each branch.'))
+ end
+ end
end
end
@@ -353,4 +370,11 @@ RSpec.describe 'Branches', feature_category: :projects do
click_button 'Yes, delete branch'
end
end
+
+ def view_branch_rules
+ page.within('.nav-controls') do
+ click_link s_("Branches|View branch rules")
+ end
+ wait_for_requests
+ end
end
diff --git a/spec/features/projects/ci/editor_spec.rb b/spec/features/projects/ci/editor_spec.rb
index 536152626af..9851194bd3c 100644
--- a/spec/features/projects/ci/editor_spec.rb
+++ b/spec/features/projects/ci/editor_spec.rb
@@ -2,8 +2,8 @@
require 'spec_helper'
-RSpec.describe 'Pipeline Editor', :js, feature_category: :pipeline_authoring do
- include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
+RSpec.describe 'Pipeline Editor', :js, feature_category: :pipeline_composition do
+ include Features::SourceEditorSpecHelpers
let(:project) { create(:project_empty_repo, :public) }
let(:user) { create(:user) }
@@ -101,7 +101,7 @@ RSpec.describe 'Pipeline Editor', :js, feature_category: :pipeline_authoring do
end
end
- it 'user who tries to navigate away can cancel the action and keep their changes' do
+ it 'user who tries to navigate away can cancel the action and keep their changes', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410496' do
click_link 'Pipelines'
page.driver.browser.switch_to.alert.dismiss
@@ -113,7 +113,7 @@ RSpec.describe 'Pipeline Editor', :js, feature_category: :pipeline_authoring do
end
end
- it 'user who tries to navigate away can confirm the action and discard their change' do
+ it 'user who tries to navigate away can confirm the action and discard their change', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410496' do
click_link 'Pipelines'
page.driver.browser.switch_to.alert.accept
diff --git a/spec/features/projects/ci/lint_spec.rb b/spec/features/projects/ci/lint_spec.rb
index 4fea07b18bc..bc370a296e4 100644
--- a/spec/features/projects/ci/lint_spec.rb
+++ b/spec/features/projects/ci/lint_spec.rb
@@ -2,8 +2,8 @@
require 'spec_helper'
-RSpec.describe 'CI Lint', :js, feature_category: :pipeline_authoring do
- include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
+RSpec.describe 'CI Lint', :js, feature_category: :pipeline_composition do
+ include Features::SourceEditorSpecHelpers
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index 114182982e2..f9195904ea3 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Gcp Cluster', :js, feature_category: :kubernetes_management do
+RSpec.describe 'Gcp Cluster', :js, feature_category: :deployment_management do
include GoogleApi::CloudPlatformHelpers
let(:project) { create(:project) }
diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb
index 34fc0a76c7f..eb2601bb85f 100644
--- a/spec/features/projects/clusters/user_spec.rb
+++ b/spec/features/projects/clusters/user_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'User Cluster', :js, feature_category: :kubernetes_management do
+RSpec.describe 'User Cluster', :js, feature_category: :deployment_management do
include GoogleApi::CloudPlatformHelpers
let(:project) { create(:project) }
diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb
index 93ce851521f..b608fc953f3 100644
--- a/spec/features/projects/commit/cherry_pick_spec.rb
+++ b/spec/features/projects/commit/cherry_pick_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe 'Cherry-pick Commits', :js, feature_category: :source_code_manage
cherry_pick_commit
- expect(page).to have_content('Sorry, we cannot cherry-pick this commit automatically.')
+ expect(page).to have_content('Commit cherry-pick failed:')
end
end
diff --git a/spec/features/projects/commit/comments/user_adds_comment_spec.rb b/spec/features/projects/commit/comments/user_adds_comment_spec.rb
index c53ac27bb5f..b0cb57f158d 100644
--- a/spec/features/projects/commit/comments/user_adds_comment_spec.rb
+++ b/spec/features/projects/commit/comments/user_adds_comment_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
RSpec.describe "User adds a comment on a commit", :js, feature_category: :source_code_management do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
include RepoHelpers
let(:comment_text) { "XML attached" }
@@ -36,7 +36,7 @@ RSpec.describe "User adds a comment on a commit", :js, feature_category: :source
expect(page).not_to have_css(".js-note-text")
# Check on the `Write` tab
- click_button("Write")
+ click_button("Continue editing")
expect(page).to have_field("note[note]", with: "#{comment_text} #{emoji}")
@@ -107,7 +107,7 @@ RSpec.describe "User adds a comment on a commit", :js, feature_category: :source
# Test UI elements, then submit.
page.within("form[data-line-code='#{sample_commit.line_code}']") do
expect(find(".js-note-text", visible: false).text).to eq("")
- expect(page).to have_css('.js-md-write-button')
+ expect(page).to have_css('.js-md-preview')
click_button("Comment")
end
diff --git a/spec/features/projects/commit/comments/user_deletes_comments_spec.rb b/spec/features/projects/commit/comments/user_deletes_comments_spec.rb
index a1e7ddb4d6e..e265756f930 100644
--- a/spec/features/projects/commit/comments/user_deletes_comments_spec.rb
+++ b/spec/features/projects/commit/comments/user_deletes_comments_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
RSpec.describe "User deletes comments on a commit", :js, feature_category: :source_code_management do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
include Spec::Support::Helpers::ModalHelpers
include RepoHelpers
@@ -30,7 +30,7 @@ RSpec.describe "User deletes comments on a commit", :js, feature_category: :sour
note.hover
find(".more-actions").click
- find(".more-actions .dropdown-menu li", match: :first)
+ find(".more-actions li", match: :first)
find(".js-note-delete").click
end
diff --git a/spec/features/projects/commit/comments/user_edits_comments_spec.rb b/spec/features/projects/commit/comments/user_edits_comments_spec.rb
index 9019a981a18..b0b963de91b 100644
--- a/spec/features/projects/commit/comments/user_edits_comments_spec.rb
+++ b/spec/features/projects/commit/comments/user_edits_comments_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
RSpec.describe "User edits a comment on a commit", :js, feature_category: :source_code_management do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
include RepoHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/features/projects/commit/diff_notes_spec.rb b/spec/features/projects/commit/diff_notes_spec.rb
index f29e0803f61..1f4358db9cd 100644
--- a/spec/features/projects/commit/diff_notes_spec.rb
+++ b/spec/features/projects/commit/diff_notes_spec.rb
@@ -8,18 +8,15 @@ RSpec.describe 'Commit diff', :js, feature_category: :source_code_management do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
- using RSpec::Parameterized::TableSyntax
-
- where(:view, :async_diff_file_loading) do
- 'inline' | true
- 'inline' | false
- 'parallel' | true
- 'parallel' | false
+ where(:view) do
+ [
+ ['inline'],
+ ['parallel']
+ ]
end
with_them do
before do
- stub_feature_flags(async_commit_diff_files: async_diff_file_loading)
project.add_maintainer(user)
sign_in user
visit project_commit_path(project, sample_commit.id, view: view)
diff --git a/spec/features/projects/commit/user_comments_on_commit_spec.rb b/spec/features/projects/commit/user_comments_on_commit_spec.rb
index 66a407b5ff6..709914434e7 100644
--- a/spec/features/projects/commit/user_comments_on_commit_spec.rb
+++ b/spec/features/projects/commit/user_comments_on_commit_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
RSpec.describe "User comments on commit", :js, feature_category: :source_code_management do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
include Spec::Support::Helpers::ModalHelpers
include RepoHelpers
@@ -38,7 +38,7 @@ RSpec.describe "User comments on commit", :js, feature_category: :source_code_ma
expect(page).not_to have_css(".js-note-text")
# Check on `Write` tab
- click_button("Write")
+ click_button("Continue editing")
expect(page).to have_field("note[note]", with: "#{comment_text} #{emoji_code}")
@@ -109,7 +109,7 @@ RSpec.describe "User comments on commit", :js, feature_category: :source_code_ma
note.hover
find(".more-actions").click
- find(".more-actions .dropdown-menu li", match: :first)
+ find(".more-actions li", match: :first)
find(".js-note-delete").click
end
diff --git a/spec/features/projects/commit/user_reverts_commit_spec.rb b/spec/features/projects/commit/user_reverts_commit_spec.rb
index 8c7b8e6ba32..4d2abf55675 100644
--- a/spec/features/projects/commit/user_reverts_commit_spec.rb
+++ b/spec/features/projects/commit/user_reverts_commit_spec.rb
@@ -47,7 +47,7 @@ RSpec.describe 'User reverts a commit', :js, feature_category: :source_code_mana
revert_commit
- expect(page).to have_content('Sorry, we cannot revert this commit automatically.')
+ expect(page).to have_content('Commit revert failed:')
end
end
diff --git a/spec/features/projects/commit/user_sees_pipelines_tab_spec.rb b/spec/features/projects/commit/user_sees_pipelines_tab_spec.rb
new file mode 100644
index 00000000000..da83bbcb63a
--- /dev/null
+++ b/spec/features/projects/commit/user_sees_pipelines_tab_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Commit > Pipelines tab', :js, feature_category: :source_code_management do
+ let_it_be_with_reload(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ context 'when commit has pipelines' do
+ let_it_be(:pipeline) do
+ create(:ci_pipeline,
+ :success,
+ project: project,
+ ref: project.default_branch,
+ sha: project.commit.sha)
+ end
+
+ let_it_be(:job) { create(:ci_build, :success, pipeline: pipeline) }
+ let_it_be(:manual_job) { create(:ci_build, :manual, pipeline: pipeline) }
+
+ before do
+ visit project_commit_path(project, project.commit.id)
+ wait_for_requests
+ end
+
+ it 'displays pipelines table' do
+ page.within('.commit-ci-menu') do
+ click_link('Pipelines')
+ end
+
+ wait_for_requests
+
+ page.within('[data-testid="pipeline-table-row"]') do
+ expect(page).to have_selector('.ci-success')
+ expect(page).to have_content(pipeline.id)
+ expect(page).to have_content('API')
+ expect(page).to have_css('[data-testid="pipeline-mini-graph"]')
+ expect(page).to have_css('[data-testid="pipelines-manual-actions-dropdown"]')
+ expect(page).to have_css('[data-testid="pipeline-multi-actions-dropdown"]')
+ end
+ end
+ end
+
+ context 'when commit does not have pipelines' do
+ before do
+ visit project_commit_path(project, project.commit.id)
+ end
+
+ it 'does not display pipelines tab link' do
+ expect(page).not_to have_link('Pipelines')
+ end
+ end
+end
diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb
index 8284299443f..4c13d23559b 100644
--- a/spec/features/projects/compare_spec.rb
+++ b/spec/features/projects/compare_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe "Compare", :js, feature_category: :projects do
sign_in user
end
- describe "branches" do
+ shared_examples "compare view of branches" do
shared_examples 'compares branches' do
it 'compares branches' do
visit project_compare_index_path(project, from: 'master', to: 'master')
@@ -114,7 +114,7 @@ RSpec.describe "Compare", :js, feature_category: :projects do
click_button('Compare')
page.within('[data-testid="too-many-changes-alert"]') do
- expect(page).to have_text("Too many changes to show. To preserve performance only 3 of 3+ files are displayed.")
+ expect(page).to have_text("Some changes are not shown. For a faster browsing experience, only 3 of 3+ files are shown. Download one of the files below to see all changes.")
end
end
end
@@ -148,7 +148,7 @@ RSpec.describe "Compare", :js, feature_category: :projects do
end
end
- describe "tags" do
+ shared_examples "compare view of tags" do
it "compares tags" do
visit project_compare_index_path(project, from: "master", to: "master")
@@ -182,4 +182,17 @@ RSpec.describe "Compare", :js, feature_category: :projects do
dropdown.all(".js-compare-#{dropdown_type}-dropdown .dropdown-item", text: selection).first.click
end
end
+
+ it_behaves_like "compare view of branches"
+ it_behaves_like "compare view of tags"
+
+ context "when super sidebar is enabled" do
+ before do
+ user.update!(use_new_navigation: true)
+ stub_feature_flags(super_sidebar_nav: true)
+ end
+
+ it_behaves_like "compare view of branches"
+ it_behaves_like "compare view of tags"
+ end
end
diff --git a/spec/features/projects/container_registry_spec.rb b/spec/features/projects/container_registry_spec.rb
index 98cf024afa8..5306a9f15c6 100644
--- a/spec/features/projects/container_registry_spec.rb
+++ b/spec/features/projects/container_registry_spec.rb
@@ -30,6 +30,20 @@ RSpec.describe 'Container Registry', :js, feature_category: :projects do
expect(page).to have_title _('Container Registry')
end
+ it 'does not have link to settings' do
+ visit_container_registry
+
+ expect(page).not_to have_link _('Configure in settings')
+ end
+
+ it 'has link to settings when user is maintainer' do
+ project.add_maintainer(user)
+
+ visit_container_registry
+
+ expect(page).to have_link _('Configure in settings')
+ end
+
context 'when there are no image repositories' do
it 'list page has no container title' do
visit_container_registry
@@ -63,7 +77,8 @@ RSpec.describe 'Container Registry', :js, feature_category: :projects do
expect(DeleteContainerRepositoryWorker).not_to receive(:perform_async)
find('[title="Remove repository"]').click
- expect(find('.modal .modal-title')).to have_content _('Remove repository')
+ expect(find('.modal .modal-title')).to have_content _('Delete image repository?')
+ find('.modal .modal-body input').set('my/image')
find('.modal .modal-footer .btn-danger').click
end
@@ -101,7 +116,11 @@ RSpec.describe 'Container Registry', :js, feature_category: :projects do
first('[data-testid="additional-actions"]').click
first('[data-testid="single-delete-button"]').click
expect(find('.modal .modal-title')).to have_content _('Remove tag')
+ stub_container_registry_tags(repository: %r{my/image}, tags: ('1'..'19').to_a, with_manifest: true)
find('.modal .modal-footer .btn-danger').click
+
+ expect(page).to have_content '19 tags'
+ expect(page).not_to have_content '20 tags'
end
it('pagination navigate to the second page') do
diff --git a/spec/features/projects/environments/environment_metrics_spec.rb b/spec/features/projects/environments/environment_metrics_spec.rb
index 4a112445ab9..e212d464029 100644
--- a/spec/features/projects/environments/environment_metrics_spec.rb
+++ b/spec/features/projects/environments/environment_metrics_spec.rb
@@ -14,10 +14,13 @@ RSpec.describe 'Environment > Metrics', feature_category: :projects do
let!(:staging) { create(:environment, name: 'staging', project: project) }
before do
+ stub_feature_flags(remove_monitor_metrics: false)
+
project.add_developer(user)
stub_any_prometheus_request
sign_in(user)
+ stub_feature_flags(remove_monitor_metrics: false)
end
around do |example|
@@ -65,6 +68,18 @@ RSpec.describe 'Environment > Metrics', feature_category: :projects do
it_behaves_like 'has environment selector'
end
+ context 'when metrics dashboard feature is unavailable' do
+ before do
+ stub_feature_flags(remove_monitor_metrics: true)
+ end
+
+ it 'does not provide a link to the monitoring dashboard' do
+ visit_environment(environment)
+
+ expect(page).not_to have_link('Monitoring')
+ end
+ end
+
def visit_environment(environment)
visit project_environment_path(environment.project, environment)
end
diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb
index 91401d19fd1..527a146ff73 100644
--- a/spec/features/projects/environments/environment_spec.rb
+++ b/spec/features/projects/environments/environment_spec.rb
@@ -94,6 +94,36 @@ RSpec.describe 'Environment', feature_category: :projects do
expect(page).to have_link("#{build.name} (##{build.id})")
end
end
+
+ context 'with related deployable present' do
+ let_it_be(:previous_pipeline) { create(:ci_pipeline, project: project) }
+
+ let_it_be(:previous_build) do
+ create(:ci_build, :success, pipeline: previous_pipeline, environment: environment.name)
+ end
+
+ let_it_be(:previous_deployment) do
+ create(:deployment, :success, environment: environment, deployable: previous_build)
+ end
+
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:build) { create(:ci_build, pipeline: pipeline, environment: environment.name) }
+
+ let_it_be(:deployment) do
+ create(:deployment, :success, environment: environment, deployable: build)
+ end
+
+ before do
+ visit_environment(environment)
+ end
+
+ it 'shows deployment information and buttons', :js do
+ wait_for_requests
+ expect(page).to have_button('Re-deploy to environment')
+ expect(page).to have_button('Rollback environment')
+ expect(page).to have_link("#{build.name} (##{build.id})")
+ end
+ end
end
end
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 788bf6477b1..b50fc59ac32 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -31,16 +31,16 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
end
describe 'page tabs' do
- it 'shows "Available" and "Stopped" tab with links' do
- visit_environments(project)
-
- expect(page).to have_link(_('Available'))
- expect(page).to have_link(_('Stopped'))
- end
-
describe 'with one available environment' do
let!(:environment) { create(:environment, project: project, state: :available) }
+ it 'shows "Available" and "Stopped" tab with links' do
+ visit_environments(project)
+
+ expect(page).to have_link(_('Available'))
+ expect(page).to have_link(_('Stopped'))
+ end
+
describe 'in available tab page' do
it 'shows one environment' do
visit_environments(project, scope: 'available')
@@ -70,7 +70,7 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
it 'shows no environments' do
visit_environments(project, scope: 'stopped')
- expect(page).to have_content(s_('Environments|You don\'t have any stopped environments.'))
+ expect(page).to have_content(s_('Environments|Get started with environments'))
end
end
@@ -99,7 +99,7 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
it 'shows no environments' do
visit_environments(project, scope: 'available')
- expect(page).to have_content(s_('Environments|You don\'t have any environments.'))
+ expect(page).to have_content(s_('Environments|Get started with environments'))
end
end
@@ -119,11 +119,11 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
visit_environments(project)
end
- it 'does not show environments and counters are set to zero' do
- expect(page).to have_content(s_('Environments|You don\'t have any environments.'))
+ it 'does not show environments and tabs' do
+ expect(page).to have_content(s_('Environments|Get started with environments'))
- expect(page).to have_link("#{_('Available')} 0")
- expect(page).to have_link("#{_('Stopped')} 0")
+ expect(page).not_to have_link(_('Available'))
+ expect(page).not_to have_link(_('Stopped'))
end
end
@@ -175,7 +175,7 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
context 'when builds and manual actions are present' do
let!(:pipeline) { create(:ci_pipeline, project: project) }
- let!(:build) { create(:ci_build, pipeline: pipeline) }
+ let!(:build) { create(:ci_build, :success, pipeline: pipeline) }
let!(:action) do
create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production')
@@ -207,8 +207,14 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
.not_to change { Ci::Pipeline.count }
end
- it 'shows a stop button' do
+ it 'shows a stop button and dialog' do
expect(page).to have_selector(stop_button_selector)
+
+ click_button(_('Stop'))
+
+ within('.modal-body') do
+ expect(page).to have_css('.warning_message')
+ end
end
it 'does not show external link button' do
@@ -216,7 +222,6 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
end
it 'does not show terminal button' do
- expect(page).not_to have_button(_('More actions'))
expect(page).not_to have_terminal_button
end
@@ -242,8 +247,14 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
on_stop: 'close_app')
end
- it 'shows a stop button' do
+ it 'shows a stop button and dialog' do
expect(page).to have_selector(stop_button_selector)
+
+ click_button(_('Stop'))
+
+ within('.modal-body') do
+ expect(page).not_to have_css('.warning_message')
+ end
end
context 'when user is a reporter' do
@@ -273,7 +284,6 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
let(:role) { :developer }
it 'does not show terminal button' do
- expect(page).not_to have_button(_('More actions'))
expect(page).not_to have_terminal_button
end
end
@@ -344,7 +354,7 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
wait_for_requests
end
- it 'enqueues the delayed job', :js do
+ it 'enqueues the delayed job', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/409990' do
expect(delayed_job.reload).to be_pending
end
end
@@ -360,7 +370,7 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
sha: project.commit.id)
end
- it 'does not show deployments' do
+ it 'does not show deployments', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/409990' do
visit_environments(project)
page.click_button _('Expand')
@@ -393,7 +403,7 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
it 'does have a new environment button' do
visit_environments(project)
- expect(page).to have_link('New environment')
+ expect(page).to have_link('Create an environment')
end
describe 'creating a new environment' do
@@ -405,7 +415,7 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
let(:role) { :developer }
it 'developer creates a new environment with a valid name' do
- click_link 'New environment'
+ click_link 'Create an environment'
fill_in('Name', with: 'production')
click_on 'Save'
@@ -413,7 +423,7 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
end
it 'developer creates a new environment with invalid name' do
- click_link 'New environment'
+ click_link 'Create an environment'
fill_in('Name', with: 'name,with,commas')
click_on 'Save'
diff --git a/spec/features/projects/files/dockerfile_dropdown_spec.rb b/spec/features/projects/files/dockerfile_dropdown_spec.rb
index 1e05bdae204..ec1f03570d9 100644
--- a/spec/features/projects/files/dockerfile_dropdown_spec.rb
+++ b/spec/features/projects/files/dockerfile_dropdown_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > User wants to add a Dockerfile file', :js, feature_category: :projects do
- include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
+ include Features::SourceEditorSpecHelpers
before do
project = create(:project, :repository)
diff --git a/spec/features/projects/files/editing_a_file_spec.rb b/spec/features/projects/files/editing_a_file_spec.rb
index 04f45de42cc..1f928da0427 100644
--- a/spec/features/projects/files/editing_a_file_spec.rb
+++ b/spec/features/projects/files/editing_a_file_spec.rb
@@ -3,7 +3,8 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > User wants to edit a file', feature_category: :projects do
- let(:project) { create(:project, :repository) }
+ include ProjectForksHelper
+ let(:project) { create(:project, :repository, :public) }
let(:user) { project.first_owner }
let(:commit_params) do
{
@@ -17,17 +18,48 @@ RSpec.describe 'Projects > Files > User wants to edit a file', feature_category:
}
end
- before do
- sign_in user
- visit project_edit_blob_path(project,
- File.join(project.default_branch, '.gitignore'))
+ context 'when the user has write access' do
+ before do
+ sign_in user
+ visit project_edit_blob_path(project,
+ File.join(project.default_branch, '.gitignore'))
+ end
+
+ it 'file has been updated since the user opened the edit page' do
+ Files::UpdateService.new(project, user, commit_params).execute
+
+ click_button 'Commit changes'
+
+ expect(page).to have_content 'Someone edited the file the same time you did.'
+ end
end
- it 'file has been updated since the user opened the edit page' do
- Files::UpdateService.new(project, user, commit_params).execute
+ context 'when the user does not have write access' do
+ let(:user) { create(:user) }
+
+ context 'and the user has a fork of the project' do
+ let(:forked_project) { fork_project(project, user, namespace: user.namespace, repository: true) }
+
+ before do
+ forked_project
+ sign_in user
+ visit project_edit_blob_path(project,
+ File.join(project.default_branch, '.gitignore'))
+ end
+
+ context 'and the forked project is ahead of the upstream project' do
+ before do
+ Files::UpdateService.new(forked_project, user, commit_params).execute
+ end
- click_button 'Commit changes'
+ it 'renders an error message' do
+ click_button 'Commit changes'
- expect(page).to have_content 'Someone edited the file the same time you did.'
+ expect(page).to have_content(
+ %(Error: Can't edit this file. The fork and upstream project have diverged. Edit the file on the fork)
+ )
+ end
+ end
+ end
end
end
diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb
index 5e11a94e65b..eedb79167bd 100644
--- a/spec/features/projects/files/gitignore_dropdown_spec.rb
+++ b/spec/features/projects/files/gitignore_dropdown_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > User wants to add a .gitignore file', :js, feature_category: :projects do
- include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
+ include Features::SourceEditorSpecHelpers
before do
project = create(:project, :repository)
diff --git a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
index 67678a937e5..f2d657b3513 100644
--- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
+++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js, feature_category: :projects do
- include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
+ include Features::SourceEditorSpecHelpers
let(:params) { {} }
let(:filename) { '.gitlab-ci.yml' }
diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
index 8d64151e680..cfa55eba188 100644
--- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
+++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > Project owner sees a link to create a license file in empty project', :js,
feature_category: :projects do
- include WebIdeSpecHelpers
+ include Features::WebIdeSpecHelpers
let(:project) { create(:project_empty_repo) }
let(:project_maintainer) { project.first_owner }
diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb
index 8082d1bdf63..9b9c2158432 100644
--- a/spec/features/projects/files/user_browses_files_spec.rb
+++ b/spec/features/projects/files/user_browses_files_spec.rb
@@ -11,8 +11,7 @@ RSpec.describe "User browses files", :js, feature_category: :projects do
"A fork of this project has been created that you can make changes in, so you can submit a merge request."
end
- let(:project) { create(:project, :repository, name: "Shop") }
- let(:project2) { create(:project, :repository, name: "Another Project", path: "another-project") }
+ let_it_be(:project) { create(:project, :repository) }
let(:tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
let(:user) { project.first_owner }
@@ -142,7 +141,9 @@ RSpec.describe "User browses files", :js, feature_category: :projects do
expect(page).to have_current_path(project_blob_path(project, "markdown/doc/raketasks/maintenance.md"), ignore_query: true)
expect(page).to have_content("bundle exec rake gitlab:env:info RAILS_ENV=production")
- click_link("shop")
+ page.within(".tree-ref-container") do
+ click_link(project.path)
+ end
page.within(".tree-table") do
click_link("README.md")
diff --git a/spec/features/projects/files/user_creates_files_spec.rb b/spec/features/projects/files/user_creates_files_spec.rb
index 97ccb45dfc6..42aceef256a 100644
--- a/spec/features/projects/files/user_creates_files_spec.rb
+++ b/spec/features/projects/files/user_creates_files_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > User creates files', :js, feature_category: :projects do
- include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
- include BlobSpecHelpers
+ include Features::SourceEditorSpecHelpers
+ include Features::BlobSpecHelpers
let(:fork_message) do
"You're not allowed to make changes to this project directly. "\
diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb
index 5a61aa146a2..779257b2e2b 100644
--- a/spec/features/projects/files/user_edits_files_spec.rb
+++ b/spec/features/projects/files/user_edits_files_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > User edits files', :js, feature_category: :projects do
- include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
+ include Features::SourceEditorSpecHelpers
include ProjectForksHelper
- include BlobSpecHelpers
+ include Features::BlobSpecHelpers
let(:project) { create(:project, :repository, name: 'Shop') }
let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb
index 8b484141a95..39cdc8faa85 100644
--- a/spec/features/projects/fork_spec.rb
+++ b/spec/features/projects/fork_spec.rb
@@ -119,16 +119,6 @@ RSpec.describe 'Project fork', feature_category: :projects do
end
end
- shared_examples "increments the fork counter on the source project's page" do
- specify :sidekiq_might_not_need_inline do
- create_forks
-
- visit project_path(project)
-
- expect(page).to have_css('.fork-count', text: 2)
- end
- end
-
it_behaves_like 'fork button on project page'
it_behaves_like 'create fork page', 'Fork project'
@@ -185,25 +175,17 @@ RSpec.describe 'Project fork', feature_category: :projects do
end
end
- context 'with cache_home_panel feature flag' do
+ context 'when user is a maintainer in multiple groups' do
before do
create(:group_member, :maintainer, user: user, group: group2)
end
- context 'when caching is enabled' do
- before do
- stub_feature_flags(cache_home_panel: project)
- end
-
- it_behaves_like "increments the fork counter on the source project's page"
- end
+ it "increments the fork counter on the source project's page", :sidekiq_might_not_need_inline do
+ create_forks
- context 'when caching is disabled' do
- before do
- stub_feature_flags(cache_home_panel: false)
- end
+ visit project_path(project)
- it_behaves_like "increments the fork counter on the source project's page"
+ expect(page).to have_css('.fork-count', text: 2)
end
end
end
diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb
index 6630956f835..3c39d8745a4 100644
--- a/spec/features/projects/import_export/export_file_spec.rb
+++ b/spec/features/projects/import_export/export_file_spec.rb
@@ -40,59 +40,28 @@ RSpec.describe 'Import/Export - project export integration test', :js, feature_c
sign_in(user)
end
- context "with streaming serializer" do
- before do
- stub_feature_flags(project_export_as_ndjson: false)
- end
-
- it 'exports a project successfully', :sidekiq_inline do
- export_project_and_download_file(page, project)
-
- in_directory_with_expanded_export(project) do |exit_status, tmpdir|
- expect(exit_status).to eq(0)
+ it 'exports a project successfully', :sidekiq_inline do
+ export_project_and_download_file(page, project)
- project_json_path = File.join(tmpdir, 'project.json')
- expect(File).to exist(project_json_path)
+ in_directory_with_expanded_export(project) do |exit_status, tmpdir|
+ expect(exit_status).to eq(0)
- project_hash = Gitlab::Json.parse(File.read(project_json_path))
-
- sensitive_words.each do |sensitive_word|
- found = find_sensitive_attributes(sensitive_word, project_hash)
+ project_json_path = File.join(tmpdir, 'tree', 'project.json')
+ expect(File).to exist(project_json_path)
- expect(found).to be_nil, failure_message(found.try(:key_found), found.try(:parent), sensitive_word)
+ relations = []
+ relations << Gitlab::Json.parse(File.read(project_json_path))
+ Dir.glob(File.join(tmpdir, 'tree/project', '*.ndjson')) do |rb_filename|
+ File.foreach(rb_filename) do |line|
+ relations << Gitlab::Json.parse(line)
end
end
- end
- end
- context "with ndjson" do
- before do
- stub_feature_flags(project_export_as_ndjson: true)
- end
-
- it 'exports a project successfully', :sidekiq_inline do
- export_project_and_download_file(page, project)
-
- in_directory_with_expanded_export(project) do |exit_status, tmpdir|
- expect(exit_status).to eq(0)
-
- project_json_path = File.join(tmpdir, 'tree', 'project.json')
- expect(File).to exist(project_json_path)
-
- relations = []
- relations << Gitlab::Json.parse(File.read(project_json_path))
- Dir.glob(File.join(tmpdir, 'tree/project', '*.ndjson')) do |rb_filename|
- File.foreach(rb_filename) do |line|
- relations << Gitlab::Json.parse(line)
- end
- end
-
- relations.each do |relation_hash|
- sensitive_words.each do |sensitive_word|
- found = find_sensitive_attributes(sensitive_word, relation_hash)
+ relations.each do |relation_hash|
+ sensitive_words.each do |sensitive_word|
+ found = find_sensitive_attributes(sensitive_word, relation_hash)
- expect(found).to be_nil, failure_message(found.try(:key_found), found.try(:parent), sensitive_word)
- end
+ expect(found).to be_nil, failure_message(found.try(:key_found), found.try(:parent), sensitive_word)
end
end
end
diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb
index 8fb11f06cdd..f4ed0728402 100644
--- a/spec/features/projects/import_export/import_file_spec.rb
+++ b/spec/features/projects/import_export/import_file_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'Import/Export - project import integration test', :js, feature_c
let(:export_path) { "#{Dir.tmpdir}/import_file_spec" }
before do
+ stub_application_setting(import_sources: ['gitlab_project'])
stub_uploads_object_storage(FileUploader)
allow_next_instance_of(Gitlab::ImportExport) do |instance|
allow(instance).to receive(:storage_path).and_return(export_path)
diff --git a/spec/features/projects/import_export/test_project_export.tar.gz b/spec/features/projects/import_export/test_project_export.tar.gz
index b93da033aea..d34d72920dd 100644
--- a/spec/features/projects/import_export/test_project_export.tar.gz
+++ b/spec/features/projects/import_export/test_project_export.tar.gz
Binary files differ
diff --git a/spec/features/projects/integrations/apple_app_store_spec.rb b/spec/features/projects/integrations/apple_app_store_spec.rb
new file mode 100644
index 00000000000..a5ae7df4a89
--- /dev/null
+++ b/spec/features/projects/integrations/apple_app_store_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Upload Dropzone Field', feature_category: :integrations do
+ include_context 'project integration activation'
+
+ it 'uploads the file data to the correct form fields and updates the messaging correctly', :js, :aggregate_failures do
+ visit_project_integration('Apple App Store Connect')
+
+ expect(page).to have_content('Drag your Private Key file here or click to upload.')
+ expect(page).not_to have_content('auth_key.p8')
+
+ find("input[name='service[dropzone_file_name]']",
+ visible: false).set(Rails.root.join('spec/fixtures/auth_key.p8'))
+
+ expect(page).to have_field("service[app_store_private_key]", type: :hidden,
+ with: File.read(Rails.root.join('spec/fixtures/auth_key.p8')))
+ expect(page).to have_field("service[app_store_private_key_file_name]", type: :hidden, with: 'auth_key.p8')
+
+ expect(page).not_to have_content('Drag your Private Key file here or click to upload.')
+ expect(page).to have_content('auth_key.p8')
+ end
+end
diff --git a/spec/features/projects/integrations/google_play_spec.rb b/spec/features/projects/integrations/google_play_spec.rb
new file mode 100644
index 00000000000..db867fc40d7
--- /dev/null
+++ b/spec/features/projects/integrations/google_play_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Upload Dropzone Field', feature_category: :integrations do
+ include_context 'project integration activation'
+
+ it 'uploads the file data to the correct form fields and updates the messaging correctly', :js, :aggregate_failures do
+ visit_project_integration('Google Play')
+
+ expect(page).to have_content('Drag your key file here or click to upload.')
+ expect(page).not_to have_content('service_account.json')
+
+ find("input[name='service[dropzone_file_name]']",
+ visible: false).set(Rails.root.join('spec/fixtures/service_account.json'))
+
+ expect(page).to have_field("service[service_account_key]", type: :hidden,
+ with: File.read(Rails.root.join('spec/fixtures/service_account.json')))
+ expect(page).to have_field("service[service_account_key_file_name]", type: :hidden, with: 'service_account.json')
+
+ expect(page).not_to have_content('Drag your key file here or click to upload.')
+ expect(page).to have_content('service_account.json')
+ end
+end
diff --git a/spec/features/projects/integrations/project_integrations_spec.rb b/spec/features/projects/integrations/project_integrations_spec.rb
index d99b6ca9092..94dbc401726 100644
--- a/spec/features/projects/integrations/project_integrations_spec.rb
+++ b/spec/features/projects/integrations/project_integrations_spec.rb
@@ -12,4 +12,16 @@ RSpec.describe 'Project integrations', :js, feature_category: :integrations do
visit_project_integration(integration.title)
end
end
+
+ context 'with remove_monitor_metrics flag enabled' do
+ before do
+ stub_feature_flags(remove_monitor_metrics: true)
+ end
+
+ it 'returns a 404 for the prometheus edit page' do
+ visit edit_project_settings_integration_path(project, :prometheus)
+
+ expect(page).to have_content "Page Not Found"
+ end
+ end
end
diff --git a/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb b/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb
index 16c7a3ff226..aea76944c7f 100644
--- a/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb
+++ b/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb
@@ -79,7 +79,7 @@ RSpec.describe 'Set up Mattermost slash commands', :js, feature_category: :integ
select_element = find('#mattermost_team_id')
- expect(select_element['disabled']).to be_falsey
+ expect(select_element['disabled']).to eq('false')
expect(select_element.all('option').count).to eq(3)
end
@@ -99,7 +99,7 @@ RSpec.describe 'Set up Mattermost slash commands', :js, feature_category: :integ
click_link 'Add to Mattermost'
- expect(find('input[type="submit"]')['disabled']).not_to eq("true")
+ expect(find('button[type="submit"]')['disabled']).not_to eq("true")
end
it 'disables the submit button if the required fields are not provided', :js do
@@ -109,7 +109,7 @@ RSpec.describe 'Set up Mattermost slash commands', :js, feature_category: :integ
fill_in('mattermost_trigger', with: '')
- expect(find('input[type="submit"]')['disabled']).to eq("true")
+ expect(find('button[type="submit"]')['disabled']).to eq("true")
end
def stub_teams(count: 0)
@@ -145,7 +145,7 @@ RSpec.describe 'Set up Mattermost slash commands', :js, feature_category: :integ
it 'shows a token placeholder' do
token_placeholder = find_field('service_token')['placeholder']
- expect(token_placeholder).to eq('XXxxXXxxXXxxXXxxXXxxXXxx')
+ expect(token_placeholder).to eq('')
end
end
end
diff --git a/spec/features/projects/integrations/user_activates_prometheus_spec.rb b/spec/features/projects/integrations/user_activates_prometheus_spec.rb
index 5b2d885410f..a47000672ca 100644
--- a/spec/features/projects/integrations/user_activates_prometheus_spec.rb
+++ b/spec/features/projects/integrations/user_activates_prometheus_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'User activates Prometheus', feature_category: :integrations do
include_context 'project integration activation'
before do
+ stub_feature_flags(remove_monitor_metrics: false)
stub_request(:get, /.*prometheus.example.com.*/)
end
diff --git a/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb b/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb
index ec00dcaf046..01c202baf70 100644
--- a/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb
+++ b/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe 'User activates Slack notifications', :js, feature_category: :int
context 'when integration is not configured yet' do
before do
- stub_feature_flags(integration_slack_app_notifications: false)
visit_project_integration('Slack notifications')
end
diff --git a/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb b/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb
index 0f6d721565e..38491501c65 100644
--- a/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb
+++ b/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'Slack slash commands', :js, feature_category: :integrations do
it 'shows a token placeholder' do
token_placeholder = find_field('Token')['placeholder']
- expect(token_placeholder).to eq('XXxxXXxxXXxxXXxxXXxxXXxx')
+ expect(token_placeholder).to eq('')
end
it 'shows a help message' do
diff --git a/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb b/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb
index e0063a9c733..9ff344bcc88 100644
--- a/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb
+++ b/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb
@@ -22,17 +22,17 @@ RSpec.describe 'User uses inherited settings', :js, feature_category: :integrati
expect(page).not_to have_button('Use custom settings')
expect(page).to have_field('Web URL', with: parent_settings[:url], readonly: true)
- expect(page).to have_field('Enter new password or API token', with: '', readonly: true)
+ expect(page).to have_field('New API token, password, or Jira personal access token', with: '', readonly: true)
click_on 'Use default settings'
click_on 'Use custom settings'
expect(page).not_to have_button('Use default settings')
expect(page).to have_field('Web URL', with: project_settings[:url], readonly: false)
- expect(page).to have_field('Enter new password or API token', with: '', readonly: false)
+ expect(page).to have_field('New API token, password, or Jira personal access token', with: '', readonly: false)
fill_in 'Web URL', with: 'http://custom.com'
- fill_in 'Enter new password or API token', with: 'custom'
+ fill_in 'New API token, password, or Jira personal access token', with: 'custom'
click_save_integration
@@ -53,14 +53,14 @@ RSpec.describe 'User uses inherited settings', :js, feature_category: :integrati
expect(page).not_to have_button('Use default settings')
expect(page).to have_field('URL', with: project_settings[:url], readonly: false)
- expect(page).to have_field('Enter new password or API token', with: '', readonly: false)
+ expect(page).to have_field('New API token, password, or Jira personal access token', with: '', readonly: false)
click_on 'Use custom settings'
click_on 'Use default settings'
expect(page).not_to have_button('Use custom settings')
expect(page).to have_field('URL', with: parent_settings[:url], readonly: true)
- expect(page).to have_field('Enter new password or API token', with: '', readonly: true)
+ expect(page).to have_field('New API token, password, or Jira personal access token', with: '', readonly: true)
click_save_integration
diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb
index adf410ce6e8..77f88994bfb 100644
--- a/spec/features/projects/issuable_templates_spec.rb
+++ b/spec/features/projects/issuable_templates_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'issuable templates', :js, feature_category: :projects do
include ProjectForksHelper
+ include CookieHelper
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
@@ -12,6 +13,7 @@ RSpec.describe 'issuable templates', :js, feature_category: :projects do
before do
project.add_maintainer(user)
sign_in user
+ set_cookie('new-actions-popover-viewed', 'true')
end
context 'user creates an issue using templates' do
diff --git a/spec/features/projects/issues/viewing_relocated_issues_spec.rb b/spec/features/projects/issues/viewing_relocated_issues_spec.rb
index abd36b3ceef..f86f7bfacbd 100644
--- a/spec/features/projects/issues/viewing_relocated_issues_spec.rb
+++ b/spec/features/projects/issues/viewing_relocated_issues_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'issues canonical link', feature_category: :team_planning do
- include Spec::Support::Helpers::Features::CanonicalLinkHelpers
+ include Features::CanonicalLinkHelpers
let_it_be(:original_project) { create(:project, :public) }
let_it_be(:original_issue) { create(:issue, project: original_project) }
diff --git a/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb b/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb
index a9e0fce1a1c..e4394010e8c 100644
--- a/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb
+++ b/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe 'User triggers manual job with variables', :js, feature_category:
find("[data-testid='ci-variable-value']").set('key_value')
end
- find("[data-testid='trigger-manual-job-btn']").click
+ find("[data-testid='run-manual-job-btn']").click
wait_for_requests
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index 67389fdda8a..796bac2e8e7 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -232,7 +232,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :proj
expect(page).to have_link('New issue')
end
- it 'links to issues/new with the title and description filled in' do
+ it 'links to issues/new with the title and description filled in', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408222' do
button_title = "Job Failed ##{job.id}"
job_url = project_job_url(project, job, host: page.server.host, port: page.server.port)
options = { issue: { title: button_title, description: "Job [##{job.id}](#{job_url}) failed for #{job.sha}:\n" } }
@@ -269,13 +269,15 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :proj
let(:resource_group) { create(:ci_resource_group, project: project) }
before do
+ resource_group.assign_resource_to(create(:ci_build))
+
visit project_job_path(project, job)
wait_for_requests
end
it 'shows correct UI components' do
expect(page).to have_content("This job is waiting for resource: #{resource_group.key}")
- expect(page).to have_link("Cancel this job")
+ expect(page).to have_link("View job currently using resource")
end
end
@@ -1065,16 +1067,19 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :proj
end
context "Build from other project" do
+ let(:other_job_download_path) { download_project_job_artifacts_path(project, job2) }
+
before do
create(:ci_job_artifact, :archive, file: artifacts_file, job: job2)
end
- it do
- requests = inspect_requests do
- visit download_project_job_artifacts_path(project, job2)
- end
+ it 'receive 404 from download request', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391632' do
+ requests = inspect_requests { visit other_job_download_path }
+
+ request = requests.find { |request| request.url == other_job_download_path }
- expect(requests.first.status_code).to eq(404)
+ expect(request).to be_present
+ expect(request.status_code).to eq(404)
end
end
end
diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb
index b527b8926a0..4af5dd380c1 100644
--- a/spec/features/projects/labels/update_prioritization_spec.rb
+++ b/spec/features/projects/labels/update_prioritization_spec.rb
@@ -101,7 +101,7 @@ RSpec.describe 'Prioritize labels', feature_category: :team_planning do
expect(page).to have_content 'wontfix'
# Sort labels
- drag_to(selector: '.label-list-item', from_index: 1, to_index: 2)
+ drag_to(selector: '.label-list-item .label-content', from_index: 1, to_index: 2)
page.within('.prioritized-labels') do
expect(first('.label-list-item')).to have_content('feature')
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 6b92581d704..0b8661cce82 100644
--- a/spec/features/projects/members/anonymous_user_sees_members_spec.rb
+++ b/spec/features/projects/members/anonymous_user_sees_members_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Members > Anonymous user sees members' do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
let(:user) { create(:user) }
let(:group) { create(:group, :public) }
diff --git a/spec/features/projects/members/group_members_spec.rb b/spec/features/projects/members/group_members_spec.rb
index 416b96ab668..c0257446a37 100644
--- a/spec/features/projects/members/group_members_spec.rb
+++ b/spec/features/projects/members/group_members_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects members', :js, feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
let(:user) { create(:user) }
let(:developer) { create(:user) }
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 51acba246c5..8238f95fd47 100644
--- a/spec/features/projects/members/groups_with_access_list_spec.rb
+++ b/spec/features/projects/members/groups_with_access_list_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'Projects > Members > Groups with access list', :js, feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
include Spec::Support::Helpers::ModalHelpers
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::InviteMembersModalHelpers
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :public) }
diff --git a/spec/features/projects/members/manage_groups_spec.rb b/spec/features/projects/members/manage_groups_spec.rb
index b78bfacf171..5efb5abefc6 100644
--- a/spec/features/projects/members/manage_groups_spec.rb
+++ b/spec/features/projects/members/manage_groups_spec.rb
@@ -4,8 +4,8 @@ require 'spec_helper'
RSpec.describe 'Project > Members > Manage groups', :js, feature_category: :subgroups do
include ActionView::Helpers::DateHelper
- include Spec::Support::Helpers::Features::MembersHelpers
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::MembersHelpers
+ include Features::InviteMembersModalHelpers
let_it_be(:maintainer) { create(:user) }
diff --git a/spec/features/projects/members/manage_members_spec.rb b/spec/features/projects/members/manage_members_spec.rb
index 615ef1b03dd..5ae6eb83b6b 100644
--- a/spec/features/projects/members/manage_members_spec.rb
+++ b/spec/features/projects/members/manage_members_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'Projects > Members > Manage members', :js, feature_category: :onboarding do
- include Spec::Support::Helpers::Features::MembersHelpers
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::MembersHelpers
+ include Features::InviteMembersModalHelpers
include Spec::Support::Helpers::ModalHelpers
let_it_be(:user1) { create(:user, name: 'John Doe') }
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 31c8237aacc..be778def833 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
@@ -4,8 +4,8 @@ require 'spec_helper'
RSpec.describe 'Projects > Members > Maintainer adds member with expiration date', :js, feature_category: :subgroups do
include ActiveSupport::Testing::TimeHelpers
- include Spec::Support::Helpers::Features::MembersHelpers
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::MembersHelpers
+ include Features::InviteMembersModalHelpers
let_it_be(:maintainer) { create(:user) }
let_it_be(:project) { create(:project, :with_namespace_settings) }
diff --git a/spec/features/projects/members/member_leaves_project_spec.rb b/spec/features/projects/members/member_leaves_project_spec.rb
index 2632bc2f5bd..91e30b3396e 100644
--- a/spec/features/projects/members/member_leaves_project_spec.rb
+++ b/spec/features/projects/members/member_leaves_project_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Members > Member leaves project', feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
include Spec::Support::Helpers::ModalHelpers
let(:user) { create(:user) }
diff --git a/spec/features/projects/members/sorting_spec.rb b/spec/features/projects/members/sorting_spec.rb
index 6df1e974f42..85bf381404c 100644
--- a/spec/features/projects/members/sorting_spec.rb
+++ b/spec/features/projects/members/sorting_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Members > Sorting', :js, feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
let(:maintainer) { create(:user, name: 'John Doe', created_at: 5.days.ago, last_activity_on: Date.today) }
let(:developer) { create(:user, name: 'Mary Jane', created_at: 1.day.ago, last_sign_in_at: 5.days.ago, last_activity_on: Date.today - 5) }
@@ -148,7 +148,7 @@ RSpec.describe 'Projects > Members > Sorting', :js, feature_category: :subgroups
def expect_sort_by(text, sort_direction)
within('[data-testid="members-sort-dropdown"]') do
- expect(page).to have_css('button[aria-haspopup="true"]', text: text)
+ expect(page).to have_css('button[aria-haspopup="menu"]', text: text)
expect(page).to have_button("Sorting Direction: #{sort_direction == :asc ? 'Ascending' : 'Descending'}")
end
end
diff --git a/spec/features/projects/members/tabs_spec.rb b/spec/features/projects/members/tabs_spec.rb
index 232420224fc..9ee06edc0c1 100644
--- a/spec/features/projects/members/tabs_spec.rb
+++ b/spec/features/projects/members/tabs_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Members > Tabs', :js, feature_category: :subgroups do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
using RSpec::Parameterized::TableSyntax
let_it_be(:user) { create(:user) }
diff --git a/spec/features/projects/milestones/milestone_editing_spec.rb b/spec/features/projects/milestones/milestone_editing_spec.rb
new file mode 100644
index 00000000000..8a03683eb35
--- /dev/null
+++ b/spec/features/projects/milestones/milestone_editing_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe "Milestone editing", :js, feature_category: :team_planning do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, name: 'test', namespace: user.namespace) }
+
+ let(:milestone) { create(:milestone, project: project, start_date: Date.today, due_date: 5.days.from_now) }
+
+ before do
+ sign_in(user)
+
+ visit(edit_project_milestone_path(project, milestone))
+ end
+
+ it_behaves_like 'milestone handling version conflicts'
+end
diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb
index 6090d132e3a..532dd7d0a84 100644
--- a/spec/features/projects/navbar_spec.rb
+++ b/spec/features/projects/navbar_spec.rb
@@ -19,9 +19,12 @@ RSpec.describe 'Project navbar', :with_license, feature_category: :projects do
stub_config(registry: { enabled: false })
stub_feature_flags(harbor_registry_integration: false)
+ stub_feature_flags(ml_experiment_tracking: false)
+ stub_feature_flags(remove_monitor_metrics: false)
insert_package_nav(_('Deployments'))
insert_infrastructure_registry_nav
insert_infrastructure_google_cloud_nav
+ insert_infrastructure_aws_nav
end
it_behaves_like 'verified navigation bar' do
@@ -90,7 +93,19 @@ RSpec.describe 'Project navbar', :with_license, feature_category: :projects do
before do
stub_feature_flags(harbor_registry_integration: true)
- insert_harbor_registry_nav(_('Infrastructure Registry'))
+ insert_harbor_registry_nav(_('Terraform modules'))
+
+ visit project_path(project)
+ end
+
+ it_behaves_like 'verified navigation bar'
+ end
+
+ context 'when models experiments is available' do
+ before do
+ stub_feature_flags(ml_experiment_tracking: true)
+
+ insert_model_experiments_nav(_('Terraform modules'))
visit project_path(project)
end
diff --git a/spec/features/projects/network_graph_spec.rb b/spec/features/projects/network_graph_spec.rb
index a29c9f58195..af976b8ffb0 100644
--- a/spec/features/projects/network_graph_spec.rb
+++ b/spec/features/projects/network_graph_spec.rb
@@ -6,10 +6,13 @@ RSpec.describe 'Project Network Graph', :js, feature_category: :projects do
let(:user) { create :user }
let(:project) { create :project, :repository, namespace: user.namespace }
let(:ref_selector) { '.ref-selector' }
+ let(:ref_with_hash) { 'ref-#-hash' }
before do
sign_in(user)
+ project.repository.create_branch(ref_with_hash, 'master')
+
# Stub Graph max_size to speed up test (10 commits vs. 650)
allow(Network::Graph).to receive(:max_count).and_return(10)
end
@@ -52,6 +55,12 @@ RSpec.describe 'Project Network Graph', :js, feature_category: :projects do
end
end
+ it 'switches ref to branch containing a hash' do
+ switch_ref_to(ref_with_hash)
+
+ expect(page).to have_selector ref_selector, text: ref_with_hash
+ end
+
it 'switches ref to tag' do
switch_ref_to('v1.0.0')
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index c6a6ee68185..351662af217 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -3,7 +3,11 @@
require 'spec_helper'
RSpec.describe 'New project', :js, feature_category: :projects do
- include Spec::Support::Helpers::Features::TopNavSpecHelpers
+ include Features::TopNavSpecHelpers
+
+ before do
+ stub_application_setting(import_sources: Gitlab::ImportSources.values)
+ end
context 'as a user' do
let_it_be(:user) { create(:user) }
@@ -67,26 +71,38 @@ RSpec.describe 'New project', :js, feature_category: :projects do
context 'as an admin' do
let(:user) { create(:admin) }
- before do
- sign_in(user)
- end
+ shared_examples '"New project" page' do
+ before do
+ sign_in(user)
+ end
- it 'shows "New project" page', :js do
- visit new_project_path
- click_link 'Create blank project'
+ it 'shows "New project" page', :js do
+ visit new_project_path
+ click_link 'Create blank project'
- expect(page).to have_content('Project name')
- expect(page).to have_content('Project URL')
- expect(page).to have_content('Project slug')
+ expect(page).to have_content('Project name')
+ expect(page).to have_content('Project URL')
+ expect(page).to have_content('Project slug')
- click_link('New project')
- click_link 'Import project'
+ click_link('New project')
+ click_link 'Import project'
+
+ expect(page).to have_link('GitHub')
+ expect(page).to have_link('Bitbucket')
+ expect(page).to have_button('Repository by URL')
+ expect(page).to have_link('GitLab export')
+ end
+ end
+
+ include_examples '"New project" page'
- expect(page).to have_link('GitHub')
- expect(page).to have_link('Bitbucket')
- expect(page).to have_link('GitLab.com')
- expect(page).to have_button('Repository by URL')
- expect(page).to have_link('GitLab export')
+ context 'when the new navigation is enabled' do
+ before do
+ user.update!(use_new_navigation: true)
+ stub_feature_flags(super_sidebar_nav: true)
+ end
+
+ include_examples '"New project" page'
end
shared_examples 'renders importer link' do |params|
@@ -123,11 +139,9 @@ RSpec.describe 'New project', :js, feature_category: :projects do
'github': :new_import_github_path,
'bitbucket': :status_import_bitbucket_path,
'bitbucket server': :status_import_bitbucket_server_path,
- 'gitlab.com': :status_import_gitlab_path,
'fogbugz': :new_import_fogbugz_path,
'gitea': :new_import_gitea_path,
- 'manifest': :new_import_manifest_path,
- 'phabricator': :new_import_phabricator_path
+ 'manifest': :new_import_manifest_path
}
end
@@ -560,22 +574,52 @@ RSpec.describe 'New project', :js, feature_category: :projects do
end
end
- context 'from GitLab.com', :js do
- let(:target_link) { 'GitLab.com' }
- let(:provider) { :gitlab }
+ describe 'sidebar' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:parent_group) { create(:group) }
- context 'as a user' do
- let(:user) { create(:user) }
- let(:oauth_config_instructions) { 'To enable importing projects from GitLab.com, ask your GitLab administrator to configure OAuth integration' }
+ before do
+ parent_group.add_owner(user)
+ sign_in(user)
+ end
- it_behaves_like 'has instructions to enable OAuth'
+ context 'in the current navigation' do
+ before do
+ user.update!(use_new_navigation: false)
+ end
+
+ context 'for a new top-level project' do
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :new_project_path, :projects
+ end
+
+ context 'for a new group project' do
+ it 'shows the group sidebar of the parent group' do
+ visit new_project_path(namespace_id: parent_group.id)
+ expect(page).to have_selector(".nav-sidebar[aria-label=\"Group navigation\"] .context-header[title=\"#{parent_group.name}\"]")
+ end
+ end
end
- context 'as an admin', :do_not_mock_admin_mode_setting do
- let(:user) { create(:admin) }
- let(:oauth_config_instructions) { 'To enable importing projects from GitLab.com, as administrator you need to configure OAuth integration' }
+ context 'in the new navigation' do
+ before do
+ parent_group.add_owner(user)
+ user.update!(use_new_navigation: true)
+ sign_in(user)
+ end
- it_behaves_like 'has instructions to enable OAuth'
+ context 'for a new top-level project' do
+ it 'shows the "Your work" navigation' do
+ visit new_project_path
+ expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: "Your work")
+ end
+ end
+
+ context 'for a new group project' do
+ it 'shows the group sidebar of the parent group' do
+ visit new_project_path(namespace_id: parent_group.id)
+ expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: parent_group.name)
+ end
+ end
end
end
end
diff --git a/spec/features/projects/packages_spec.rb b/spec/features/projects/packages_spec.rb
index 31ff455d0df..5d3ebd8bec6 100644
--- a/spec/features/projects/packages_spec.rb
+++ b/spec/features/projects/packages_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe 'Packages', feature_category: :projects do
end
context 'when there are packages' do
- let_it_be(:npm_package) { create(:npm_package, project: project, name: 'zzz', created_at: 1.day.ago, version: '1.0.0') }
+ let_it_be(:npm_package) { create(:npm_package, :with_build, project: project, name: 'zzz', created_at: 1.day.ago, version: '1.0.0') }
let_it_be(:maven_package) { create(:maven_package, project: project, name: 'aaa', created_at: 2.days.ago, version: '2.0.0') }
let_it_be(:packages) { [npm_package, maven_package] }
@@ -40,6 +40,8 @@ RSpec.describe 'Packages', feature_category: :projects do
it_behaves_like 'packages list'
+ it_behaves_like 'pipelines on packages list'
+
it_behaves_like 'package details link'
context 'deleting a package' do
diff --git a/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb b/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb
index a7da59200e9..16e64ade665 100644
--- a/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb
+++ b/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb
@@ -48,13 +48,13 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled, feature_categor
expect(domain.auto_ssl_enabled).to eq false
expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false'
- expect(page).to have_selector '.card-header', text: 'Certificate'
+ expect(page).to have_selector '.gl-card-header', text: 'Certificate'
expect(page).to have_text domain.subject
find('.js-auto-ssl-toggle-container .js-project-feature-toggle button').click
expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true'
- expect(page).not_to have_selector '.card-header', text: 'Certificate'
+ expect(page).not_to have_selector '.gl-card-header', text: 'Certificate'
expect(page).not_to have_text domain.subject
click_on 'Save Changes'
@@ -108,7 +108,7 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled, feature_categor
it 'user do not see private key' do
visit project_pages_domain_path(project, domain)
- expect(page).not_to have_selector '.card-header', text: 'Certificate'
+ expect(page).not_to have_selector '.gl-card-header', text: 'Certificate'
expect(page).not_to have_text domain.subject
end
end
@@ -131,16 +131,16 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled, feature_categor
it 'user sees certificate subject' do
visit project_pages_domain_path(project, domain)
- expect(page).to have_selector '.card-header', text: 'Certificate'
+ expect(page).to have_selector '.gl-card-header', text: 'Certificate'
expect(page).to have_text domain.subject
end
it 'user can delete the certificate', :js do
visit project_pages_domain_path(project, domain)
- expect(page).to have_selector '.card-header', text: 'Certificate'
+ expect(page).to have_selector '.gl-card-header', text: 'Certificate'
expect(page).to have_text domain.subject
- within('.card') { click_on 'Remove' }
+ within('.gl-card') { click_on 'Remove' }
accept_gl_confirm(button_text: 'Remove certificate')
expect(page).to have_field 'Certificate (PEM)', with: ''
expect(page).to have_field 'Key (PEM)', with: ''
diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb
index 3ede76d3360..81e003d7d1c 100644
--- a/spec/features/projects/pipeline_schedules_spec.rb
+++ b/spec/features/projects/pipeline_schedules_spec.rb
@@ -7,295 +7,394 @@ RSpec.describe 'Pipeline Schedules', :js, feature_category: :projects do
let!(:project) { create(:project, :repository) }
let!(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project) }
- let!(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule) }
+ let!(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule, project: project) }
let(:scope) { nil }
let!(:user) { create(:user) }
+ let!(:maintainer) { create(:user) }
- before do
- stub_feature_flags(pipeline_schedules_vue: false)
- end
-
- context 'logged in as the pipeline schedule owner' do
+ context 'with pipeline_schedules_vue feature flag turned off' do
before do
- project.add_developer(user)
- pipeline_schedule.update!(owner: user)
- gitlab_sign_in(user)
+ stub_feature_flags(pipeline_schedules_vue: false)
end
- describe 'GET /projects/pipeline_schedules' do
+ context 'logged in as the pipeline schedule owner' do
before do
- visit_pipelines_schedules
+ project.add_developer(user)
+ pipeline_schedule.update!(owner: user)
+ gitlab_sign_in(user)
end
- it 'edits the pipeline' do
- page.within('.pipeline-schedule-table-row') do
- click_link 'Edit'
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
end
- expect(page).to have_content('Edit Pipeline Schedule')
- end
- end
+ it 'edits the pipeline' do
+ page.within('.pipeline-schedule-table-row') do
+ click_link 'Edit'
+ end
- describe 'PATCH /projects/pipelines_schedules/:id/edit' do
- before do
- edit_pipeline_schedule
+ expect(page).to have_content('Edit Pipeline Schedule')
+ end
end
- it 'displays existing properties' do
- description = find_field('schedule_description').value
- expect(description).to eq('pipeline schedule')
- expect(page).to have_button('master')
- expect(page).to have_button('Select timezone')
- end
+ describe 'PATCH /projects/pipelines_schedules/:id/edit' do
+ before do
+ edit_pipeline_schedule
+ end
- it 'edits the scheduled pipeline' do
- fill_in 'schedule_description', with: 'my brand new description'
+ it 'displays existing properties' do
+ description = find_field('schedule_description').value
+ expect(description).to eq('pipeline schedule')
+ expect(page).to have_button('master')
+ expect(page).to have_button('Select timezone')
+ end
- save_pipeline_schedule
+ it 'edits the scheduled pipeline' do
+ fill_in 'schedule_description', with: 'my brand new description'
- expect(page).to have_content('my brand new description')
- end
+ save_pipeline_schedule
- context 'when ref is nil' do
- before do
- pipeline_schedule.update_attribute(:ref, nil)
- edit_pipeline_schedule
+ expect(page).to have_content('my brand new description')
end
- it 'shows the pipeline schedule with default ref' do
- page.within('[data-testid="schedule-target-ref"]') do
- expect(first('.gl-button-text').text).to eq('master')
+ context 'when ref is nil' do
+ before do
+ pipeline_schedule.update_attribute(:ref, nil)
+ edit_pipeline_schedule
end
- end
- end
- context 'when ref is empty' do
- before do
- pipeline_schedule.update_attribute(:ref, '')
- edit_pipeline_schedule
+ it 'shows the pipeline schedule with default ref' do
+ page.within('[data-testid="schedule-target-ref"]') do
+ expect(first('.gl-button-text').text).to eq('master')
+ end
+ end
end
- it 'shows the pipeline schedule with default ref' do
- page.within('[data-testid="schedule-target-ref"]') do
- expect(first('.gl-button-text').text).to eq('master')
+ context 'when ref is empty' do
+ before do
+ pipeline_schedule.update_attribute(:ref, '')
+ edit_pipeline_schedule
+ end
+
+ it 'shows the pipeline schedule with default ref' do
+ page.within('[data-testid="schedule-target-ref"]') do
+ expect(first('.gl-button-text').text).to eq('master')
+ end
end
end
end
end
- end
- context 'logged in as a project maintainer' do
- before do
- project.add_maintainer(user)
- gitlab_sign_in(user)
- end
-
- describe 'GET /projects/pipeline_schedules' do
+ context 'logged in as a project maintainer' do
before do
- visit_pipelines_schedules
+ project.add_maintainer(user)
+ gitlab_sign_in(user)
end
- describe 'The view' do
- it 'displays the required information description' do
- page.within('.pipeline-schedule-table-row') do
- expect(page).to have_content('pipeline schedule')
- expect(find("[data-testid='next-run-cell'] time")['title'])
- .to include(pipeline_schedule.real_next_run.strftime('%b %-d, %Y'))
- expect(page).to have_link('master')
- expect(page).to have_link("##{pipeline.id}")
- end
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
end
- it 'creates a new scheduled pipeline' do
- click_link 'New schedule'
+ describe 'The view' do
+ it 'displays the required information description' do
+ page.within('.pipeline-schedule-table-row') do
+ expect(page).to have_content('pipeline schedule')
+ expect(find("[data-testid='next-run-cell'] time")['title'])
+ .to include(pipeline_schedule.real_next_run.strftime('%b %-d, %Y'))
+ expect(page).to have_link('master')
+ expect(page).to have_link("##{pipeline.id}")
+ end
+ end
- expect(page).to have_content('Schedule a new pipeline')
- end
+ it 'creates a new scheduled pipeline' do
+ click_link 'New schedule'
+
+ expect(page).to have_content('Schedule a new pipeline')
+ end
- it 'changes ownership of the pipeline' do
- click_button 'Take ownership'
+ it 'changes ownership of the pipeline' do
+ click_button 'Take ownership'
- page.within('#pipeline-take-ownership-modal') do
- click_link 'Take ownership'
+ page.within('#pipeline-take-ownership-modal') do
+ click_link 'Take ownership'
+ end
+
+ page.within('.pipeline-schedule-table-row') do
+ expect(page).not_to have_content('No owner')
+ expect(page).to have_link('Sidney Jones')
+ end
end
- page.within('.pipeline-schedule-table-row') do
- expect(page).not_to have_content('No owner')
- expect(page).to have_link('Sidney Jones')
+ it 'deletes the pipeline' do
+ click_link 'Delete'
+
+ accept_gl_confirm(button_text: 'Delete pipeline schedule')
+
+ expect(page).not_to have_css(".pipeline-schedule-table-row")
end
end
- it 'deletes the pipeline' do
- click_link 'Delete'
+ context 'when ref is nil' do
+ before do
+ pipeline_schedule.update_attribute(:ref, nil)
+ visit_pipelines_schedules
+ end
+
+ it 'shows a list of the pipeline schedules with empty ref column' do
+ expect(first('.branch-name-cell').text).to eq('')
+ end
+ end
- accept_gl_confirm(button_text: 'Delete pipeline schedule')
+ context 'when ref is empty' do
+ before do
+ pipeline_schedule.update_attribute(:ref, '')
+ visit_pipelines_schedules
+ end
- expect(page).not_to have_css(".pipeline-schedule-table-row")
+ it 'shows a list of the pipeline schedules with empty ref column' do
+ expect(first('.branch-name-cell').text).to eq('')
+ end
end
end
- context 'when ref is nil' do
+ describe 'POST /projects/pipeline_schedules/new' do
before do
- pipeline_schedule.update_attribute(:ref, nil)
- visit_pipelines_schedules
+ visit_new_pipeline_schedule
+ end
+
+ it 'sets defaults for timezone and target branch' do
+ expect(page).to have_button('master')
+ expect(page).to have_button('Select timezone')
end
- it 'shows a list of the pipeline schedules with empty ref column' do
- expect(first('.branch-name-cell').text).to eq('')
+ it 'creates a new scheduled pipeline' do
+ fill_in_schedule_form
+ save_pipeline_schedule
+
+ expect(page).to have_content('my fancy description')
+ end
+
+ it 'prevents an invalid form from being submitted' do
+ save_pipeline_schedule
+
+ expect(page).to have_content('This field is required')
end
end
- context 'when ref is empty' do
+ context 'when user creates a new pipeline schedule with variables' do
before do
- pipeline_schedule.update_attribute(:ref, '')
visit_pipelines_schedules
+ click_link 'New schedule'
+ fill_in_schedule_form
+ all('[name="schedule[variables_attributes][][key]"]')[0].set('AAA')
+ all('[name="schedule[variables_attributes][][secret_value]"]')[0].set('AAA123')
+ all('[name="schedule[variables_attributes][][key]"]')[1].set('BBB')
+ all('[name="schedule[variables_attributes][][secret_value]"]')[1].set('BBB123')
+ save_pipeline_schedule
end
- it 'shows a list of the pipeline schedules with empty ref column' do
- expect(first('.branch-name-cell').text).to eq('')
+ it 'user sees the new variable in edit window', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/397040' do
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ page.within('.ci-variable-list') do
+ expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-key").value).to eq('AAA')
+ expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-value", visible: false).value).to eq('AAA123')
+ expect(find(".ci-variable-row:nth-child(2) .js-ci-variable-input-key").value).to eq('BBB')
+ expect(find(".ci-variable-row:nth-child(2) .js-ci-variable-input-value", visible: false).value).to eq('BBB123')
+ end
end
end
- end
- describe 'POST /projects/pipeline_schedules/new' do
- before do
- visit_new_pipeline_schedule
- end
+ context 'when user edits a variable of a pipeline schedule' do
+ before do
+ create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
+ create(:ci_pipeline_schedule_variable, key: 'AAA', value: 'AAA123', pipeline_schedule: pipeline_schedule)
+ end
- it 'sets defaults for timezone and target branch' do
- expect(page).to have_button('master')
- expect(page).to have_button('Select timezone')
+ visit_pipelines_schedules
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ find('.js-ci-variable-list-section .js-secret-value-reveal-button').click
+ first('.js-ci-variable-input-key').set('foo')
+ first('.js-ci-variable-input-value').set('bar')
+ click_button 'Save pipeline schedule'
+ end
+
+ it 'user sees the updated variable in edit window' do
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ page.within('.ci-variable-list') do
+ expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-key").value).to eq('foo')
+ expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-value", visible: false).value).to eq('bar')
+ end
+ end
end
- it 'creates a new scheduled pipeline' do
- fill_in_schedule_form
- save_pipeline_schedule
+ context 'when user removes a variable of a pipeline schedule' do
+ before do
+ create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
+ create(:ci_pipeline_schedule_variable, key: 'AAA', value: 'AAA123', pipeline_schedule: pipeline_schedule)
+ end
- expect(page).to have_content('my fancy description')
+ visit_pipelines_schedules
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ find('.ci-variable-list .ci-variable-row-remove-button').click
+ click_button 'Save pipeline schedule'
+ end
+
+ it 'user does not see the removed variable in edit window' do
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ page.within('.ci-variable-list') do
+ expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-key").value).to eq('')
+ expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-value", visible: false).value).to eq('')
+ end
+ end
end
- it 'prevents an invalid form from being submitted' do
- save_pipeline_schedule
+ context 'when active is true and next_run_at is NULL' do
+ before do
+ create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
+ pipeline_schedule.update_attribute(:next_run_at, nil) # Consequently next_run_at will be nil
+ end
+ end
+
+ it 'user edit and recover the problematic pipeline schedule' do
+ visit_pipelines_schedules
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ fill_in 'schedule_cron', with: '* 1 2 3 4'
+ click_button 'Save pipeline schedule'
- expect(page).to have_content('This field is required')
+ page.within('.pipeline-schedule-table-row:nth-child(1)') do
+ expect(page).to have_css("[data-testid='next-run-cell'] time")
+ end
+ end
end
end
- context 'when user creates a new pipeline schedule with variables' do
+ context 'logged in as non-member' do
before do
- visit_pipelines_schedules
- click_link 'New schedule'
- fill_in_schedule_form
- all('[name="schedule[variables_attributes][][key]"]')[0].set('AAA')
- all('[name="schedule[variables_attributes][][secret_value]"]')[0].set('AAA123')
- all('[name="schedule[variables_attributes][][key]"]')[1].set('BBB')
- all('[name="schedule[variables_attributes][][secret_value]"]')[1].set('BBB123')
- save_pipeline_schedule
+ gitlab_sign_in(user)
end
- it 'user sees the new variable in edit window' do
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- page.within('.ci-variable-list') do
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-key").value).to eq('AAA')
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-value", visible: false).value).to eq('AAA123')
- expect(find(".ci-variable-row:nth-child(2) .js-ci-variable-input-key").value).to eq('BBB')
- expect(find(".ci-variable-row:nth-child(2) .js-ci-variable-input-value", visible: false).value).to eq('BBB123')
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
+ end
+
+ describe 'The view' do
+ it 'does not show create schedule button' do
+ expect(page).not_to have_link('New schedule')
+ end
end
end
end
- context 'when user edits a variable of a pipeline schedule' do
- before do
- create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
- create(:ci_pipeline_schedule_variable, key: 'AAA', value: 'AAA123', pipeline_schedule: pipeline_schedule)
+ context 'not logged in' do
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
end
- visit_pipelines_schedules
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
-
- find('.js-ci-variable-list-section .js-secret-value-reveal-button').click
- first('.js-ci-variable-input-key').set('foo')
- first('.js-ci-variable-input-value').set('bar')
- click_button 'Save pipeline schedule'
- end
-
- it 'user sees the updated variable in edit window' do
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- page.within('.ci-variable-list') do
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-key").value).to eq('foo')
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-value", visible: false).value).to eq('bar')
+ describe 'The view' do
+ it 'does not show create schedule button' do
+ expect(page).not_to have_link('New schedule')
+ end
end
end
end
+ end
- context 'when user removes a variable of a pipeline schedule' do
+ context 'with pipeline_schedules_vue feature flag turned on' do
+ context 'logged in as a project maintainer' do
before do
- create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
- create(:ci_pipeline_schedule_variable, key: 'AAA', value: 'AAA123', pipeline_schedule: pipeline_schedule)
- end
-
- visit_pipelines_schedules
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- find('.ci-variable-list .ci-variable-row-remove-button').click
- click_button 'Save pipeline schedule'
+ project.add_maintainer(maintainer)
+ pipeline_schedule.update!(owner: user)
+ gitlab_sign_in(maintainer)
end
- it 'user does not see the removed variable in edit window' do
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- page.within('.ci-variable-list') do
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-key").value).to eq('')
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-value", visible: false).value).to eq('')
- end
- end
- end
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
- context 'when active is true and next_run_at is NULL' do
- before do
- create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
- pipeline_schedule.update_attribute(:next_run_at, nil) # Consequently next_run_at will be nil
+ wait_for_requests
end
- end
- it 'user edit and recover the problematic pipeline schedule' do
- visit_pipelines_schedules
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- fill_in 'schedule_cron', with: '* 1 2 3 4'
- click_button 'Save pipeline schedule'
+ describe 'The view' do
+ it 'displays the required information description' do
+ page.within('[data-testid="pipeline-schedule-table-row"]') do
+ expect(page).to have_content('pipeline schedule')
+ expect(find("[data-testid='next-run-cell'] time")['title'])
+ .to include(pipeline_schedule.real_next_run.strftime('%b %-d, %Y'))
+ expect(page).to have_link('master')
+ expect(find("[data-testid='last-pipeline-status'] a")['href']).to include(pipeline.id.to_s)
+ end
+ end
+
+ it 'changes ownership of the pipeline' do
+ click_button 'Take ownership'
+
+ page.within('#pipeline-take-ownership-modal') do
+ click_button 'Take ownership'
+
+ wait_for_requests
+ end
+
+ page.within('[data-testid="pipeline-schedule-table-row"]') do
+ expect(page).not_to have_content('No owner')
+ expect(page).to have_link('Sidney Jones')
+ end
+ end
- page.within('.pipeline-schedule-table-row:nth-child(1)') do
- expect(page).to have_css("[data-testid='next-run-cell'] time")
+ it 'runs the pipeline' do
+ click_button 'Run pipeline schedule'
+
+ wait_for_requests
+
+ expect(page).to have_content("Successfully scheduled a pipeline to run. Go to the Pipelines page for details.")
+ end
+
+ it 'deletes the pipeline' do
+ click_button 'Delete pipeline schedule'
+
+ accept_gl_confirm(button_text: 'Delete pipeline schedule')
+
+ expect(page).not_to have_css('[data-testid="pipeline-schedule-table-row"]')
+ end
end
end
end
- end
-
- context 'logged in as non-member' do
- before do
- gitlab_sign_in(user)
- end
- describe 'GET /projects/pipeline_schedules' do
+ context 'logged in as non-member' do
before do
- visit_pipelines_schedules
+ gitlab_sign_in(user)
end
- describe 'The view' do
- it 'does not show create schedule button' do
- expect(page).not_to have_link('New schedule')
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
+
+ wait_for_requests
+ end
+
+ describe 'The view' do
+ it 'does not show create schedule button' do
+ expect(page).not_to have_link('New schedule')
+ end
end
end
end
- end
- context 'not logged in' do
- describe 'GET /projects/pipeline_schedules' do
- before do
- visit_pipelines_schedules
- end
+ context 'not logged in' do
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
+
+ wait_for_requests
+ end
- describe 'The view' do
- it 'does not show create schedule button' do
- expect(page).not_to have_link('New schedule')
+ describe 'The view' do
+ it 'does not show create schedule button' do
+ expect(page).not_to have_link('New schedule')
+ end
end
end
end
@@ -332,5 +431,6 @@ RSpec.describe 'Pipeline Schedules', :js, feature_category: :projects do
select_timezone
select_target_branch
+ find('body').click # close dropdown
end
end
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 343c7f53022..7167581eedf 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -80,7 +80,7 @@ RSpec.describe 'Pipeline', :js, feature_category: :projects do
expect(page).to have_content('test')
expect(page).to have_content('deploy')
expect(page).to have_content('Retry')
- expect(page).to have_content('Cancel running')
+ expect(page).to have_content('Cancel pipeline')
end
it 'shows link to the pipeline ref' do
@@ -113,6 +113,39 @@ RSpec.describe 'Pipeline', :js, feature_category: :projects do
end
end
+ describe 'pipeline stats text' do
+ let(:finished_pipeline) do
+ create(:ci_pipeline, :success, project: project,
+ ref: 'master', sha: project.commit.id, user: user)
+ end
+
+ before do
+ finished_pipeline.update!(started_at: "2023-01-01 01:01:05", created_at: "2023-01-01 01:01:01",
+ finished_at: "2023-01-01 01:01:10", duration: 9)
+ end
+
+ context 'pipeline has finished' do
+ it 'shows pipeline stats with flag on' do
+ visit project_pipeline_path(project, finished_pipeline)
+
+ within '.pipeline-info' do
+ expect(page).to have_content("in #{finished_pipeline.duration} seconds")
+ expect(page).to have_content("and was queued for #{finished_pipeline.queued_duration} seconds")
+ end
+ end
+ end
+
+ context 'pipeline has not finished' do
+ it 'does not show pipeline stats' do
+ visit_pipeline
+
+ within '.pipeline-info' do
+ expect(page).not_to have_selector('[data-testid="pipeline-stats-text"]')
+ end
+ end
+ end
+ end
+
describe 'related merge requests' do
context 'when there are no related merge requests' do
it 'shows a "no related merge requests" message' do
@@ -592,11 +625,11 @@ RSpec.describe 'Pipeline', :js, feature_category: :projects do
context 'when canceling' do
before do
- click_on 'Cancel running'
+ click_on 'Cancel pipeline'
end
- it 'does not show a "Cancel running" button', :sidekiq_might_not_need_inline do
- expect(page).not_to have_content('Cancel running')
+ it 'does not show a "Cancel pipeline" button', :sidekiq_might_not_need_inline do
+ expect(page).not_to have_content('Cancel pipeline')
end
end
end
@@ -814,10 +847,10 @@ RSpec.describe 'Pipeline', :js, feature_category: :projects do
expect(page).to have_content('test')
expect(page).to have_content('deploy')
expect(page).to have_content('Retry')
- expect(page).to have_content('Cancel running')
+ expect(page).to have_content('Cancel pipeline')
end
- it 'does not link to job' do
+ it 'does not link to job', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408215' do
expect(page).not_to have_selector('.js-pipeline-graph-job-link')
end
end
@@ -880,7 +913,7 @@ RSpec.describe 'Pipeline', :js, feature_category: :projects do
expect(page).to have_selector('table.ci-table > tbody > tr > td', text: 'blocked user schedule')
end
- it 'does not create a new Pipeline' do
+ it 'does not create a new Pipeline', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408215' do
visit project_pipelines_path(project)
expect(page).not_to have_selector('.ci-table')
@@ -1060,7 +1093,7 @@ RSpec.describe 'Pipeline', :js, feature_category: :projects do
expect(page).to have_content(build_running.id)
expect(page).to have_content(build_external.id)
expect(page).to have_content('Retry')
- expect(page).to have_content('Cancel running')
+ expect(page).to have_content('Cancel pipeline')
expect(page).to have_button('Play')
end
@@ -1095,11 +1128,11 @@ RSpec.describe 'Pipeline', :js, feature_category: :projects do
context 'when canceling' do
before do
- click_on 'Cancel running'
+ click_on 'Cancel pipeline'
end
- it 'does not show a "Cancel running" button', :sidekiq_might_not_need_inline do
- expect(page).not_to have_content('Cancel running')
+ it 'does not show a "Cancel pipeline" button', :sidekiq_might_not_need_inline do
+ expect(page).not_to have_content('Cancel pipeline')
end
end
end
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index b5f640f1cca..d3ccde3d2e1 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -288,16 +288,21 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
it 'has link to the manual action' do
find('[data-testid="pipelines-manual-actions-dropdown"]').click
+ wait_for_requests
+
expect(page).to have_button('manual build')
end
context 'when manual action was played' do
before do
find('[data-testid="pipelines-manual-actions-dropdown"]').click
+
+ wait_for_requests
+
click_button('manual build')
end
- it 'enqueues manual action job' do
+ it 'enqueues manual action job', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/409984' do
expect(page).to have_selector('[data-testid="pipelines-manual-actions-dropdown"] .gl-dropdown-toggle:disabled')
end
end
@@ -308,7 +313,8 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
create(:ci_build, :scheduled,
pipeline: pipeline,
name: 'delayed job 1',
- stage: 'test')
+ stage: 'test',
+ scheduled_at: 2.hours.since + 2.minutes)
end
before do
@@ -322,9 +328,12 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
it "has link to the delayed job's action" do
find('[data-testid="pipelines-manual-actions-dropdown"]').click
- time_diff = [0, delayed_job.scheduled_at - Time.zone.now].max
+ wait_for_requests
+
expect(page).to have_button('delayed job 1')
- expect(page).to have_content(Time.at(time_diff).utc.strftime("%H:%M:%S"))
+
+ time_diff = [0, delayed_job.scheduled_at - Time.zone.now].max
+ expect(page).to have_content(Time.at(time_diff).utc.strftime("%H:%M"))
end
context 'when delayed job is expired already' do
@@ -338,6 +347,8 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
it "shows 00:00:00 as the remaining time" do
find('[data-testid="pipelines-manual-actions-dropdown"]').click
+ wait_for_requests
+
expect(page).to have_content("00:00:00")
end
end
@@ -358,7 +369,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
wait_for_requests
end
- it 'enqueues the delayed job', :js do
+ it 'enqueues the delayed job', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410129' do
expect(delayed_job.reload).to be_pending
end
end
@@ -675,7 +686,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
click_button project.default_branch
wait_for_requests
- find('.gl-new-dropdown-item', text: 'master').click
+ find('.gl-new-dropdown-item', text: '2-mb-file').click
wait_for_requests
end
@@ -686,7 +697,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
it 'creates a new pipeline' do
expect do
- click_on 'Run pipeline'
+ find('[data-testid="run_pipeline_button"]', text: 'Run pipeline').click
wait_for_requests
end
.to change { Ci::Pipeline.count }.by(1)
@@ -695,14 +706,14 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
end
context 'when variables are specified' do
- it 'creates a new pipeline with variables', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/375552' do
+ it 'creates a new pipeline with variables' do
page.within(find("[data-testid='ci-variable-row']")) do
find("[data-testid='pipeline-form-ci-variable-key']").set('key_name')
find("[data-testid='pipeline-form-ci-variable-value']").set('value')
end
expect do
- click_on 'Run pipeline'
+ find('[data-testid="run_pipeline_button"]', text: 'Run pipeline').click
wait_for_requests
end
.to change { Ci::Pipeline.count }.by(1)
@@ -715,17 +726,17 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
context 'without gitlab-ci.yml' do
before do
- click_on 'Run pipeline'
+ find('[data-testid="run_pipeline_button"]', text: 'Run pipeline').click
wait_for_requests
end
it { expect(page).to have_content('Missing CI config file') }
- it 'creates a pipeline after first request failed and a valid gitlab-ci.yml file is available when trying again', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/375552' do
+ it 'creates a pipeline after first request failed and a valid gitlab-ci.yml file is available when trying again' do
stub_ci_pipeline_to_return_yaml_file
expect do
- click_on 'Run pipeline'
+ find('[data-testid="run_pipeline_button"]', text: 'Run pipeline').click
wait_for_requests
end
.to change { Ci::Pipeline.count }.by(1)
@@ -787,9 +798,9 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
describe 'find pipelines' do
it 'shows filtered pipelines', :js do
click_button project.default_branch
- send_keys('fix')
+ send_keys('2-mb-file')
- expect_listbox_item('fix')
+ expect_listbox_item('2-mb-file')
end
end
end
diff --git a/spec/features/projects/releases/user_creates_release_spec.rb b/spec/features/projects/releases/user_creates_release_spec.rb
index f678d77b002..678c8df666f 100644
--- a/spec/features/projects/releases/user_creates_release_spec.rb
+++ b/spec/features/projects/releases/user_creates_release_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User creates release', :js, feature_category: :continuous_delivery do
- include Spec::Support::Helpers::Features::ReleasesHelpers
+ include Features::ReleasesHelpers
let_it_be(:project) { create(:project, :repository) }
let_it_be(:milestone_1) { create(:milestone, project: project, title: '1.1') }
@@ -25,17 +25,19 @@ RSpec.describe 'User creates release', :js, feature_category: :continuous_delive
it 'renders the breadcrumbs', :aggregate_failures do
within('.breadcrumbs') do
- expect(page).to have_content("#{project.creator.name} #{project.name} New Release")
+ expect(page).to have_content("#{project.creator.name} #{project.name} Releases New")
expect(page).to have_link(project.creator.name, href: user_path(project.creator))
expect(page).to have_link(project.name, href: project_path(project))
- expect(page).to have_link('New Release', href: new_project_release_path(project))
+ expect(page).to have_link('Releases', href: project_releases_path(project))
+ expect(page).to have_link('New', href: new_project_release_path(project))
end
end
it 'defaults the "Create from" dropdown to the project\'s default branch' do
select_new_tag_name(tag_name)
+ expect(page).to have_button(project.default_branch)
expect(page.find('[data-testid="create-from-field"] .ref-selector button')).to have_content(project.default_branch)
end
@@ -107,7 +109,7 @@ RSpec.describe 'User creates release', :js, feature_category: :continuous_delive
fill_release_notes('**some** _markdown_ [content](https://example.com)')
- click_on 'Preview'
+ click_button("Preview")
wait_for_all_requests
end
@@ -123,13 +125,12 @@ RSpec.describe 'User creates release', :js, feature_category: :continuous_delive
let(:new_page_url) { new_project_release_path(project, tag_name: 'v1.1.0') }
it 'creates release with preselected tag' do
- page.within '[data-testid="tag-name-field"]' do
- expect(page).to have_text('v1.1.0')
- end
+ expect(page).to have_button 'v1.1.0'
+
+ open_tag_popover 'v1.1.0'
expect(page).not_to have_selector('[data-testid="create-from-field"]')
- fill_release_title("test release")
click_button('Create release')
wait_for_all_requests
diff --git a/spec/features/projects/settings/access_tokens_spec.rb b/spec/features/projects/settings/access_tokens_spec.rb
index 12e14f5193f..a38c10c6bab 100644
--- a/spec/features/projects/settings/access_tokens_spec.rb
+++ b/spec/features/projects/settings/access_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project > Settings > Access Tokens', :js, feature_category: :credential_management do
+RSpec.describe 'Project > Settings > Access Tokens', :js, feature_category: :user_management do
include Spec::Support::Helpers::ModalHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/features/projects/settings/branch_rules_settings_spec.rb b/spec/features/projects/settings/branch_rules_settings_spec.rb
index 71d9c559b77..59609fecd93 100644
--- a/spec/features/projects/settings/branch_rules_settings_spec.rb
+++ b/spec/features/projects/settings/branch_rules_settings_spec.rb
@@ -28,6 +28,17 @@ RSpec.describe 'Projects > Settings > Repository > Branch rules settings', featu
let(:role) { :maintainer }
context 'Branch rules', :js do
+ it 'renders breadcrumbs' do
+ request
+
+ page.within '.breadcrumbs' do
+ expect(page).to have_link('Repository Settings', href: project_settings_repository_path(project))
+ expect(page).to have_link('Branch rules',
+ href: project_settings_repository_path(project, anchor: 'branch-rules'))
+ expect(page).to have_link('Details', href: '#')
+ end
+ end
+
it 'renders branch rules page' do
request
diff --git a/spec/features/projects/settings/forked_project_settings_spec.rb b/spec/features/projects/settings/forked_project_settings_spec.rb
index 28d5c080db9..6b646bcf7d3 100644
--- a/spec/features/projects/settings/forked_project_settings_spec.rb
+++ b/spec/features/projects/settings/forked_project_settings_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe 'Projects > Settings > For a forked project', :js, feature_catego
wait_for_requests
- fill_in('confirm_name_input', with: forked_project.name)
+ fill_in('confirm_name_input', with: forked_project.path)
click_button('Confirm')
wait_for_requests
diff --git a/spec/features/projects/settings/monitor_settings_spec.rb b/spec/features/projects/settings/monitor_settings_spec.rb
index 4b553b57331..1367ffb0009 100644
--- a/spec/features/projects/settings/monitor_settings_spec.rb
+++ b/spec/features/projects/settings/monitor_settings_spec.rb
@@ -3,12 +3,15 @@
require 'spec_helper'
RSpec.describe 'Projects > Settings > For a forked project', :js, feature_category: :projects do
+ include ListboxHelpers
+
let_it_be(:project) { create(:project, :repository, create_templates: :issue) }
let(:user) { project.first_owner }
before do
sign_in(user)
+ stub_feature_flags(remove_monitor_metrics: false)
end
describe 'Sidebar > Monitor' do
@@ -47,7 +50,7 @@ RSpec.describe 'Projects > Settings > For a forked project', :js, feature_catego
check(create_issue)
uncheck(send_email)
click_on('No template selected')
- click_on('bug')
+ select_listbox_item('bug')
save_form
click_settings_tab
diff --git a/spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb b/spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb
index d4c1fe4d43e..bdfe6a06dd1 100644
--- a/spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb
+++ b/spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb
@@ -32,10 +32,19 @@ feature_category: :projects do
it 'shows available section' do
subject
- expect(find('.breadcrumbs')).to have_content('Clean up image tags')
+ expect(find('.breadcrumbs')).to have_content('Cleanup policies')
section = find('[data-testid="container-expiration-policy-project-settings"]')
- expect(section).to have_text 'Clean up image tags'
+ expect(section).to have_text 'Cleanup policies'
+ end
+
+ it 'passes axe automated accessibility testing' do
+ subject
+
+ wait_for_requests
+
+ expect(page).to be_axe_clean.within('[data-testid="container-expiration-policy-project-settings"]')
+ .skipping :'link-in-text-block'
end
it 'saves cleanup policy submit the form' do
diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb
index 072b5f7f3b0..68e9b0225ea 100644
--- a/spec/features/projects/settings/registry_settings_spec.rb
+++ b/spec/features/projects/settings/registry_settings_spec.rb
@@ -21,6 +21,15 @@ feature_category: :projects do
end
context 'as owner', :js do
+ it 'passes axe automated accessibility testing' do
+ subject
+
+ wait_for_requests
+
+ expect(page).to be_axe_clean.within('[data-testid="packages-and-registries-project-settings"]')
+ .skipping :'link-in-text-block'
+ end
+
it 'shows active tab on sidebar' do
subject
@@ -33,10 +42,10 @@ feature_category: :projects do
subject
settings_block = find('[data-testid="container-expiration-policy-project-settings"]')
- expect(settings_block).to have_text 'Clean up image tags'
+ expect(settings_block).to have_text 'Cleanup policies'
end
- it 'contains link to clean up image tags page' do
+ it 'contains link to cleanup policies page' do
subject
expect(page).to have_link('Edit cleanup rules', href: cleanup_image_tags_project_settings_packages_and_registries_path(project))
diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb
index a0625c93b1a..08abade7d18 100644
--- a/spec/features/projects/settings/repository_settings_spec.rb
+++ b/spec/features/projects/settings/repository_settings_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Projects > Settings > Repository settings', feature_category: :projects do
+ include Features::MirroringHelpers
+
let(:project) { create(:project_empty_repo) }
let(:user) { create(:user) }
let(:role) { :developer }
@@ -61,6 +63,10 @@ RSpec.describe 'Projects > Settings > Repository settings', feature_category: :p
let(:new_ssh_key) { attributes_for(:key)[:key] }
+ around do |example|
+ travel_to Time.zone.local(2022, 3, 1, 1, 0, 0) { example.run }
+ end
+
it 'get list of keys' do
project.deploy_keys << private_deploy_key
project.deploy_keys << public_deploy_key
@@ -83,6 +89,21 @@ RSpec.describe 'Projects > Settings > Repository settings', feature_category: :p
expect(page).to have_content('Grant write permissions to this key')
end
+ it 'add a new deploy key with expiration' do
+ one_month = Time.zone.local(2022, 4, 1, 1, 0, 0)
+ visit project_settings_repository_path(project)
+
+ fill_in 'deploy_key_title', with: 'new_deploy_key_with_expiry'
+ fill_in 'deploy_key_key', with: new_ssh_key
+ fill_in 'deploy_key_expires_at', with: one_month.to_s
+ check 'deploy_key_deploy_keys_projects_attributes_0_can_push'
+ click_button 'Add key'
+
+ expect(page).to have_content('new_deploy_key_with_expiry')
+ expect(page).to have_content('in 1 month')
+ expect(page).to have_content('Grant write permissions to this key')
+ end
+
it 'edit an existing deploy key' do
project.deploy_keys << private_deploy_key
visit project_settings_repository_path(project)
@@ -152,10 +173,8 @@ RSpec.describe 'Projects > Settings > Repository settings', feature_category: :p
end
it 'creates a push mirror that mirrors all branches', :js do
- expect(page).to have_css('.js-mirror-protected-hidden[value="0"]', visible: false)
-
- fill_in 'url', with: ssh_url
- expect(page).to have_css(".js-mirror-url-hidden[value=\"#{ssh_url}\"]", visible: false)
+ wait_for_mirror_field_javascript('protected', '0')
+ fill_and_wait_for_mirror_url_javascript('url', ssh_url)
select 'SSH public key', from: 'Authentication method'
select_direction
@@ -172,10 +191,8 @@ RSpec.describe 'Projects > Settings > Repository settings', feature_category: :p
it 'creates a push mirror that only mirrors protected branches', :js do
find('#only_protected_branches').click
- expect(page).to have_css('.js-mirror-protected-hidden[value="1"]', visible: false)
-
- fill_in 'url', with: ssh_url
- expect(page).to have_css(".js-mirror-url-hidden[value=\"#{ssh_url}\"]", visible: false)
+ wait_for_mirror_field_javascript('protected', '1')
+ fill_and_wait_for_mirror_url_javascript('url', ssh_url)
select 'SSH public key', from: 'Authentication method'
select_direction
@@ -192,8 +209,7 @@ RSpec.describe 'Projects > Settings > Repository settings', feature_category: :p
it 'creates a push mirror that keeps divergent refs', :js do
select_direction
- fill_in 'url', with: ssh_url
- expect(page).to have_css(".js-mirror-url-hidden[value=\"#{ssh_url}\"]", visible: false)
+ fill_and_wait_for_mirror_url_javascript('url', ssh_url)
fill_in 'Password', with: 'password'
check 'Keep divergent refs'
@@ -212,8 +228,7 @@ RSpec.describe 'Projects > Settings > Repository settings', feature_category: :p
end
it 'generates an SSH public key on submission', :js do
- fill_in 'url', with: ssh_url
- expect(page).to have_css(".js-mirror-url-hidden[value=\"#{ssh_url}\"]", visible: false)
+ fill_and_wait_for_mirror_url_javascript('url', ssh_url)
select 'SSH public key', from: 'Authentication method'
diff --git a/spec/features/projects/settings/service_desk_setting_spec.rb b/spec/features/projects/settings/service_desk_setting_spec.rb
index 859c738731b..74139aa0d7f 100644
--- a/spec/features/projects/settings/service_desk_setting_spec.rb
+++ b/spec/features/projects/settings/service_desk_setting_spec.rb
@@ -12,8 +12,8 @@ RSpec.describe 'Service Desk Setting', :js, :clean_gitlab_redis_cache, feature_c
sign_in(user)
allow_any_instance_of(Project).to receive(:present).with(current_user: user).and_return(presenter)
- allow(::Gitlab::IncomingEmail).to receive(:enabled?) { true }
- allow(::Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
+ allow(::Gitlab::Email::IncomingEmail).to receive(:enabled?) { true }
+ allow(::Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?) { true }
end
it 'shows activation checkbox' do
@@ -24,7 +24,7 @@ RSpec.describe 'Service Desk Setting', :js, :clean_gitlab_redis_cache, feature_c
context 'when service_desk_email is disabled' do
before do
- allow(::Gitlab::ServiceDeskEmail).to receive(:enabled?).and_return(false)
+ allow(::Gitlab::Email::ServiceDeskEmail).to receive(:enabled?).and_return(false)
visit edit_project_path(project)
end
@@ -43,8 +43,8 @@ RSpec.describe 'Service Desk Setting', :js, :clean_gitlab_redis_cache, feature_c
context 'when service_desk_email is enabled' do
before do
- allow(::Gitlab::ServiceDeskEmail).to receive(:enabled?) { true }
- allow(::Gitlab::ServiceDeskEmail).to receive(:address_for_key) { 'address-suffix@example.com' }
+ allow(::Gitlab::Email::ServiceDeskEmail).to receive(:enabled?) { true }
+ allow(::Gitlab::Email::ServiceDeskEmail).to receive(:address_for_key) { 'address-suffix@example.com' }
visit edit_project_path(project)
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 159a83a261d..b7463537fb2 100644
--- a/spec/features/projects/settings/user_manages_project_members_spec.rb
+++ b/spec/features/projects/settings/user_manages_project_members_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Settings > User manages project members', feature_category: :projects do
- include Spec::Support::Helpers::Features::MembersHelpers
+ include Features::MembersHelpers
include Spec::Support::Helpers::ModalHelpers
include ListboxHelpers
diff --git a/spec/features/projects/settings/user_renames_a_project_spec.rb b/spec/features/projects/settings/user_renames_a_project_spec.rb
index 2da6e760fbf..a6b72e7a297 100644
--- a/spec/features/projects/settings/user_renames_a_project_spec.rb
+++ b/spec/features/projects/settings/user_renames_a_project_spec.rb
@@ -37,7 +37,7 @@ RSpec.describe 'Projects > Settings > User renames a project', feature_category:
it 'shows errors for invalid project path' do
change_path(project, 'foo&bar')
- expect(page).to have_field 'Path', with: 'gitlab'
+ expect(page).to have_field 'Path', with: project.path
expect(page).to have_content "Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-', end in '.git' or end in '.atom'"
end
end
@@ -67,7 +67,7 @@ RSpec.describe 'Projects > Settings > User renames a project', feature_category:
end
context 'when changing project path' do
- let(:project) { create(:project, :repository, namespace: user.namespace, name: 'gitlabhq') }
+ let(:project) { create(:project, :repository, namespace: user.namespace, path: 'gitlabhq') }
before(:context) do
TestEnv.clean_test_path
diff --git a/spec/features/projects/settings/webhooks_settings_spec.rb b/spec/features/projects/settings/webhooks_settings_spec.rb
index 3b8b982b621..e527d0c9c74 100644
--- a/spec/features/projects/settings/webhooks_settings_spec.rb
+++ b/spec/features/projects/settings/webhooks_settings_spec.rb
@@ -83,7 +83,7 @@ RSpec.describe 'Projects > Settings > Webhook Settings', feature_category: :proj
visit webhooks_path
click_button 'Test'
- click_button 'Push events'
+ click_link 'Push events'
expect(page).to have_current_path(webhooks_path, ignore_query: true)
end
diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb
index 06e48bc82c0..a28416f3ca3 100644
--- a/spec/features/projects/snippets/create_snippet_spec.rb
+++ b/spec/features/projects/snippets/create_snippet_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Snippets > Create Snippet', :js, feature_category: :source_code_management do
include DropzoneHelper
- include Spec::Support::Helpers::Features::SnippetSpecHelpers
+ include Features::SnippetSpecHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) do
diff --git a/spec/features/projects/snippets/user_updates_snippet_spec.rb b/spec/features/projects/snippets/user_updates_snippet_spec.rb
index 014bf63c696..dda9a556d17 100644
--- a/spec/features/projects/snippets/user_updates_snippet_spec.rb
+++ b/spec/features/projects/snippets/user_updates_snippet_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Snippets > User updates a snippet', :js, feature_category: :source_code_management do
- include Spec::Support::Helpers::Features::SnippetSpecHelpers
+ include Features::SnippetSpecHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
diff --git a/spec/features/projects/terraform_spec.rb b/spec/features/projects/terraform_spec.rb
index 5e2f65165c2..b7500b0cfb7 100644
--- a/spec/features/projects/terraform_spec.rb
+++ b/spec/features/projects/terraform_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe 'Terraform', :js, feature_category: :projects do
end
it 'displays a tab with states count' do
- expect(page).to have_content("States #{project.terraform_states.size}")
+ expect(page).to have_content("Terraform states #{project.terraform_states.size}")
end
it 'displays a table with terraform states' do
diff --git a/spec/features/projects/tree/create_directory_spec.rb b/spec/features/projects/tree/create_directory_spec.rb
index 58f572bc021..8fae8f38025 100644
--- a/spec/features/projects/tree/create_directory_spec.rb
+++ b/spec/features/projects/tree/create_directory_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Multi-file editor new directory', :js, feature_category: :web_ide do
- include WebIdeSpecHelpers
+ include Features::WebIdeSpecHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
diff --git a/spec/features/projects/tree/create_file_spec.rb b/spec/features/projects/tree/create_file_spec.rb
index 674aef8e6f4..2f8935b9ce3 100644
--- a/spec/features/projects/tree/create_file_spec.rb
+++ b/spec/features/projects/tree/create_file_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Multi-file editor new file', :js, feature_category: :web_ide do
- include WebIdeSpecHelpers
+ include Features::WebIdeSpecHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
diff --git a/spec/features/projects/tree/tree_show_spec.rb b/spec/features/projects/tree/tree_show_spec.rb
index 52c6cb2192b..3becc48d450 100644
--- a/spec/features/projects/tree/tree_show_spec.rb
+++ b/spec/features/projects/tree/tree_show_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects tree', :js, feature_category: :web_ide do
- include WebIdeSpecHelpers
+ include Features::WebIdeSpecHelpers
include RepoHelpers
include ListboxHelpers
diff --git a/spec/features/projects/tree/upload_file_spec.rb b/spec/features/projects/tree/upload_file_spec.rb
index 42fa88a0d3e..6ec57af2590 100644
--- a/spec/features/projects/tree/upload_file_spec.rb
+++ b/spec/features/projects/tree/upload_file_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Multi-file editor upload file', :js, feature_category: :web_ide do
- include WebIdeSpecHelpers
+ include Features::WebIdeSpecHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
diff --git a/spec/features/projects/user_changes_project_visibility_spec.rb b/spec/features/projects/user_changes_project_visibility_spec.rb
index 5daa5b98b6e..64af25aea28 100644
--- a/spec/features/projects/user_changes_project_visibility_spec.rb
+++ b/spec/features/projects/user_changes_project_visibility_spec.rb
@@ -91,23 +91,4 @@ RSpec.describe 'User changes public project visibility', :js, feature_category:
it_behaves_like 'does not require confirmation'
end
-
- context 'with unlink_fork_network_upon_visibility_decrease = false' do
- let(:project) { create(:project, :empty_repo, :public) }
-
- before do
- stub_feature_flags(unlink_fork_network_upon_visibility_decrease: false)
-
- fork_project(project, project.first_owner)
-
- sign_in(project.first_owner)
-
- visit edit_project_path(project)
-
- # https://gitlab.com/gitlab-org/gitlab/-/issues/381259
- allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(110)
- end
-
- it_behaves_like 'does not require confirmation'
- end
end
diff --git a/spec/features/projects/user_sees_user_popover_spec.rb b/spec/features/projects/user_sees_user_popover_spec.rb
index 5badcd99dff..9d8d06c514e 100644
--- a/spec/features/projects/user_sees_user_popover_spec.rb
+++ b/spec/features/projects/user_sees_user_popover_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User sees user popover', :js, feature_category: :projects do
- include Spec::Support::Helpers::Features::NotesHelpers
+ include Features::NotesHelpers
let_it_be(:user) { create(:user, pronouns: 'they/them') }
let_it_be(:project) { create(:project, :repository, creator: user) }
diff --git a/spec/features/projects/user_uses_shortcuts_spec.rb b/spec/features/projects/user_uses_shortcuts_spec.rb
index 05d79ea3b1b..1d4ab242308 100644
--- a/spec/features/projects/user_uses_shortcuts_spec.rb
+++ b/spec/features/projects/user_uses_shortcuts_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :projects do
before do
sign_in(user)
+ stub_feature_flags(remove_monitor_metrics: false)
visit(project_path(project))
@@ -68,11 +69,11 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :projects do
end
context 'when navigating to the Project pages' do
- it 'redirects to the project page' do
+ it 'redirects to the project overview page' do
visit project_issues_path(project)
find('body').native.send_key('g')
- find('body').native.send_key('p')
+ find('body').native.send_key('o')
expect(page).to have_active_navigation(project.name)
end
@@ -155,6 +156,14 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :projects do
end
context 'when navigating to the CI/CD pages' do
+ it 'redirects to the Pipelines page' do
+ find('body').native.send_key('g')
+ find('body').native.send_key('p')
+
+ expect(page).to have_active_navigation('CI/CD')
+ expect(page).to have_active_sub_navigation('Pipelines')
+ end
+
it 'redirects to the Jobs page' do
find('body').native.send_key('g')
find('body').native.send_key('j')
diff --git a/spec/features/projects/user_views_empty_project_spec.rb b/spec/features/projects/user_views_empty_project_spec.rb
index e2b56e8ced6..e38cfc2273a 100644
--- a/spec/features/projects/user_views_empty_project_spec.rb
+++ b/spec/features/projects/user_views_empty_project_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User views an empty project', feature_category: :projects do
- include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Features::InviteMembersModalHelpers
let_it_be(:project) { create(:project, :empty_repo) }
let_it_be(:user) { create(:user) }
diff --git a/spec/features/work_items/work_item_children_spec.rb b/spec/features/projects/work_items/work_item_children_spec.rb
index f41fb86d13c..43a6b2771f6 100644
--- a/spec/features/work_items/work_item_children_spec.rb
+++ b/spec/features/projects/work_items/work_item_children_spec.rb
@@ -132,5 +132,48 @@ RSpec.describe 'Work item children', :js, feature_category: :team_planning do
end
end
end
+
+ context 'in work item metadata' do
+ let_it_be(:label) { create(:label, title: 'Label 1', project: project) }
+ let_it_be(:milestone) { create(:milestone, project: project, title: 'v1') }
+ let_it_be(:task) do
+ create(
+ :work_item,
+ :task,
+ project: project,
+ labels: [label],
+ assignees: [user],
+ milestone: milestone
+ )
+ end
+
+ before do
+ visit project_issue_path(project, issue)
+
+ wait_for_requests
+ end
+
+ it 'displays labels, milestone and assignee for work item children', :aggregate_failures do
+ page.within('[data-testid="work-item-links"]') do
+ click_button 'Add'
+ click_button 'Existing task'
+
+ find('[data-testid="work-item-token-select-input"]').set(task.title)
+ wait_for_all_requests
+ click_button task.title
+
+ click_button 'Add task'
+
+ wait_for_all_requests
+ end
+
+ page.within('[data-testid="links-child"]') do
+ expect(page).to have_content(task.title)
+ expect(page).to have_content(label.title)
+ expect(page).to have_link(user.name)
+ expect(page).to have_content(milestone.title)
+ end
+ end
+ end
end
end
diff --git a/spec/features/projects/work_items/work_item_spec.rb b/spec/features/projects/work_items/work_item_spec.rb
new file mode 100644
index 00000000000..b706a624fc5
--- /dev/null
+++ b/spec/features/projects/work_items/work_item_spec.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Work item', :js, feature_category: :team_planning do
+ let_it_be_with_reload(:user) { create(:user) }
+
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:work_item) { create(:work_item, project: project) }
+ let_it_be(:milestone) { create(:milestone, project: project) }
+ let_it_be(:milestones) { create_list(:milestone, 25, project: project) }
+ let_it_be(:note) { create(:note, noteable: work_item, project: work_item.project) }
+ let(:work_items_path) { project_work_items_path(project, work_items_path: work_item.iid) }
+
+ context 'for signed in user' do
+ before do
+ project.add_developer(user)
+
+ sign_in(user)
+
+ visit work_items_path
+ end
+
+ it 'shows project issues link in breadcrumbs' do
+ within('[data-testid="breadcrumb-links"]') do
+ expect(page).to have_link('Issues', href: project_issues_path(project))
+ end
+ end
+
+ it 'uses IID path in breadcrumbs' do
+ within('[data-testid="breadcrumb-current-link"]') do
+ expect(page).to have_link("##{work_item.iid}", href: work_items_path)
+ end
+ end
+
+ it_behaves_like 'work items title'
+ it_behaves_like 'work items status'
+ it_behaves_like 'work items assignees'
+ it_behaves_like 'work items labels'
+ it_behaves_like 'work items comments', :issue
+ it_behaves_like 'work items description'
+ it_behaves_like 'work items milestone'
+ it_behaves_like 'work items notifications'
+ it_behaves_like 'work items todos'
+ it_behaves_like 'work items award emoji'
+ end
+
+ context 'for signed in owner' do
+ before do
+ project.add_owner(user)
+
+ sign_in(user)
+
+ visit work_items_path
+ end
+
+ it_behaves_like 'work items invite members'
+ end
+
+ context 'for guest users' do
+ before do
+ project.add_guest(user)
+
+ sign_in(user)
+
+ visit work_items_path
+ end
+
+ it_behaves_like 'work items comment actions for guest users'
+ end
+
+ context 'for user not signed in' do
+ before do
+ visit work_items_path
+ end
+
+ it 'actions dropdown is not displayed' do
+ expect(page).not_to have_selector('[data-testid="work-item-actions-dropdown"]')
+ end
+
+ it 'todos action is not displayed' do
+ expect(page).not_to have_selector('[data-testid="work-item-todos-action"]')
+ end
+
+ it 'award button is disabled and add reaction is not displayed' do
+ within('[data-testid="work-item-award-list"]') do
+ expect(page).not_to have_selector('[data-testid="emoji-picker"]')
+ expect(page).to have_selector('[data-testid="award-button"].disabled')
+ end
+ end
+ end
+end
diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb
index 04096b3e4f9..e4a64d391b0 100644
--- a/spec/features/protected_branches_spec.rb
+++ b/spec/features/protected_branches_spec.rb
@@ -96,6 +96,15 @@ RSpec.describe 'Protected Branches', :js, feature_category: :source_code_managem
expect(ProtectedBranch.last.name).to eq('some->branch')
end
+ it "shows success alert once protected branch is created" do
+ visit project_protected_branches_path(project)
+ set_defaults
+ set_protected_branch_name('some->branch')
+ click_on "Protect"
+ wait_for_requests
+ expect(page).to have_content(s_('ProtectedBranch|View protected branches as branch rules'))
+ end
+
it "displays the last commit on the matching branch if it exists" do
commit = create(:commit, project: project)
project.repository.add_branch(admin, 'some-branch', commit.id)
diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb
index c2058a5c345..45315f53fd6 100644
--- a/spec/features/protected_tags_spec.rb
+++ b/spec/features/protected_tags_spec.rb
@@ -16,8 +16,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
it "allows creating explicit protected tags" do
visit project_protected_tags_path(project)
set_protected_tag_name('some-tag')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
within(".protected-tags-list") { expect(page).to have_content('some-tag') }
expect(ProtectedTag.count).to eq(1)
@@ -30,8 +30,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
visit project_protected_tags_path(project)
set_protected_tag_name('some-tag')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
within(".protected-tags-list") { expect(page).to have_content(commit.id[0..7]) }
end
@@ -39,8 +39,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
it "displays an error message if the named tag does not exist" do
visit project_protected_tags_path(project)
set_protected_tag_name('some-tag')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
within(".protected-tags-list") { expect(page).to have_content('tag was removed') }
end
@@ -50,8 +50,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
it "allows creating protected tags with a wildcard" do
visit project_protected_tags_path(project)
set_protected_tag_name('*-stable')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
within(".protected-tags-list") { expect(page).to have_content('*-stable') }
expect(ProtectedTag.count).to eq(1)
@@ -64,8 +64,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
visit project_protected_tags_path(project)
set_protected_tag_name('*-stable')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
within(".protected-tags-list") do
expect(page).to have_content("Protected tags (2)")
@@ -80,8 +80,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
visit project_protected_tags_path(project)
set_protected_tag_name('*-stable')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
visit project_protected_tags_path(project)
click_on "2 matching tags"
@@ -101,4 +101,14 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
include_examples "protected tags > access control > CE"
end
+
+ context 'when the users for protected tags feature is off' do
+ before do
+ stub_licensed_features(protected_refs_for_users: false)
+ end
+
+ include_examples 'Deploy keys with protected tags' do
+ let(:all_dropdown_sections) { ['Roles', 'Deploy Keys'] }
+ end
+ end
end
diff --git a/spec/features/reportable_note/issue_spec.rb b/spec/features/reportable_note/issue_spec.rb
index 55e7f5897bc..a18cdf27294 100644
--- a/spec/features/reportable_note/issue_spec.rb
+++ b/spec/features/reportable_note/issue_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Reportable note on issue', :js, feature_category: :team_planning do
+ include CookieHelper
+
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
@@ -11,7 +13,7 @@ RSpec.describe 'Reportable note on issue', :js, feature_category: :team_planning
before do
project.add_maintainer(user)
sign_in(user)
-
+ set_cookie('new-actions-popover-viewed', 'true')
visit project_issue_path(project, issue)
end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index b2ddf427c0d..452a5700e08 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -14,23 +14,58 @@ RSpec.describe 'Runners', feature_category: :runner_fleet do
stub_feature_flags(project_runners_vue_ui: false)
end
- context 'when user opens runners page' do
- let(:project) { create(:project) }
+ context 'when user views runners page' do
+ let_it_be(:project) { create(:project) }
before do
project.add_maintainer(user)
end
- it 'user can see a link with instructions on how to install GitLab Runner' do
- visit project_runners_path(project)
+ context 'when create_runner_workflow_for_namespace is enabled', :js do
+ before do
+ stub_feature_flags(create_runner_workflow_for_namespace: [project.namespace])
+
+ visit project_runners_path(project)
+ end
+
+ it 'user can see a link with instructions on how to install GitLab Runner' do
+ expect(page).to have_link(s_('Runners|New project runner'), href: new_project_runner_path(project))
+ end
+
+ it_behaves_like "shows and resets runner registration token" do
+ let(:dropdown_text) { s_('Runners|Register a project runner') }
+ let(:registration_token) { project.runners_token }
+ end
+ end
+
+ context 'when user views new runner page' do
+ context 'when create_runner_workflow_for_namespace is enabled', :js do
+ before do
+ stub_feature_flags(create_runner_workflow_for_namespace: [project.namespace])
+
+ visit new_project_runner_path(project)
+ end
- expect(page).to have_link('Install GitLab Runner and ensure it\'s running.', href: "https://docs.gitlab.com/runner/install/")
+ it_behaves_like 'creates runner and shows register page' do
+ let(:register_path_pattern) { register_project_runner_path(project, '.*') }
+ end
+ end
end
- describe 'runners registration token' do
- let!(:token) { project.runners_token }
+ context 'when create_runner_workflow_for_namespace is disabled' do
+ before do
+ stub_feature_flags(create_runner_workflow_for_namespace: false)
+ end
+
+ it 'user can see a link with instructions on how to install GitLab Runner' do
+ visit project_runners_path(project)
+
+ expect(page).to have_link('Install GitLab Runner and ensure it\'s running.', href: "https://docs.gitlab.com/runner/install/")
+ end
+
+ describe 'runners registration token' do
+ let!(:token) { project.runners_token }
- context 'when project_runners_vue_ui is disabled' do
before do
visit project_runners_path(project)
end
diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb
index b7d06a3a962..976324a5032 100644
--- a/spec/features/search/user_searches_for_code_spec.rb
+++ b/spec/features/search/user_searches_for_code_spec.rb
@@ -99,64 +99,11 @@ RSpec.describe 'User searches for code', :js, :disable_rate_limiter, feature_cat
end
end
- context 'when :new_header_search is true' do
+ context 'when header search' do
context 'search code within refs' do
let(:ref_name) { 'v1.0.0' }
before do
- # This feature is disabled by default in spec_helper.rb.
- # We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
- # This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
- stub_feature_flags(new_header_search: true)
- visit(project_tree_path(project, ref_name))
-
- submit_search('gitlab-grack')
- select_search_scope('Code')
- end
-
- it 'shows ref switcher in code result summary' do
- expect(find('.ref-selector')).to have_text(ref_name)
- end
-
- it 'persists branch name across search' do
- find('.gl-search-box-by-click-search-button').click
- expect(find('.ref-selector')).to have_text(ref_name)
- end
-
- # this example is use to test the design that the refs is not
- # only represent the branch as well as the tags.
- it 'ref switcher list all the branches and tags' do
- find('.ref-selector').click
- wait_for_requests
-
- page.within('.ref-selector') do
- expect(page).to have_selector('li', text: 'add-ipython-files')
- expect(page).to have_selector('li', text: 'v1.0.0')
- end
- end
-
- it 'search result changes when refs switched' do
- expect(find('.results')).not_to have_content('path = gitlab-grack')
-
- find('.ref-selector').click
- wait_for_requests
-
- select_listbox_item('add-ipython-files')
-
- expect(page).to have_selector('.results', text: 'path = gitlab-grack')
- end
- end
- end
-
- context 'when :new_header_search is false' do
- context 'search code within refs' do
- let(:ref_name) { 'v1.0.0' }
-
- before do
- # This feature is disabled by default in spec_helper.rb.
- # We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
- # This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
- stub_feature_flags(new_header_search: false)
visit(project_tree_path(project, ref_name))
submit_search('gitlab-grack')
diff --git a/spec/features/search/user_uses_header_search_field_spec.rb b/spec/features/search/user_uses_header_search_field_spec.rb
index 334a192bec4..71d0f8d6d7f 100644
--- a/spec/features/search/user_uses_header_search_field_spec.rb
+++ b/spec/features/search/user_uses_header_search_field_spec.rb
@@ -26,11 +26,21 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
wait_for_all_requests
end
- it 'starts searching by pressing the enter key' do
- submit_search('gitlab')
+ context 'when searching by pressing the enter key' do
+ before do
+ submit_search('gitlab')
+ end
+
+ it 'renders page title' do
+ page.within('.page-title') do
+ expect(page).to have_content('Search')
+ end
+ end
- page.within('.page-title') do
- expect(page).to have_content('Search')
+ it 'renders breadcrumbs' do
+ page.within('.breadcrumbs') do
+ expect(page).to have_content('Search')
+ end
end
end
diff --git a/spec/features/security/admin_access_spec.rb b/spec/features/security/admin_access_spec.rb
index de81444ed71..d162b24175f 100644
--- a/spec/features/security/admin_access_spec.rb
+++ b/spec/features/security/admin_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Admin::Projects", feature_category: :permissions do
+RSpec.describe "Admin::Projects", feature_category: :system_access do
include AccessMatchers
describe "GET /admin/projects" do
diff --git a/spec/features/security/dashboard_access_spec.rb b/spec/features/security/dashboard_access_spec.rb
index 948a4567624..0d60f1b1d11 100644
--- a/spec/features/security/dashboard_access_spec.rb
+++ b/spec/features/security/dashboard_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Dashboard access", feature_category: :permissions do
+RSpec.describe "Dashboard access", feature_category: :system_access do
include AccessMatchers
describe "GET /dashboard" do
diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb
index ad2df4a1882..49f81600ac2 100644
--- a/spec/features/security/group/internal_access_spec.rb
+++ b/spec/features/security/group/internal_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Internal Group access', feature_category: :permissions do
+RSpec.describe 'Internal Group access', feature_category: :system_access do
include AccessMatchers
let(:group) { create(:group, :internal) }
diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb
index 2e7b7512b45..5206667427e 100644
--- a/spec/features/security/group/private_access_spec.rb
+++ b/spec/features/security/group/private_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Private Group access', feature_category: :permissions do
+RSpec.describe 'Private Group access', feature_category: :system_access do
include AccessMatchers
let(:group) { create(:group, :private) }
diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb
index 513c5710c8f..5c5580908aa 100644
--- a/spec/features/security/group/public_access_spec.rb
+++ b/spec/features/security/group/public_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Public Group access', feature_category: :permissions do
+RSpec.describe 'Public Group access', feature_category: :system_access do
include AccessMatchers
let(:group) { create(:group, :public) }
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index e35e7ed742b..8ad4bedfdf8 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Internal Project Access", feature_category: :permissions do
+RSpec.describe "Internal Project Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project, reload: true) { create(:project, :internal, :repository, :with_namespace_settings) }
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index 59ddb18ae8a..d2d74ecf5c9 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Private Project Access", feature_category: :permissions do
+RSpec.describe "Private Project Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project, reload: true) do
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 425691001f2..916f289b0b8 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Public Project Access", feature_category: :permissions do
+RSpec.describe "Public Project Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project, reload: true) do
diff --git a/spec/features/security/project/snippet/internal_access_spec.rb b/spec/features/security/project/snippet/internal_access_spec.rb
index b7dcc5f31d3..6ed0ec20210 100644
--- a/spec/features/security/project/snippet/internal_access_spec.rb
+++ b/spec/features/security/project/snippet/internal_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Internal Project Snippets Access", feature_category: :permissions do
+RSpec.describe "Internal Project Snippets Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project) { create(:project, :internal) }
diff --git a/spec/features/security/project/snippet/private_access_spec.rb b/spec/features/security/project/snippet/private_access_spec.rb
index 0ae45abb7ec..ef61f79a1b5 100644
--- a/spec/features/security/project/snippet/private_access_spec.rb
+++ b/spec/features/security/project/snippet/private_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Private Project Snippets Access", feature_category: :permissions do
+RSpec.describe "Private Project Snippets Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project) { create(:project, :private) }
diff --git a/spec/features/security/project/snippet/public_access_spec.rb b/spec/features/security/project/snippet/public_access_spec.rb
index b98f665c0dc..27fee745635 100644
--- a/spec/features/security/project/snippet/public_access_spec.rb
+++ b/spec/features/security/project/snippet/public_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Public Project Snippets Access", feature_category: :permissions do
+RSpec.describe "Public Project Snippets Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/features/signed_commits_spec.rb b/spec/features/signed_commits_spec.rb
index 5d9b451cdf6..0268c8ad0d4 100644
--- a/spec/features/signed_commits_spec.rb
+++ b/spec/features/signed_commits_spec.rb
@@ -98,7 +98,8 @@ RSpec.describe 'GPG signed commits', feature_category: :source_code_management d
end
end
- it 'unverified signature: gpg key email does not match the committer_email when the committer_email belongs to the user as a unconfirmed secondary email' do
+ it 'unverified signature: gpg key email does not match the committer_email when the committer_email belongs to the user as a unconfirmed secondary email',
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408233' do
user_2_key
visit project_commit_path(project, GpgHelpers::SIGNED_COMMIT_SHA)
@@ -112,7 +113,7 @@ RSpec.describe 'GPG signed commits', feature_category: :source_code_management d
end
end
- it 'unverified signature: commit contains multiple GPG signatures' do
+ it 'unverified signature: commit contains multiple GPG signatures', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408233' do
user_1_key
visit project_commit_path(project, GpgHelpers::MULTIPLE_SIGNATURES_SHA)
@@ -125,7 +126,7 @@ RSpec.describe 'GPG signed commits', feature_category: :source_code_management d
end
end
- it 'verified and the gpg user has a gitlab profile' do
+ it 'verified and the gpg user has a gitlab profile', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408233' do
user_1_key
visit project_commit_path(project, GpgHelpers::SIGNED_AND_AUTHORED_SHA)
@@ -139,7 +140,7 @@ RSpec.describe 'GPG signed commits', feature_category: :source_code_management d
end
end
- it "verified and the gpg user's profile doesn't exist anymore" do
+ it "verified and the gpg user's profile doesn't exist anymore", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/395802' do
user_1_key
visit project_commit_path(project, GpgHelpers::SIGNED_AND_AUTHORED_SHA)
diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb
index c281e5906ad..5c1ee729346 100644
--- a/spec/features/snippets/notes_on_personal_snippets_spec.rb
+++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb
@@ -81,6 +81,7 @@ RSpec.describe 'Comments on personal snippets', :js, feature_category: :source_c
it 'previews a note' do
fill_in 'note[note]', with: 'This is **awesome**!'
+
find('.js-md-preview-button').click
page.within('.new-note .md-preview-holder') do
@@ -119,20 +120,36 @@ RSpec.describe 'Comments on personal snippets', :js, feature_category: :source_c
end
context 'when editing a note' do
- it 'changes the text' do
- find('.js-note-edit').click
+ context 'when note is empty' do
+ before do
+ find('.js-note-edit').click
- page.within('.current-note-edit-form') do
- fill_in 'note[note]', with: 'new content'
- find('.btn-confirm').click
+ page.within('.current-note-edit-form') do
+ fill_in 'note[note]', with: ''
+ end
end
- page.within("#notes-list li#note_#{snippet_notes[0].id}") do
- edited_text = find('.edited-text')
+ it 'disables save button' do
+ expect(page).to have_button('Save comment', disabled: true)
+ end
+ end
+
+ context 'when note is not empty' do
+ it 'changes the text' do
+ find('.js-note-edit').click
+
+ page.within('.current-note-edit-form') do
+ fill_in 'note[note]', with: 'new content'
+ find('.btn-confirm').click
+ end
+
+ page.within("#notes-list li#note_#{snippet_notes[0].id}") do
+ edited_text = find('.edited-text')
- expect(page).to have_css('.note_edited_ago')
- expect(page).to have_content('new content')
- expect(edited_text).to have_selector('.note_edited_ago')
+ expect(page).to have_css('.note_edited_ago')
+ expect(page).to have_content('new content')
+ expect(edited_text).to have_selector('.note_edited_ago')
+ end
end
end
end
diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb
index dc2fcdd7305..2673ad5e1d7 100644
--- a/spec/features/snippets/show_spec.rb
+++ b/spec/features/snippets/show_spec.rb
@@ -25,14 +25,13 @@ RSpec.describe 'Snippet', :js, feature_category: :source_code_management do
subject { visit snippet_path(snippet) }
end
- it_behaves_like 'a dashboard page with sidebar', :dashboard_snippets_path, :snippets
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_snippets_path, :snippets
context 'when unauthenticated' do
- it 'does not have the sidebar' do
+ it 'shows the "Explore" sidebar' do
visit snippet_path(snippet)
- expect(page).to have_title _('Snippets')
- expect(page).not_to have_css('aside.nav-sidebar')
+ expect(page).to have_css('aside.nav-sidebar[aria-label="Explore"]')
end
end
@@ -43,6 +42,6 @@ RSpec.describe 'Snippet', :js, feature_category: :source_code_management do
sign_in(different_user)
end
- it_behaves_like 'a dashboard page with sidebar', :dashboard_snippets_path, :snippets
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_snippets_path, :snippets
end
end
diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb
index 03f569fe4b0..f4b6b552d46 100644
--- a/spec/features/snippets/user_creates_snippet_spec.rb
+++ b/spec/features/snippets/user_creates_snippet_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'User creates snippet', :js, feature_category: :source_code_management do
include DropzoneHelper
- include Spec::Support::Helpers::Features::SnippetSpecHelpers
+ include Features::SnippetSpecHelpers
let_it_be(:user) { create(:user) }
@@ -21,7 +21,7 @@ RSpec.describe 'User creates snippet', :js, feature_category: :source_code_manag
visit new_snippet_path
end
- it_behaves_like 'a dashboard page with sidebar', :new_snippet_path, :snippets
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :new_snippet_path, :snippets
def fill_form
snippet_fill_in_form(title: title, content: file_content, description: md_description)
@@ -128,7 +128,7 @@ RSpec.describe 'User creates snippet', :js, feature_category: :source_code_manag
expect(page).not_to have_content(files_validation_message)
end
- it 'previews a snippet with file' do
+ it 'previews a snippet with file', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408203' do
# Click placeholder first to expand full description field
snippet_fill_in_description('My Snippet')
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
diff --git a/spec/features/snippets/user_edits_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb
index 5096472ebe1..f58fda67b59 100644
--- a/spec/features/snippets/user_edits_snippet_spec.rb
+++ b/spec/features/snippets/user_edits_snippet_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'User edits snippet', :js, feature_category: :source_code_management do
include DropzoneHelper
- include Spec::Support::Helpers::Features::SnippetSpecHelpers
+ include Features::SnippetSpecHelpers
let_it_be(:file_name) { 'test.rb' }
let_it_be(:content) { 'puts "test"' }
diff --git a/spec/features/tags/developer_creates_tag_spec.rb b/spec/features/tags/developer_creates_tag_spec.rb
index 6a1db051e87..cb59ee17514 100644
--- a/spec/features/tags/developer_creates_tag_spec.rb
+++ b/spec/features/tags/developer_creates_tag_spec.rb
@@ -62,7 +62,7 @@ RSpec.describe 'Developer creates tag', :js, feature_category: :source_code_mana
expect(ref_input.value).to eq 'master'
expect(find('.gl-button-text')).to have_content 'master'
find('.ref-selector').click
- expect(find('.gl-new-dropdown-inner')).to have_content 'test'
+ expect(find('.gl-new-dropdown-inner')).to have_content 'spooky-stuff'
end
end
end
diff --git a/spec/features/tags/developer_deletes_tag_spec.rb b/spec/features/tags/developer_deletes_tag_spec.rb
index 76cf3aa691d..19feb5b21bc 100644
--- a/spec/features/tags/developer_deletes_tag_spec.rb
+++ b/spec/features/tags/developer_deletes_tag_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Developer deletes tag', :js, feature_category: :source_code_management do
+ include Spec::Support::Helpers::ModalHelpers
+
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, :repository, namespace: group) }
@@ -18,7 +20,7 @@ RSpec.describe 'Developer deletes tag', :js, feature_category: :source_code_mana
it 'deletes the tag' do
expect(page).to have_content 'v1.1.0'
- container = page.find('.content .flex-row', text: 'v1.1.0')
+ container = page.find('[data-testid="tag-row"]', text: 'v1.1.0')
delete_tag container
expect(page).not_to have_content 'v1.1.0'
@@ -28,7 +30,7 @@ RSpec.describe 'Developer deletes tag', :js, feature_category: :source_code_mana
it 'can not delete protected tags' do
expect(page).to have_content 'v1.1.1'
- container = page.find('.content .flex-row', text: 'v1.1.1')
+ container = page.find('[data-testid="tag-row"]', text: 'v1.1.1')
expect(container).to have_button('Only a project maintainer or owner can delete a protected tag',
disabled: true)
end
@@ -41,8 +43,7 @@ RSpec.describe 'Developer deletes tag', :js, feature_category: :source_code_mana
expect(page).to have_current_path(
project_tag_path(project, 'v1.0.0'), ignore_query: true)
- container = page.find('.nav-controls')
- delete_tag container
+ delete_tag
expect(page).to have_current_path(project_tags_path(project), ignore_query: true)
expect(page).not_to have_content 'v1.0.0'
@@ -58,17 +59,22 @@ RSpec.describe 'Developer deletes tag', :js, feature_category: :source_code_mana
end
it 'shows the error message' do
- container = page.find('.content .flex-row', text: 'v1.1.0')
+ container = page.find('[data-testid="tag-row"]', text: 'v1.1.0')
delete_tag container
expect(page).to have_content('Do not delete tags')
end
end
- def delete_tag(container)
- container.find('.js-delete-tag-button').click
+ def delete_tag(container = page.document)
+ within container do
+ click_button('Delete tag')
+ end
+
+ within_modal do
+ click_button('Yes, delete tag')
+ end
- page.within('.modal') { click_button('Yes, delete tag') }
wait_for_requests
end
end
diff --git a/spec/features/tags/developer_views_tags_spec.rb b/spec/features/tags/developer_views_tags_spec.rb
index dc9f38f1d83..81a41951377 100644
--- a/spec/features/tags/developer_views_tags_spec.rb
+++ b/spec/features/tags/developer_views_tags_spec.rb
@@ -60,7 +60,6 @@ RSpec.describe 'Developer views tags', feature_category: :source_code_management
expect(page).to have_current_path(
project_tag_path(project, 'v1.0.0'), ignore_query: true)
expect(page).to have_content 'v1.0.0'
- expect(page).to have_content 'This tag has no release notes.'
end
describe 'links on the tag page' do
diff --git a/spec/features/tags/maintainer_deletes_protected_tag_spec.rb b/spec/features/tags/maintainer_deletes_protected_tag_spec.rb
index ce518b962cd..67f6862502c 100644
--- a/spec/features/tags/maintainer_deletes_protected_tag_spec.rb
+++ b/spec/features/tags/maintainer_deletes_protected_tag_spec.rb
@@ -19,7 +19,10 @@ RSpec.describe 'Maintainer deletes protected tag', :js, feature_category: :sourc
it 'deletes the tag' do
expect(page).to have_content "#{tag_name} protected"
- page.find('.content .flex-row', text: tag_name).find('.js-delete-tag-button').click
+ page.within('[data-testid="tag-row"]', text: tag_name) do
+ click_button('Delete tag')
+ end
+
assert_modal_content(tag_name)
confirm_delete_tag(tag_name)
@@ -35,7 +38,7 @@ RSpec.describe 'Maintainer deletes protected tag', :js, feature_category: :sourc
it 'deletes the tag' do
expect(page).to have_current_path(project_tag_path(project, tag_name), ignore_query: true)
- page.find('.js-delete-tag-button').click
+ click_button('Delete tag')
assert_modal_content(tag_name)
confirm_delete_tag(tag_name)
diff --git a/spec/features/topic_show_spec.rb b/spec/features/topic_show_spec.rb
index d640e4e4edb..39b8782ea58 100644
--- a/spec/features/topic_show_spec.rb
+++ b/spec/features/topic_show_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'Topic show page', feature_category: :projects do
it 'shows title, avatar and description as markdown' do
expect(page).to have_content(topic.title)
expect(page).not_to have_content(topic.name)
- expect(page).to have_selector('.avatar-container > img.topic-avatar')
+ expect(page).to have_selector('.gl-avatar.gl-avatar-s64')
expect(find('.topic-description')).to have_selector('p > strong')
expect(find('.topic-description')).to have_selector('p > a[rel]')
expect(find('.topic-description')).to have_selector('p > gl-emoji')
diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb
deleted file mode 100644
index 9ef0626b2b2..00000000000
--- a/spec/features/u2f_spec.rb
+++ /dev/null
@@ -1,216 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js,
-feature_category: :authentication_and_authorization do
- include Spec::Support::Helpers::Features::TwoFactorHelpers
-
- before do
- stub_feature_flags(webauthn: false)
- end
-
- it_behaves_like 'hardware device for 2fa', 'U2F'
-
- describe "registration" do
- let(:user) { create(:user) }
-
- before do
- gitlab_sign_in(user)
- user.update_attribute(:otp_required_for_login, true)
- end
-
- describe 'when 2FA via OTP is enabled' do
- it 'allows registering more than one device' do
- visit profile_account_path
-
- # First device
- manage_two_factor_authentication
- first_device = register_u2f_device
- expect(page).to have_content('Your U2F device was registered')
-
- # Second device
- second_device = register_u2f_device(name: 'My other device')
- expect(page).to have_content('Your U2F device was registered')
-
- expect(page).to have_content(first_device.name)
- expect(page).to have_content(second_device.name)
- expect(U2fRegistration.count).to eq(2)
- end
- end
-
- it 'allows the same device to be registered for multiple users' do
- # U2f specs will be removed after WebAuthn migration completed
- pending('FakeU2fDevice has static key handle, '\
- 'leading to duplicate credential_xid for WebAuthn during migration, '\
- 'resulting in unique constraint violation')
-
- # First user
- visit profile_account_path
- manage_two_factor_authentication
- u2f_device = register_u2f_device
- expect(page).to have_content('Your U2F device was registered')
- gitlab_sign_out
-
- # Second user
- user = gitlab_sign_in(:user)
- user.update_attribute(:otp_required_for_login, true)
- visit profile_account_path
- manage_two_factor_authentication
- register_u2f_device(u2f_device, name: 'My other device')
- expect(page).to have_content('Your U2F device was registered')
-
- expect(U2fRegistration.count).to eq(2)
- end
-
- context "when there are form errors" do
- it "doesn't register the device if there are errors" do
- visit profile_account_path
- manage_two_factor_authentication
-
- # Have the "u2f device" respond with bad data
- page.execute_script("u2f.register = function(_,_,_,callback) { callback('bad response'); };")
- click_on 'Set up new device'
- expect(page).to have_content('Your device was successfully set up')
- click_on 'Register device'
-
- expect(U2fRegistration.count).to eq(0)
- expect(page).to have_content("The form contains the following error")
- expect(page).to have_content("did not send a valid JSON response")
- end
-
- it "allows retrying registration" do
- visit profile_account_path
- manage_two_factor_authentication
-
- # Failed registration
- page.execute_script("u2f.register = function(_,_,_,callback) { callback('bad response'); };")
- click_on 'Set up new device'
- expect(page).to have_content('Your device was successfully set up')
- click_on 'Register device'
- expect(page).to have_content("The form contains the following error")
-
- # Successful registration
- register_u2f_device
-
- expect(page).to have_content('Your U2F device was registered')
- expect(U2fRegistration.count).to eq(1)
- end
- end
- end
-
- describe "authentication" do
- let(:user) { create(:user) }
-
- before do
- # Register and logout
- gitlab_sign_in(user)
- user.update_attribute(:otp_required_for_login, true)
- visit profile_account_path
- manage_two_factor_authentication
- @u2f_device = register_u2f_device
- gitlab_sign_out
- end
-
- describe "when 2FA via OTP is disabled" do
- it "allows logging in with the U2F device" do
- user.update_attribute(:otp_required_for_login, false)
- gitlab_sign_in(user)
-
- @u2f_device.respond_to_u2f_authentication
-
- expect(page).to have_css('.sign-out-link', visible: false)
- end
- end
-
- describe "when 2FA via OTP is enabled" do
- it "allows logging in with the U2F device" do
- user.update_attribute(:otp_required_for_login, true)
- gitlab_sign_in(user)
-
- @u2f_device.respond_to_u2f_authentication
-
- expect(page).to have_css('.sign-out-link', visible: false)
- end
- end
-
- describe "when a given U2F device has already been registered by another user" do
- describe "but not the current user" do
- it "does not allow logging in with that particular device" do
- # Register current user with the different U2F device
- current_user = gitlab_sign_in(:user)
- current_user.update_attribute(:otp_required_for_login, true)
- visit profile_account_path
- manage_two_factor_authentication
- register_u2f_device(name: 'My other device')
- gitlab_sign_out
-
- # Try authenticating user with the old U2F device
- gitlab_sign_in(current_user)
- @u2f_device.respond_to_u2f_authentication
- expect(page).to have_content('Authentication via U2F device failed')
- end
- end
-
- describe "and also the current user" do
- it "allows logging in with that particular device" do
- # U2f specs will be removed after WebAuthn migration completed
- pending('FakeU2fDevice has static key handle, '\
- 'leading to duplicate credential_xid for WebAuthn during migration, '\
- 'resulting in unique constraint violation')
-
- # Register current user with the same U2F device
- current_user = gitlab_sign_in(:user)
- current_user.update_attribute(:otp_required_for_login, true)
- visit profile_account_path
- manage_two_factor_authentication
- register_u2f_device(@u2f_device)
- gitlab_sign_out
-
- # Try authenticating user with the same U2F device
- gitlab_sign_in(current_user)
- @u2f_device.respond_to_u2f_authentication
-
- expect(page).to have_css('.sign-out-link', visible: false)
- end
- end
- end
-
- describe "when a given U2F device has not been registered" do
- it "does not allow logging in with that particular device" do
- unregistered_device = FakeU2fDevice.new(page, 'My device')
- gitlab_sign_in(user)
- unregistered_device.respond_to_u2f_authentication
-
- expect(page).to have_content('Authentication via U2F device failed')
- end
- end
-
- describe "when more than one device has been registered by the same user" do
- it "allows logging in with either device" do
- # Register first device
- user = gitlab_sign_in(:user)
- user.update_attribute(:otp_required_for_login, true)
- visit profile_two_factor_auth_path
- expect(page).to have_content("Your device needs to be set up.")
- first_device = register_u2f_device
-
- # Register second device
- visit profile_two_factor_auth_path
- expect(page).to have_content("Your device needs to be set up.")
- second_device = register_u2f_device(name: 'My other device')
- gitlab_sign_out
-
- # Authenticate as both devices
- [first_device, second_device].each do |device|
- gitlab_sign_in(user)
- device.respond_to_u2f_authentication
-
- expect(page).to have_css('.sign-out-link', visible: false)
-
- gitlab_sign_out
- end
- end
- end
- end
-end
diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb
index 23fa6261bd5..28699bc2c24 100644
--- a/spec/features/unsubscribe_links_spec.rb
+++ b/spec/features/unsubscribe_links_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Unsubscribe links', :sidekiq_inline, feature_category: :not_owned do
+RSpec.describe 'Unsubscribe links', :sidekiq_inline, feature_category: :shared do
include Warden::Test::Helpers
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/features/user_can_display_performance_bar_spec.rb b/spec/features/user_can_display_performance_bar_spec.rb
index 4f6ce6e8f71..caf13c4111b 100644
--- a/spec/features/user_can_display_performance_bar_spec.rb
+++ b/spec/features/user_can_display_performance_bar_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'User can display performance bar', :js, feature_category: :continuous_verification do
+RSpec.describe 'User can display performance bar', :js, feature_category: :application_performance do
shared_examples 'performance bar cannot be displayed' do
it 'does not show the performance bar by default' do
expect(page).not_to have_css('#js-peek')
diff --git a/spec/features/user_sees_revert_modal_spec.rb b/spec/features/user_sees_revert_modal_spec.rb
index ae3158e4270..aca32d26bdb 100644
--- a/spec/features/user_sees_revert_modal_spec.rb
+++ b/spec/features/user_sees_revert_modal_spec.rb
@@ -19,9 +19,12 @@ feature_category: :code_review_workflow do
end
before do
+ stub_feature_flags(unbatch_graphql_queries: false)
sign_in(user)
visit(project_merge_request_path(project, merge_request))
- click_button('Merge')
+ page.within('.mr-state-widget') do
+ click_button 'Merge'
+ end
wait_for_requests
end
diff --git a/spec/features/user_sorts_things_spec.rb b/spec/features/user_sorts_things_spec.rb
index b45de88832c..bc377fb1f8f 100644
--- a/spec/features/user_sorts_things_spec.rb
+++ b/spec/features/user_sorts_things_spec.rb
@@ -7,7 +7,7 @@ require "spec_helper"
# The `it`s are named here by convention `starting point -> some pages -> final point`.
# All those specs are moved out to this spec intentionally to keep them all in one place.
RSpec.describe "User sorts things", :js do
- include Spec::Support::Helpers::Features::SortingHelpers
+ include Features::SortingHelpers
include DashboardHelper
let_it_be(:project) { create(:project_empty_repo, :public) }
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 5e683befeec..5529f0fa49e 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -109,6 +109,10 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'within the grace period' do
+ before do
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
+ end
+
it 'allows to login' do
expect(authentication_metrics).to increment(:user_authenticated_counter)
@@ -137,11 +141,9 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'when resending the confirmation email' do
- it 'redirects to the "almost there" page' do
- stub_feature_flags(soft_email_confirmation: false)
-
- user = create(:user)
+ let_it_be(:user) { create(:user) }
+ it 'redirects to the "almost there" page' do
visit new_user_confirmation_path
fill_in 'user_email', with: user.email
click_button 'Resend'
@@ -206,18 +208,96 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
describe 'with two-factor authentication', :js do
- def enter_code(code)
+ def enter_code(code, only_two_factor_webauthn_enabled: false)
+ click_on("Sign in via 2FA code") if only_two_factor_webauthn_enabled
+
fill_in 'user_otp_attempt', with: code
click_button 'Verify code'
end
- context 'with valid username/password' do
+ shared_examples_for 'can login with recovery codes' do |only_two_factor_webauthn_enabled: false|
+ context 'using backup code' do
+ let(:codes) { user.generate_otp_backup_codes! }
+
+ before do
+ expect(codes.size).to eq 10
+
+ # Ensure the generated codes get saved
+ user.save!(touch: false)
+ end
+
+ context 'with valid code' do
+ it 'allows login' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+ .and increment(:user_two_factor_authenticated_counter)
+
+ enter_code(codes.sample, only_two_factor_webauthn_enabled: only_two_factor_webauthn_enabled)
+
+ expect(page).to have_current_path root_path, ignore_query: true
+ end
+
+ it 'invalidates the used code' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+ .and increment(:user_two_factor_authenticated_counter)
+
+ expect { enter_code(codes.sample, only_two_factor_webauthn_enabled: only_two_factor_webauthn_enabled) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+ end
+
+ it 'invalidates backup codes twice in a row' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter).twice
+ .and increment(:user_two_factor_authenticated_counter).twice
+ .and increment(:user_session_destroyed_counter)
+
+ random_code = codes.delete(codes.sample)
+ expect { enter_code(random_code, only_two_factor_webauthn_enabled: only_two_factor_webauthn_enabled) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+
+ gitlab_sign_out
+ gitlab_sign_in(user)
+
+ expect { enter_code(codes.sample, only_two_factor_webauthn_enabled: only_two_factor_webauthn_enabled) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+ end
+
+ it 'triggers ActiveSession.cleanup for the user' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+ .and increment(:user_two_factor_authenticated_counter)
+ expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original
+
+ enter_code(codes.sample, only_two_factor_webauthn_enabled: only_two_factor_webauthn_enabled)
+ end
+ end
+
+ context 'with invalid code' do
+ it 'blocks login' do
+ # TODO, invalid two factor authentication does not increment
+ # metrics / counters, see gitlab-org/gitlab-ce#49785
+
+ code = codes.sample
+ expect(user.invalidate_otp_backup_code!(code)).to eq true
+
+ user.save!(touch: false)
+ expect(user.reload.otp_backup_codes.size).to eq 9
+
+ enter_code(code, only_two_factor_webauthn_enabled: only_two_factor_webauthn_enabled)
+ expect(page).to have_content('Invalid two-factor code.')
+ end
+ end
+ end
+ end
+
+ # Freeze time to prevent failures when time between code being entered and
+ # validated greater than otp_allowed_drift
+ context 'with valid username/password', :freeze_time do
let(:user) { create(:user, :two_factor) }
before do
gitlab_sign_in(user, remember: true)
-
- expect(page).to have_content('Two-factor authentication code')
end
it 'does not show a "You are already signed in." error message' do
@@ -290,78 +370,16 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
end
- context 'using backup code' do
- let(:codes) { user.generate_otp_backup_codes! }
-
- before do
- expect(codes.size).to eq 10
-
- # Ensure the generated codes get saved
- user.save!(touch: false)
- end
-
- context 'with valid code' do
- it 'allows login' do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter)
- .and increment(:user_two_factor_authenticated_counter)
-
- enter_code(codes.sample)
-
- expect(page).to have_current_path root_path, ignore_query: true
- end
-
- it 'invalidates the used code' do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter)
- .and increment(:user_two_factor_authenticated_counter)
-
- expect { enter_code(codes.sample) }
- .to change { user.reload.otp_backup_codes.size }.by(-1)
- end
-
- it 'invalidates backup codes twice in a row' do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter).twice
- .and increment(:user_two_factor_authenticated_counter).twice
- .and increment(:user_session_destroyed_counter)
-
- random_code = codes.delete(codes.sample)
- expect { enter_code(random_code) }
- .to change { user.reload.otp_backup_codes.size }.by(-1)
-
- gitlab_sign_out
- gitlab_sign_in(user)
-
- expect { enter_code(codes.sample) }
- .to change { user.reload.otp_backup_codes.size }.by(-1)
- end
-
- it 'triggers ActiveSession.cleanup for the user' do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter)
- .and increment(:user_two_factor_authenticated_counter)
- expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original
-
- enter_code(codes.sample)
- end
- end
+ context 'when user with TOTP enabled' do
+ let(:user) { create(:user, :two_factor) }
- context 'with invalid code' do
- it 'blocks login' do
- # TODO, invalid two factor authentication does not increment
- # metrics / counters, see gitlab-org/gitlab-ce#49785
-
- code = codes.sample
- expect(user.invalidate_otp_backup_code!(code)).to eq true
+ include_examples 'can login with recovery codes'
+ end
- user.save!(touch: false)
- expect(user.reload.otp_backup_codes.size).to eq 9
+ context 'when user with only Webauthn enabled' do
+ let(:user) { create(:user, :two_factor_via_webauthn, registrations_count: 1) }
- enter_code(code)
- expect(page).to have_content('Invalid two-factor code.')
- end
- end
+ include_examples 'can login with recovery codes', only_two_factor_webauthn_enabled: true
end
end
@@ -376,11 +394,29 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
providers: [mock_saml_config_with_upstream_two_factor_authn_contexts])
end
+ it 'displays the remember me checkbox' do
+ visit new_user_session_path
+
+ expect(page).to have_field('remember_me_omniauth')
+ end
+
+ context 'when remember me is not enabled' do
+ before do
+ stub_application_setting(remember_me_enabled: false)
+ end
+
+ it 'does not display the remember me checkbox' do
+ visit new_user_session_path
+
+ expect(page).not_to have_field('remember_me_omniauth')
+ end
+ end
+
context 'when authn_context is worth two factors' do
let(:mock_saml_response) do
File.read('spec/fixtures/authentication/saml_response.xml')
- .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
- 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS')
+ .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
+ 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS')
end
it 'signs user in without prompting for second factor' do
@@ -394,12 +430,14 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
sign_in_using_saml!
expect_single_session_with_authenticated_ttl
- expect(page).not_to have_content('Two-Factor Authentication')
+ expect(page).not_to have_content(_('Enter verification code'))
expect(page).to have_current_path root_path, ignore_query: true
end
end
- context 'when two factor authentication is required' do
+ # Freeze time to prevent failures when time between code being entered and
+ # validated greater than otp_allowed_drift
+ context 'when two factor authentication is required', :freeze_time do
it 'shows 2FA prompt after OAuth login' do
expect(authentication_metrics)
.to increment(:user_authenticated_counter)
@@ -408,7 +446,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
sign_in_using_saml!
- expect(page).to have_content('Two-factor authentication code')
+ expect(page).to have_content('Enter verification code')
enter_code(user.current_otp)
@@ -424,6 +462,24 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
describe 'without two-factor authentication' do
+ it 'displays the remember me checkbox' do
+ visit new_user_session_path
+
+ expect(page).to have_content(_('Remember me'))
+ end
+
+ context 'when remember me is not enabled' do
+ before do
+ stub_application_setting(remember_me_enabled: false)
+ end
+
+ it 'does not display the remember me checkbox' do
+ visit new_user_session_path
+
+ expect(page).not_to have_content(_('Remember me'))
+ end
+ end
+
context 'with correct username and password' do
let(:user) { create(:user) }
@@ -457,6 +513,43 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
gitlab_sign_in(user)
end
+ context 'when the session expires' do
+ it 'signs the user out' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+
+ gitlab_sign_in(user)
+ expire_session
+ visit root_path
+
+ expect(page).to have_current_path new_user_session_path
+ end
+
+ it 'extends the session when using remember me' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter).twice
+
+ gitlab_sign_in(user, remember: true)
+ expire_session
+ visit root_path
+
+ expect(page).to have_current_path root_path
+ end
+
+ it 'does not extend the session when remember me is not enabled' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+
+ gitlab_sign_in(user, remember: true)
+ expire_session
+ stub_application_setting(remember_me_enabled: false)
+
+ visit root_path
+
+ expect(page).to have_current_path new_user_session_path
+ end
+ end
+
context 'when the users password is expired' do
before do
user.update!(password_expires_at: Time.zone.parse('2018-05-08 11:29:46 UTC'))
@@ -591,23 +684,21 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'within the grace period' do
- it 'redirects to two-factor configuration page' do
- freeze_time do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter)
-
- gitlab_sign_in(user)
-
- expect(page).to have_current_path profile_two_factor_auth_path, ignore_query: true
- expect(page).to have_content(
- 'The group settings for Group 1 and Group 2 require you to enable '\
- 'Two-Factor Authentication for your account. '\
- 'You can leave Group 1 and leave Group 2. '\
- 'You need to do this '\
- 'before '\
- "#{(Time.zone.now + 2.days).strftime("%a, %d %b %Y %H:%M:%S %z")}"
- )
- end
+ it 'redirects to two-factor configuration page', :freeze_time do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+
+ gitlab_sign_in(user)
+
+ expect(page).to have_current_path profile_two_factor_auth_path, ignore_query: true
+ expect(page).to have_content(
+ 'The group settings for Group 1 and Group 2 require you to enable '\
+ 'Two-Factor Authentication for your account. '\
+ 'You can leave Group 1 and leave Group 2. '\
+ 'You need to do this '\
+ 'before '\
+ "#{(Time.zone.now + 2.days).strftime("%a, %d %b %Y %H:%M:%S %z")}"
+ )
end
it 'allows skipping two-factor configuration', :js do
@@ -732,17 +823,37 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
allow(instance).to receive(:"user_#{provider}_omniauth_callback_path")
.and_return("/users/auth/#{provider}/callback")
end
-
- visit new_user_session_path
end
it 'correctly renders tabs and panes' do
+ visit new_user_session_path
+
ensure_tab_pane_correctness(['Main LDAP', 'Standard'])
end
it 'renders link to sign up path' do
+ visit new_user_session_path
+
expect(page.body).to have_link('Register now', href: new_user_registration_path)
end
+
+ it 'displays the remember me checkbox' do
+ visit new_user_session_path
+
+ ensure_remember_me_in_tab(ldap_server_config['label'])
+ end
+
+ context 'when remember me is not enabled' do
+ before do
+ stub_application_setting(remember_me_enabled: false)
+ end
+
+ it 'does not display the remember me checkbox' do
+ visit new_user_session_path
+
+ ensure_remember_me_not_in_tab(ldap_server_config['label'])
+ end
+ end
end
context 'when crowd is enabled' do
@@ -757,13 +868,31 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
allow(instance).to receive(:user_crowd_omniauth_authorize_path)
.and_return("/users/auth/crowd/callback")
end
-
- visit new_user_session_path
end
it 'correctly renders tabs and panes' do
+ visit new_user_session_path
+
ensure_tab_pane_correctness(%w(Crowd Standard))
end
+
+ it 'displays the remember me checkbox' do
+ visit new_user_session_path
+
+ ensure_remember_me_in_tab(_('Crowd'))
+ end
+
+ context 'when remember me is not enabled' do
+ before do
+ stub_application_setting(remember_me_enabled: false)
+ end
+
+ it 'does not display the remember me checkbox' do
+ visit new_user_session_path
+
+ ensure_remember_me_not_in_tab(_('Crowd'))
+ end
+ end
end
end
@@ -928,22 +1057,22 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
it 'asks the user to accept the terms before setting an email',
quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/388049', type: :flaky } do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter)
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
- gitlab_sign_in_via('saml', user, 'my-uid')
+ gitlab_sign_in_via('saml', user, 'my-uid')
- expect_to_be_on_terms_page
- click_button 'Accept terms'
+ expect_to_be_on_terms_page
+ click_button 'Accept terms'
- expect(page).to have_current_path(profile_path, ignore_query: true)
+ expect(page).to have_current_path(profile_path, ignore_query: true)
- fill_in 'Email', with: 'hello@world.com'
+ fill_in 'Email', with: 'hello@world.com'
- click_button 'Update profile settings'
+ click_button 'Update profile settings'
- expect(page).to have_content('Profile was successfully updated')
- end
+ expect(page).to have_content('Profile was successfully updated')
+ end
end
end
@@ -954,8 +1083,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
let(:alert_message) { "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select Resend confirmation email" }
before do
- stub_application_setting_enum('email_confirmation_setting', 'hard')
- stub_feature_flags(soft_email_confirmation: true)
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
stub_feature_flags(identity_verification: false)
allow(User).to receive(:allow_unconfirmed_access_for).and_return grace_period
end
diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb
index 88b2d918976..9c4a1b36ecc 100644
--- a/spec/features/users/show_spec.rb
+++ b/spec/features/users/show_spec.rb
@@ -15,6 +15,14 @@ RSpec.describe 'User page', feature_category: :user_profile do
expect(page).to have_content("User ID: #{user.id}")
end
+ it 'shows name on breadcrumbs' do
+ subject
+
+ page.within '.breadcrumbs' do
+ expect(page).to have_content(user.name)
+ end
+ end
+
context 'with public profile' do
context 'with `profile_tabs_vue` feature flag disabled' do
before do
@@ -149,7 +157,7 @@ RSpec.describe 'User page', feature_category: :user_profile do
end
end
- context 'follow/unfollow and followers/following' do
+ context 'follow/unfollow and followers/following', :js do
let_it_be(:followee) { create(:user) }
let_it_be(:follower) { create(:user) }
@@ -159,21 +167,33 @@ RSpec.describe 'User page', feature_category: :user_profile do
expect(page).not_to have_button(text: 'Follow', class: 'gl-button')
end
- it 'shows 0 followers and 0 following' do
- subject
+ shared_examples 'follower tabs with count badges' do
+ it 'shows 0 followers and 0 following' do
+ subject
+
+ expect(page).to have_content('Followers 0')
+ expect(page).to have_content('Following 0')
+ end
- expect(page).to have_content('0 followers')
- expect(page).to have_content('0 following')
+ it 'shows 1 followers and 1 following' do
+ follower.follow(user)
+ user.follow(followee)
+
+ subject
+
+ expect(page).to have_content('Followers 1')
+ expect(page).to have_content('Following 1')
+ end
end
- it 'shows 1 followers and 1 following' do
- follower.follow(user)
- user.follow(followee)
+ it_behaves_like 'follower tabs with count badges'
- subject
+ context 'with profile_tabs_vue feature flag disabled' do
+ before_all do
+ stub_feature_flags(profile_tabs_vue: false)
+ end
- expect(page).to have_content('1 follower')
- expect(page).to have_content('1 following')
+ it_behaves_like 'follower tabs with count badges'
end
it 'does show button to follow' do
@@ -526,4 +546,36 @@ RSpec.describe 'User page', feature_category: :user_profile do
end
end
end
+
+ context 'achievements' do
+ it 'renders the user achievements mount point' do
+ subject
+
+ expect(page).to have_selector('#js-user-achievements')
+ end
+
+ context 'when the user has chosen not to display achievements' do
+ let(:user) { create(:user) }
+
+ before do
+ user.update!(achievements_enabled: false)
+ end
+
+ it 'does not render the user achievements mount point' do
+ subject
+
+ expect(page).not_to have_selector('#js-user-achievements')
+ end
+ end
+
+ context 'when the profile is private' do
+ let(:user) { create(:user, private_profile: true) }
+
+ it 'does not render the user achievements mount point' do
+ subject
+
+ expect(page).not_to have_selector('#js-user-achievements')
+ end
+ end
+ end
end
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index 11ff318c346..d65eea3671c 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -10,7 +10,7 @@ RSpec.shared_examples 'Signup name validation' do |field, max_length, label|
visit new_user_registration_path
end
- describe "#{field} validation", :js do
+ describe "#{field} validation" do
it "does not show an error border if the user's fullname length is not longer than #{max_length} characters" do
fill_in field, with: 'u' * max_length
@@ -44,7 +44,7 @@ RSpec.shared_examples 'Signup name validation' do |field, max_length, label|
end
end
-RSpec.describe 'Signup', feature_category: :user_profile do
+RSpec.describe 'Signup', :js, feature_category: :user_profile do
include TermsHelper
let(:new_user) { build_stubbed(:user) }
@@ -71,7 +71,7 @@ RSpec.describe 'Signup', feature_category: :user_profile do
stub_application_setting(require_admin_approval_after_user_signup: false)
end
- describe 'username validation', :js do
+ describe 'username validation' do
before do
visit new_user_registration_path
end
@@ -200,9 +200,8 @@ RSpec.describe 'Signup', feature_category: :user_profile do
stub_application_setting_enum('email_confirmation_setting', 'hard')
end
- context 'when soft email confirmation is not enabled' do
+ context 'when email confirmation setting is not `soft`' do
before do
- stub_feature_flags(soft_email_confirmation: false)
stub_feature_flags(identity_verification: false)
end
@@ -221,9 +220,9 @@ RSpec.describe 'Signup', feature_category: :user_profile do
end
end
- context 'when soft email confirmation is enabled' do
+ context 'when email confirmation setting is `soft`' do
before do
- stub_feature_flags(soft_email_confirmation: true)
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
end
it 'creates the user account and sends a confirmation email' do
@@ -338,6 +337,7 @@ RSpec.describe 'Signup', feature_category: :user_profile do
expect { click_button 'Register' }.not_to change { User.count }
expect(page).to have_content(_('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'))
+ expect(page).to have_content("Minimum length is #{Gitlab::CurrentSettings.minimum_password_length} characters")
end
end
@@ -357,6 +357,8 @@ RSpec.describe 'Signup', feature_category: :user_profile do
visit new_user_registration_path
fill_in_signup_form
+ wait_for_all_requests
+
click_button 'Register'
visit new_project_path
@@ -384,7 +386,7 @@ RSpec.describe 'Signup', feature_category: :user_profile do
expect(page.body).not_to match(/#{new_user.password}/)
end
- context 'with invalid email', :saas, :js do
+ context 'with invalid email' do
it_behaves_like 'user email validation' do
let(:path) { new_user_registration_path }
end
diff --git a/spec/features/webauthn_spec.rb b/spec/features/webauthn_spec.rb
index 859793d1353..5c42facfa8b 100644
--- a/spec/features/webauthn_spec.rb
+++ b/spec/features/webauthn_spec.rb
@@ -2,14 +2,121 @@
require 'spec_helper'
-RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_category: :authentication_and_authorization do
- include Spec::Support::Helpers::Features::TwoFactorHelpers
+RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_category: :system_access do
+ include Features::TwoFactorHelpers
let(:app_id) { "http://#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}" }
before do
WebAuthn.configuration.origin = app_id
end
+ context 'when the webauth_without_totp feature flag is enabled' do
+ # Some of the shared tests don't apply. After removing U2F support and the `webauthn_without_totp` feature flag, refactor the shared tests.
+ # TODO: it_behaves_like 'hardware device for 2fa', 'WebAuthn'
+
+ describe 'registration' do
+ let(:user) { create(:user) }
+
+ before do
+ gitlab_sign_in(user)
+ end
+
+ it 'shows an error when using a wrong password' do
+ visit profile_account_path
+
+ # First device
+ enable_two_factor_authentication
+ webauthn_device_registration(password: 'fake')
+ expect(page).to have_content(_('You must provide a valid current password.'))
+ end
+
+ it 'allows registering more than one device' do
+ visit profile_account_path
+
+ # First device
+ enable_two_factor_authentication
+ first_device = webauthn_device_registration(password: user.password)
+ expect(page).to have_content('Your WebAuthn device was registered!')
+ copy_recovery_codes
+ manage_two_factor_authentication
+
+ # Second device
+ second_device = webauthn_device_registration(name: 'My other device', password: user.password)
+ expect(page).to have_content('Your WebAuthn device was registered!')
+
+ expect(page).to have_content(first_device.name)
+ expect(page).to have_content(second_device.name)
+ expect(WebauthnRegistration.count).to eq(2)
+ end
+
+ it 'allows the same device to be registered for multiple users' do
+ # First user
+ visit profile_account_path
+ enable_two_factor_authentication
+ webauthn_device = webauthn_device_registration(password: user.password)
+ expect(page).to have_content('Your WebAuthn device was registered!')
+ gitlab_sign_out
+
+ # Second user
+ user = gitlab_sign_in(:user)
+ visit profile_account_path
+ enable_two_factor_authentication
+ webauthn_device_registration(webauthn_device: webauthn_device, name: 'My other device', password: user.password)
+ expect(page).to have_content('Your WebAuthn device was registered!')
+
+ expect(WebauthnRegistration.count).to eq(2)
+ end
+
+ context 'when there are form errors' do
+ let(:mock_register_js) do
+ <<~JS
+ const mockResponse = {
+ type: 'public-key',
+ id: '',
+ rawId: '',
+ response: {
+ clientDataJSON: '',
+ attestationObject: '',
+ },
+ getClientExtensionResults: () => {},
+ };
+ navigator.credentials.create = () => Promise.resolve(mockResponse);
+ JS
+ end
+
+ it "doesn't register the device if there are errors" do
+ visit profile_account_path
+ enable_two_factor_authentication
+
+ # Have the "webauthn device" respond with bad data
+ page.execute_script(mock_register_js)
+ click_on _('Set up new device')
+ webauthn_fill_form_and_submit(password: user.password)
+ expect(page).to have_content(_('Your WebAuthn device did not send a valid JSON response.'))
+
+ expect(WebauthnRegistration.count).to eq(0)
+ end
+
+ it 'allows retrying registration' do
+ visit profile_account_path
+ enable_two_factor_authentication
+
+ # Failed registration
+ page.execute_script(mock_register_js)
+ click_on _('Set up new device')
+ webauthn_fill_form_and_submit(password: user.password)
+ expect(page).to have_content(_('Your WebAuthn device did not send a valid JSON response.'))
+
+ # Successful registration
+ webauthn_device_registration(password: user.password)
+
+ expect(page).to have_content('Your WebAuthn device was registered!')
+ expect(WebauthnRegistration.count).to eq(1)
+ end
+ end
+ end
+ end
+
context 'when the webauth_without_totp feature flag is disabled' do
before do
stub_feature_flags(webauthn_without_totp: false)
@@ -114,99 +221,99 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
end
end
end
+ end
- describe 'authentication' do
- let(:otp_required_for_login) { true }
- let(:user) { create(:user, webauthn_xid: WebAuthn.generate_user_id, otp_required_for_login: otp_required_for_login) }
- let!(:webauthn_device) do
- add_webauthn_device(app_id, user)
- end
+ describe 'authentication' do
+ let(:otp_required_for_login) { true }
+ let(:user) { create(:user, webauthn_xid: WebAuthn.generate_user_id, otp_required_for_login: otp_required_for_login) }
+ let!(:webauthn_device) do
+ add_webauthn_device(app_id, user)
+ end
- describe 'when 2FA via OTP is disabled' do
- let(:otp_required_for_login) { false }
+ describe 'when 2FA via OTP is disabled' do
+ let(:otp_required_for_login) { false }
- it 'allows logging in with the WebAuthn device' do
- gitlab_sign_in(user)
+ it 'allows logging in with the WebAuthn device' do
+ gitlab_sign_in(user)
- webauthn_device.respond_to_webauthn_authentication
+ webauthn_device.respond_to_webauthn_authentication
- expect(page).to have_css('.sign-out-link', visible: false)
- end
+ expect(page).to have_css('.sign-out-link', visible: false)
end
+ end
- describe 'when 2FA via OTP is enabled' do
- it 'allows logging in with the WebAuthn device' do
- gitlab_sign_in(user)
+ describe 'when 2FA via OTP is enabled' do
+ it 'allows logging in with the WebAuthn device' do
+ gitlab_sign_in(user)
- webauthn_device.respond_to_webauthn_authentication
+ webauthn_device.respond_to_webauthn_authentication
- expect(page).to have_css('.sign-out-link', visible: false)
- end
+ expect(page).to have_css('.sign-out-link', visible: false)
end
+ end
- describe 'when a given WebAuthn device has already been registered by another user' do
- describe 'but not the current user' do
- let(:other_user) { create(:user, webauthn_xid: WebAuthn.generate_user_id, otp_required_for_login: otp_required_for_login) }
+ describe 'when a given WebAuthn device has already been registered by another user' do
+ describe 'but not the current user' do
+ let(:other_user) { create(:user, webauthn_xid: WebAuthn.generate_user_id, otp_required_for_login: otp_required_for_login) }
- it 'does not allow logging in with that particular device' do
- # Register other user with a different WebAuthn device
- other_device = add_webauthn_device(app_id, other_user)
+ it 'does not allow logging in with that particular device' do
+ # Register other user with a different WebAuthn device
+ other_device = add_webauthn_device(app_id, other_user)
- # Try authenticating user with the old WebAuthn device
- gitlab_sign_in(user)
- other_device.respond_to_webauthn_authentication
- expect(page).to have_content('Authentication via WebAuthn device failed')
- end
+ # Try authenticating user with the old WebAuthn device
+ gitlab_sign_in(user)
+ other_device.respond_to_webauthn_authentication
+ expect(page).to have_content('Authentication via WebAuthn device failed')
end
+ end
+
+ describe "and also the current user" do
+ # TODO Uncomment once WebAuthn::FakeClient supports passing credential options
+ # (especially allow_credentials, as this is needed to specify which credential the
+ # fake client should use. Currently, the first credential is always used).
+ # There is an issue open for this: https://github.com/cedarcode/webauthn-ruby/issues/259
+ it "allows logging in with that particular device" do
+ pending("support for passing credential options in FakeClient")
+ # Register current user with the same WebAuthn device
+ current_user = gitlab_sign_in(:user)
+ visit profile_account_path
+ manage_two_factor_authentication
+ register_webauthn_device(webauthn_device)
+ gitlab_sign_out
+
+ # Try authenticating user with the same WebAuthn device
+ gitlab_sign_in(current_user)
+ webauthn_device.respond_to_webauthn_authentication
- describe "and also the current user" do
- # TODO Uncomment once WebAuthn::FakeClient supports passing credential options
- # (especially allow_credentials, as this is needed to specify which credential the
- # fake client should use. Currently, the first credential is always used).
- # There is an issue open for this: https://github.com/cedarcode/webauthn-ruby/issues/259
- it "allows logging in with that particular device" do
- pending("support for passing credential options in FakeClient")
- # Register current user with the same WebAuthn device
- current_user = gitlab_sign_in(:user)
- visit profile_account_path
- manage_two_factor_authentication
- register_webauthn_device(webauthn_device)
- gitlab_sign_out
-
- # Try authenticating user with the same WebAuthn device
- gitlab_sign_in(current_user)
- webauthn_device.respond_to_webauthn_authentication
-
- expect(page).to have_css('.sign-out-link', visible: false)
- end
+ expect(page).to have_css('.sign-out-link', visible: false)
end
end
+ end
- describe 'when a given WebAuthn device has not been registered' do
- it 'does not allow logging in with that particular device' do
- unregistered_device = FakeWebauthnDevice.new(page, 'My device')
- gitlab_sign_in(user)
- unregistered_device.respond_to_webauthn_authentication
+ describe 'when a given WebAuthn device has not been registered' do
+ it 'does not allow logging in with that particular device' do
+ unregistered_device = FakeWebauthnDevice.new(page, 'My device')
+ gitlab_sign_in(user)
+ unregistered_device.respond_to_webauthn_authentication
- expect(page).to have_content('Authentication via WebAuthn device failed')
- end
+ expect(page).to have_content('Authentication via WebAuthn device failed')
end
+ end
- describe 'when more than one device has been registered by the same user' do
- it 'allows logging in with either device' do
- first_device = add_webauthn_device(app_id, user)
- second_device = add_webauthn_device(app_id, user)
+ describe 'when more than one device has been registered by the same user' do
+ it 'allows logging in with either device' do
+ first_device = add_webauthn_device(app_id, user)
+ second_device = add_webauthn_device(app_id, user)
- # Authenticate as both devices
- [first_device, second_device].each do |device|
- gitlab_sign_in(user)
- # register_webauthn_device(device)
- device.respond_to_webauthn_authentication
+ # Authenticate as both devices
+ [first_device, second_device].each do |device|
+ gitlab_sign_in(user)
+ # register_webauthn_device(device)
+ device.respond_to_webauthn_authentication
- expect(page).to have_css('.sign-out-link', visible: false)
+ expect(page).to have_css('.sign-out-link', visible: false)
- gitlab_sign_out
- end
+ gitlab_sign_out
end
end
end
diff --git a/spec/features/whats_new_spec.rb b/spec/features/whats_new_spec.rb
index 6b19ab28b44..3668d90f2e9 100644
--- a/spec/features/whats_new_spec.rb
+++ b/spec/features/whats_new_spec.rb
@@ -2,13 +2,11 @@
require "spec_helper"
-RSpec.describe "renders a `whats new` dropdown item", feature_category: :not_owned do
+RSpec.describe "renders a `whats new` dropdown item", feature_category: :onboarding do
let_it_be(:user) { create(:user) }
context 'when not logged in' do
- it 'and on .com it renders' do
- allow(Gitlab).to receive(:com?).and_return(true)
-
+ it 'and on SaaS it renders', :saas do
visit user_path(user)
page.within '.header-help' do
diff --git a/spec/features/work_items/work_item_spec.rb b/spec/features/work_items/work_item_spec.rb
deleted file mode 100644
index 3c71a27ff82..00000000000
--- a/spec/features/work_items/work_item_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Work item', :js, feature_category: :team_planning do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:user) { create(:user) }
- let_it_be(:work_item) { create(:work_item, project: project) }
-
- context 'for signed in user' do
- before do
- project.add_developer(user)
-
- sign_in(user)
-
- visit project_work_items_path(project, work_items_path: work_item.id)
- end
-
- it_behaves_like 'work items status'
- it_behaves_like 'work items assignees'
- it_behaves_like 'work items labels'
- it_behaves_like 'work items comments'
- it_behaves_like 'work items description'
- end
-
- context 'for signed in owner' do
- before do
- project.add_owner(user)
-
- sign_in(user)
-
- visit project_work_items_path(project, work_items_path: work_item.id)
- end
-
- it_behaves_like 'work items invite members'
- end
-end