summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-24 09:08:32 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-24 09:08:32 +0000
commitd6348d22dd0c78e11d56855cb5f1fb71be437901 (patch)
tree0e64970b1491cee49b7258cb44c11ac079d48ebe
parentfa7ac2663b53f61551b9db51f16d55fa4e5b74c3 (diff)
downloadgitlab-ce-d6348d22dd0c78e11d56855cb5f1fb71be437901.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/design_management/index.js3
-rw-r--r--app/assets/javascripts/design_management_new/components/app.vue3
-rw-r--r--app/assets/javascripts/design_management_new/components/delete_button.vue64
-rw-r--r--app/assets/javascripts/design_management_new/components/design_destroyer.vue66
-rw-r--r--app/assets/javascripts/design_management_new/components/design_note_pin.vue61
-rw-r--r--app/assets/javascripts/design_management_new/components/design_notes/design_discussion.vue297
-rw-r--r--app/assets/javascripts/design_management_new/components/design_notes/design_note.vue156
-rw-r--r--app/assets/javascripts/design_management_new/components/design_notes/design_reply_form.vue141
-rw-r--r--app/assets/javascripts/design_management_new/components/design_notes/toggle_replies_widget.vue70
-rw-r--r--app/assets/javascripts/design_management_new/components/design_overlay.vue287
-rw-r--r--app/assets/javascripts/design_management_new/components/design_presentation.vue322
-rw-r--r--app/assets/javascripts/design_management_new/components/design_scaler.vue65
-rw-r--r--app/assets/javascripts/design_management_new/components/design_sidebar.vue178
-rw-r--r--app/assets/javascripts/design_management_new/components/image.vue110
-rw-r--r--app/assets/javascripts/design_management_new/components/list/item.vue174
-rw-r--r--app/assets/javascripts/design_management_new/components/toolbar/index.vue126
-rw-r--r--app/assets/javascripts/design_management_new/components/toolbar/pagination.vue83
-rw-r--r--app/assets/javascripts/design_management_new/components/toolbar/pagination_button.vue48
-rw-r--r--app/assets/javascripts/design_management_new/components/upload/button.vue58
-rw-r--r--app/assets/javascripts/design_management_new/components/upload/design_dropzone.vue134
-rw-r--r--app/assets/javascripts/design_management_new/components/upload/design_version_dropdown.vue76
-rw-r--r--app/assets/javascripts/design_management_new/constants.js16
-rw-r--r--app/assets/javascripts/design_management_new/graphql.js45
-rw-r--r--app/assets/javascripts/design_management_new/graphql/fragments/design.fragment.graphql24
-rw-r--r--app/assets/javascripts/design_management_new/graphql/fragments/design_list.fragment.graphql8
-rw-r--r--app/assets/javascripts/design_management_new/graphql/fragments/design_note.fragment.graphql29
-rw-r--r--app/assets/javascripts/design_management_new/graphql/fragments/diff_refs.fragment.graphql5
-rw-r--r--app/assets/javascripts/design_management_new/graphql/fragments/discussion_resolved_status.fragment.graphql9
-rw-r--r--app/assets/javascripts/design_management_new/graphql/fragments/note_permissions.fragment.graphql3
-rw-r--r--app/assets/javascripts/design_management_new/graphql/fragments/version.fragment.graphql4
-rw-r--r--app/assets/javascripts/design_management_new/graphql/mutations/create_image_diff_note.mutation.graphql21
-rw-r--r--app/assets/javascripts/design_management_new/graphql/mutations/create_note.mutation.graphql10
-rw-r--r--app/assets/javascripts/design_management_new/graphql/mutations/destroy_design.mutation.graphql10
-rw-r--r--app/assets/javascripts/design_management_new/graphql/mutations/toggle_resolve_discussion.mutation.graphql17
-rw-r--r--app/assets/javascripts/design_management_new/graphql/mutations/update_active_discussion.mutation.graphql3
-rw-r--r--app/assets/javascripts/design_management_new/graphql/mutations/update_image_diff_note.mutation.graphql10
-rw-r--r--app/assets/javascripts/design_management_new/graphql/mutations/update_note.mutation.graphql10
-rw-r--r--app/assets/javascripts/design_management_new/graphql/mutations/upload_design.mutation.graphql21
-rw-r--r--app/assets/javascripts/design_management_new/graphql/queries/active_discussion.query.graphql6
-rw-r--r--app/assets/javascripts/design_management_new/graphql/queries/app_data.query.graphql4
-rw-r--r--app/assets/javascripts/design_management_new/graphql/queries/design_permissions.query.graphql10
-rw-r--r--app/assets/javascripts/design_management_new/graphql/queries/get_design.query.graphql31
-rw-r--r--app/assets/javascripts/design_management_new/graphql/queries/get_design_list.query.graphql26
-rw-r--r--app/assets/javascripts/design_management_new/graphql/typedefs.graphql12
-rw-r--r--app/assets/javascripts/design_management_new/index.js58
-rw-r--r--app/assets/javascripts/design_management_new/mixins/all_designs.js49
-rw-r--r--app/assets/javascripts/design_management_new/mixins/all_versions.js62
-rw-r--r--app/assets/javascripts/design_management_new/pages/design/index.vue378
-rw-r--r--app/assets/javascripts/design_management_new/pages/index.vue323
-rw-r--r--app/assets/javascripts/design_management_new/router/constants.js3
-rw-r--r--app/assets/javascripts/design_management_new/router/index.js35
-rw-r--r--app/assets/javascripts/design_management_new/router/routes.js44
-rw-r--r--app/assets/javascripts/design_management_new/utils/cache_update.js276
-rw-r--r--app/assets/javascripts/design_management_new/utils/design_management_utils.js128
-rw-r--r--app/assets/javascripts/design_management_new/utils/error_messages.js95
-rw-r--r--app/assets/javascripts/design_management_new/utils/tracking.js28
-rw-r--r--app/assets/javascripts/pages/projects/issues/show.js17
-rw-r--r--app/views/projects/issues/_design_management.html.haml5
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml4
-rw-r--r--changelogs/unreleased/223171_allow_erb_extension_for_sse.yml5
-rw-r--r--changelogs/unreleased/223185-add-project-key-to-jira-tracker-data.yml5
-rw-r--r--changelogs/unreleased/upgrade-codequality-template.yml5
-rw-r--r--db/migrate/20200619154527_add_project_key_to_jira_tracker_data.rb12
-rw-r--r--db/migrate/20200619154528_add_text_limit_to_jira_tracker_data_project_key.rb17
-rw-r--r--db/structure.sql6
-rw-r--r--doc/user/discussions/index.md4
-rw-r--r--lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml2
-rw-r--r--lib/gitlab/static_site_editor/config.rb6
-rw-r--r--qa/qa/page/component/issuable/sidebar.rb31
-rw-r--r--qa/qa/resource/issue.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/milestone/assign_project_milestone_spec.rb58
-rw-r--r--spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb4
-rw-r--r--spec/features/projects/issues/design_management/user_paginates_designs_spec.rb1
-rw-r--r--spec/features/projects/issues/design_management/user_permissions_upload_spec.rb1
-rw-r--r--spec/features/projects/issues/design_management/user_uploads_designs_spec.rb1
-rw-r--r--spec/features/projects/issues/design_management/user_views_design_images_spec.rb1
-rw-r--r--spec/features/projects/issues/design_management/user_views_design_spec.rb1
-rw-r--r--spec/features/projects/issues/design_management/user_views_designs_spec.rb1
-rw-r--r--spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb1
-rw-r--r--spec/frontend/design_management_new/components/__snapshots__/design_note_pin_spec.js.snap42
-rw-r--r--spec/frontend/design_management_new/components/__snapshots__/design_presentation_spec.js.snap104
-rw-r--r--spec/frontend/design_management_new/components/__snapshots__/design_scaler_spec.js.snap115
-rw-r--r--spec/frontend/design_management_new/components/__snapshots__/image_spec.js.snap68
-rw-r--r--spec/frontend/design_management_new/components/delete_button_spec.js51
-rw-r--r--spec/frontend/design_management_new/components/design_note_pin_spec.js49
-rw-r--r--spec/frontend/design_management_new/components/design_notes/__snapshots__/design_note_spec.js.snap67
-rw-r--r--spec/frontend/design_management_new/components/design_notes/__snapshots__/design_reply_form_spec.js.snap15
-rw-r--r--spec/frontend/design_management_new/components/design_notes/design_discussion_spec.js318
-rw-r--r--spec/frontend/design_management_new/components/design_notes/design_note_spec.js170
-rw-r--r--spec/frontend/design_management_new/components/design_notes/design_reply_form_spec.js184
-rw-r--r--spec/frontend/design_management_new/components/design_notes/toggle_replies_widget_spec.js98
-rw-r--r--spec/frontend/design_management_new/components/design_overlay_spec.js410
-rw-r--r--spec/frontend/design_management_new/components/design_presentation_spec.js553
-rw-r--r--spec/frontend/design_management_new/components/design_scaler_spec.js67
-rw-r--r--spec/frontend/design_management_new/components/design_sidebar_spec.js236
-rw-r--r--spec/frontend/design_management_new/components/image_spec.js133
-rw-r--r--spec/frontend/design_management_new/components/list/__snapshots__/item_spec.js.snap472
-rw-r--r--spec/frontend/design_management_new/components/list/item_spec.js168
-rw-r--r--spec/frontend/design_management_new/components/toolbar/__snapshots__/index_spec.js.snap61
-rw-r--r--spec/frontend/design_management_new/components/toolbar/__snapshots__/pagination_button_spec.js.snap28
-rw-r--r--spec/frontend/design_management_new/components/toolbar/__snapshots__/pagination_spec.js.snap29
-rw-r--r--spec/frontend/design_management_new/components/toolbar/index_spec.js123
-rw-r--r--spec/frontend/design_management_new/components/toolbar/pagination_button_spec.js61
-rw-r--r--spec/frontend/design_management_new/components/toolbar/pagination_spec.js79
-rw-r--r--spec/frontend/design_management_new/components/upload/__snapshots__/button_spec.js.snap79
-rw-r--r--spec/frontend/design_management_new/components/upload/__snapshots__/design_dropzone_spec.js.snap455
-rw-r--r--spec/frontend/design_management_new/components/upload/__snapshots__/design_version_dropdown_spec.js.snap111
-rw-r--r--spec/frontend/design_management_new/components/upload/button_spec.js59
-rw-r--r--spec/frontend/design_management_new/components/upload/design_dropzone_spec.js132
-rw-r--r--spec/frontend/design_management_new/components/upload/design_version_dropdown_spec.js114
-rw-r--r--spec/frontend/design_management_new/components/upload/mock_data/all_versions.js14
-rw-r--r--spec/frontend/design_management_new/mock_data/all_versions.js8
-rw-r--r--spec/frontend/design_management_new/mock_data/design.js74
-rw-r--r--spec/frontend/design_management_new/mock_data/designs.js17
-rw-r--r--spec/frontend/design_management_new/mock_data/no_designs.js11
-rw-r--r--spec/frontend/design_management_new/mock_data/notes.js46
-rw-r--r--spec/frontend/design_management_new/pages/__snapshots__/index_spec.js.snap263
-rw-r--r--spec/frontend/design_management_new/pages/design/__snapshots__/index_spec.js.snap216
-rw-r--r--spec/frontend/design_management_new/pages/design/index_spec.js291
-rw-r--r--spec/frontend/design_management_new/pages/index_spec.js543
-rw-r--r--spec/frontend/design_management_new/router_spec.js82
-rw-r--r--spec/frontend/design_management_new/utils/cache_update_spec.js44
-rw-r--r--spec/frontend/design_management_new/utils/design_management_utils_spec.js176
-rw-r--r--spec/frontend/design_management_new/utils/error_messages_spec.js62
-rw-r--r--spec/frontend/design_management_new/utils/tracking_spec.js53
-rw-r--r--spec/graphql/mutations/issues/update_spec.rb2
-rw-r--r--spec/graphql/mutations/merge_requests/create_spec.rb2
-rw-r--r--spec/graphql/mutations/merge_requests/set_assignees_spec.rb2
-rw-r--r--spec/graphql/mutations/merge_requests/set_labels_spec.rb2
-rw-r--r--spec/graphql/mutations/merge_requests/set_locked_spec.rb2
-rw-r--r--spec/graphql/mutations/merge_requests/set_milestone_spec.rb2
-rw-r--r--spec/graphql/mutations/merge_requests/set_subscription_spec.rb2
-rw-r--r--spec/graphql/mutations/merge_requests/set_wip_spec.rb2
-rw-r--r--spec/graphql/mutations/todos/mark_all_done_spec.rb2
-rw-r--r--spec/graphql/mutations/todos/mark_done_spec.rb2
-rw-r--r--spec/graphql/mutations/todos/restore_many_spec.rb2
-rw-r--r--spec/graphql/mutations/todos/restore_spec.rb2
-rw-r--r--spec/graphql/resolvers/alert_management/alert_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/alert_management/alert_status_counts_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/base_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/board_lists_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/boards_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/branch_commit_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/commit_pipelines_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb2
-rw-r--r--spec/graphql/resolvers/concerns/resolves_project_spec.rb2
-rw-r--r--spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/design_management/design_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/design_management/designs_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/design_management/version_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/design_management/versions_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/echo_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/environments_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/group_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/last_commit_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/merge_requests_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/metadata_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/metrics/dashboard_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/milestone_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/namespace_projects_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/project_pipelines_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/project_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/projects/services_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/projects/snippets_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/projects_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/release_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/releases_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/snippets_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/todo_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/tree_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/user_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/users/snippets_resolver_spec.rb2
-rw-r--r--spec/graphql/types/alert_management/alert_status_count_type_spec.rb2
-rw-r--r--spec/graphql/types/alert_management/alert_type_spec.rb2
-rw-r--r--spec/graphql/types/alert_management/severity_enum_spec.rb2
-rw-r--r--spec/graphql/types/alert_management/status_enum_spec.rb2
-rw-r--r--spec/graphql/types/award_emojis/award_emoji_type_spec.rb2
-rw-r--r--spec/graphql/types/base_enum_spec.rb2
-rw-r--r--spec/graphql/types/base_field_spec.rb2
-rw-r--r--spec/graphql/types/blob_viewers/type_enum_spec.rb2
-rw-r--r--spec/graphql/types/board_list_type_spec.rb2
-rw-r--r--spec/graphql/types/board_type_spec.rb2
-rw-r--r--spec/graphql/types/branch_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/detailed_status_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/pipeline_type_spec.rb2
-rw-r--r--spec/graphql/types/commit_action_mode_enum_spec.rb2
-rw-r--r--spec/graphql/types/commit_encoding_enum_spec.rb2
-rw-r--r--spec/graphql/types/commit_type_spec.rb2
-rw-r--r--spec/graphql/types/container_expiration_policy_cadence_enum_spec.rb2
-rw-r--r--spec/graphql/types/container_expiration_policy_keep_enum_spec.rb2
-rw-r--r--spec/graphql/types/container_expiration_policy_older_than_enum_spec.rb2
-rw-r--r--spec/graphql/types/container_expiration_policy_type_spec.rb2
-rw-r--r--spec/graphql/types/design_management/design_at_version_type_spec.rb2
-rw-r--r--spec/graphql/types/design_management/design_collection_type_spec.rb2
-rw-r--r--spec/graphql/types/design_management/design_type_spec.rb2
-rw-r--r--spec/graphql/types/design_management/design_version_event_enum_spec.rb2
-rw-r--r--spec/graphql/types/design_management/version_type_spec.rb2
-rw-r--r--spec/graphql/types/design_management_type_spec.rb2
-rw-r--r--spec/graphql/types/diff_refs_type_spec.rb2
-rw-r--r--spec/graphql/types/environment_type_spec.rb2
-rw-r--r--spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb2
-rw-r--r--spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb2
-rw-r--r--spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb2
-rw-r--r--spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb2
-rw-r--r--spec/graphql/types/error_tracking/sentry_error_type_spec.rb2
-rw-r--r--spec/graphql/types/grafana_integration_type_spec.rb2
-rw-r--r--spec/graphql/types/group_type_spec.rb2
-rw-r--r--spec/graphql/types/issuable_sort_enum_spec.rb2
-rw-r--r--spec/graphql/types/issuable_state_enum_spec.rb2
-rw-r--r--spec/graphql/types/issue_sort_enum_spec.rb2
-rw-r--r--spec/graphql/types/issue_state_enum_spec.rb2
-rw-r--r--spec/graphql/types/issue_type_spec.rb2
-rw-r--r--spec/graphql/types/jira_import_type_spec.rb2
-rw-r--r--spec/graphql/types/label_type_spec.rb2
-rw-r--r--spec/graphql/types/merge_request_state_enum_spec.rb2
-rw-r--r--spec/graphql/types/merge_request_type_spec.rb2
-rw-r--r--spec/graphql/types/metadata_type_spec.rb2
-rw-r--r--spec/graphql/types/metrics/dashboard_type_spec.rb2
-rw-r--r--spec/graphql/types/metrics/dashboards/annotation_type_spec.rb2
-rw-r--r--spec/graphql/types/milestone_type_spec.rb2
-rw-r--r--spec/graphql/types/mutation_type_spec.rb2
-rw-r--r--spec/graphql/types/namespace_type_spec.rb2
-rw-r--r--spec/graphql/types/notes/diff_position_type_spec.rb2
-rw-r--r--spec/graphql/types/notes/discussion_type_spec.rb2
-rw-r--r--spec/graphql/types/notes/note_type_spec.rb2
-rw-r--r--spec/graphql/types/notes/noteable_type_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/base_permission_type_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/issue_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/merge_request_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/merge_request_type_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/note_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/project_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/snippet_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/user_spec.rb2
-rw-r--r--spec/graphql/types/project_statistics_type_spec.rb2
-rw-r--r--spec/graphql/types/project_type_spec.rb2
-rw-r--r--spec/graphql/types/projects/base_service_type_spec.rb2
-rw-r--r--spec/graphql/types/projects/jira_project_type_spec.rb2
-rw-r--r--spec/graphql/types/projects/jira_service_type_spec.rb2
-rw-r--r--spec/graphql/types/projects/service_type_spec.rb2
-rw-r--r--spec/graphql/types/projects/services_enum_spec.rb2
-rw-r--r--spec/graphql/types/query_type_spec.rb2
-rw-r--r--spec/graphql/types/release_assets_type_spec.rb2
-rw-r--r--spec/graphql/types/release_links_type_spec.rb2
-rw-r--r--spec/graphql/types/release_source_type_spec.rb2
-rw-r--r--spec/graphql/types/release_type_spec.rb2
-rw-r--r--spec/graphql/types/repository_type_spec.rb2
-rw-r--r--spec/graphql/types/resolvable_interface_spec.rb2
-rw-r--r--spec/graphql/types/root_storage_statistics_type_spec.rb2
-rw-r--r--spec/graphql/types/snippet_type_spec.rb2
-rw-r--r--spec/graphql/types/snippets/blob_type_spec.rb2
-rw-r--r--spec/graphql/types/snippets/blob_viewer_type_spec.rb2
-rw-r--r--spec/graphql/types/time_type_spec.rb2
-rw-r--r--spec/graphql/types/todo_type_spec.rb2
-rw-r--r--spec/graphql/types/tree/blob_type_spec.rb2
-rw-r--r--spec/graphql/types/tree/submodule_type_spec.rb2
-rw-r--r--spec/graphql/types/tree/tree_entry_type_spec.rb2
-rw-r--r--spec/graphql/types/tree/tree_type_spec.rb2
-rw-r--r--spec/graphql/types/tree/type_enum_spec.rb2
-rw-r--r--spec/graphql/types/user_type_spec.rb2
-rw-r--r--spec/haml_lint/linter/no_plain_nodes_spec.rb2
-rw-r--r--spec/helpers/access_tokens_helper_spec.rb2
-rw-r--r--spec/helpers/appearances_helper_spec.rb2
-rw-r--r--spec/helpers/application_helper_spec.rb2
-rw-r--r--spec/helpers/application_settings_helper_spec.rb2
-rw-r--r--spec/helpers/auth_helper_spec.rb2
-rw-r--r--spec/helpers/auto_devops_helper_spec.rb2
-rw-r--r--spec/helpers/avatars_helper_spec.rb2
-rw-r--r--spec/helpers/award_emoji_helper_spec.rb2
-rw-r--r--spec/helpers/blame_helper_spec.rb2
-rw-r--r--spec/helpers/blob_helper_spec.rb2
-rw-r--r--spec/helpers/boards_helper_spec.rb2
-rw-r--r--spec/helpers/broadcast_messages_helper_spec.rb2
-rw-r--r--spec/helpers/button_helper_spec.rb2
-rw-r--r--spec/helpers/calendar_helper_spec.rb2
-rw-r--r--spec/helpers/ci_status_helper_spec.rb2
-rw-r--r--spec/helpers/clusters_helper_spec.rb2
-rw-r--r--spec/helpers/commits_helper_spec.rb2
-rw-r--r--spec/helpers/components_helper_spec.rb2
-rw-r--r--spec/helpers/container_expiration_policies_helper_spec.rb2
-rw-r--r--spec/helpers/dashboard_helper_spec.rb2
-rw-r--r--spec/helpers/defer_script_tag_helper_spec.rb2
-rw-r--r--spec/helpers/diff_helper_spec.rb2
-rw-r--r--spec/helpers/emails_helper_spec.rb2
-rw-r--r--spec/helpers/emoji_helper_spec.rb2
-rw-r--r--spec/helpers/environment_helper_spec.rb2
-rw-r--r--spec/helpers/environments_helper_spec.rb2
-rw-r--r--spec/helpers/events_helper_spec.rb2
-rw-r--r--spec/helpers/explore_helper_spec.rb2
-rw-r--r--spec/helpers/export_helper_spec.rb2
-rw-r--r--spec/helpers/external_link_helper_spec.rb2
-rw-r--r--spec/helpers/form_helper_spec.rb2
-rw-r--r--spec/helpers/git_helper_spec.rb2
-rw-r--r--spec/helpers/gitlab_routing_helper_spec.rb2
-rw-r--r--spec/helpers/graph_helper_spec.rb2
-rw-r--r--spec/helpers/groups/group_members_helper_spec.rb2
-rw-r--r--spec/helpers/groups_helper_spec.rb2
-rw-r--r--spec/helpers/hooks_helper_spec.rb2
-rw-r--r--spec/helpers/icons_helper_spec.rb2
-rw-r--r--spec/helpers/import_helper_spec.rb2
-rw-r--r--spec/helpers/instance_configuration_helper_spec.rb2
-rw-r--r--spec/helpers/issuables_helper_spec.rb2
-rw-r--r--spec/helpers/issues_helper_spec.rb2
-rw-r--r--spec/helpers/labels_helper_spec.rb2
-rw-r--r--spec/helpers/markup_helper_spec.rb2
-rw-r--r--spec/helpers/members_helper_spec.rb2
-rw-r--r--spec/helpers/merge_requests_helper_spec.rb2
-rw-r--r--spec/helpers/namespaces_helper_spec.rb2
-rw-r--r--spec/helpers/nav_helper_spec.rb2
-rw-r--r--spec/helpers/notes_helper_spec.rb2
-rw-r--r--spec/helpers/notifications_helper_spec.rb2
-rw-r--r--spec/helpers/onboarding_experiment_helper_spec.rb2
-rw-r--r--spec/helpers/page_layout_helper_spec.rb2
-rw-r--r--spec/helpers/pagination_helper_spec.rb2
-rw-r--r--spec/helpers/preferences_helper_spec.rb2
-rw-r--r--spec/helpers/profiles_helper_spec.rb2
-rw-r--r--spec/helpers/projects/alert_management_helper_spec.rb2
-rw-r--r--spec/helpers/projects/error_tracking_helper_spec.rb2
-rw-r--r--spec/helpers/projects_helper_spec.rb2
-rw-r--r--spec/helpers/recaptcha_experiment_helper_spec.rb2
-rw-r--r--spec/helpers/releases_helper_spec.rb2
-rw-r--r--spec/helpers/rss_helper_spec.rb2
-rw-r--r--spec/helpers/runners_helper_spec.rb2
-rw-r--r--spec/helpers/search_helper_spec.rb2
-rw-r--r--spec/helpers/services_helper_spec.rb2
-rw-r--r--spec/helpers/sessions_helper_spec.rb2
-rw-r--r--spec/helpers/sidekiq_helper_spec.rb2
-rw-r--r--spec/helpers/snippets_helper_spec.rb2
-rw-r--r--spec/helpers/sorting_helper_spec.rb2
-rw-r--r--spec/helpers/sourcegraph_helper_spec.rb2
-rw-r--r--spec/helpers/storage_helper_spec.rb2
-rw-r--r--spec/helpers/submodule_helper_spec.rb2
-rw-r--r--spec/helpers/tab_helper_spec.rb2
-rw-r--r--spec/helpers/time_helper_spec.rb2
-rw-r--r--spec/helpers/timeboxes_helper_spec.rb2
-rw-r--r--spec/helpers/timeboxes_routing_helper_spec.rb2
-rw-r--r--spec/helpers/todos_helper_spec.rb2
-rw-r--r--spec/helpers/tracking_helper_spec.rb2
-rw-r--r--spec/helpers/tree_helper_spec.rb2
-rw-r--r--spec/helpers/user_callouts_helper_spec.rb2
-rw-r--r--spec/helpers/users_helper_spec.rb2
-rw-r--r--spec/helpers/version_check_helper_spec.rb2
-rw-r--r--spec/helpers/visibility_level_helper_spec.rb2
-rw-r--r--spec/helpers/wiki_helper_spec.rb2
-rw-r--r--spec/helpers/x509_helper_spec.rb2
-rw-r--r--spec/initializers/100_patch_omniauth_saml_spec.rb2
-rw-r--r--spec/initializers/6_validations_spec.rb2
-rw-r--r--spec/initializers/action_mailer_hooks_spec.rb2
-rw-r--r--spec/initializers/active_record_locking_spec.rb2
-rw-r--r--spec/initializers/asset_proxy_setting_spec.rb2
-rw-r--r--spec/initializers/attr_encrypted_no_db_connection_spec.rb2
-rw-r--r--spec/initializers/attr_encrypted_thread_safe_spec.rb2
-rw-r--r--spec/initializers/database_config_spec.rb2
-rw-r--r--spec/initializers/direct_upload_support_spec.rb2
-rw-r--r--spec/initializers/doorkeeper_spec.rb2
-rw-r--r--spec/initializers/fog_google_https_private_urls_spec.rb2
-rw-r--r--spec/initializers/hangouts_chat_http_override_spec.rb2
-rw-r--r--spec/initializers/lograge_spec.rb2
-rw-r--r--spec/initializers/mail_encoding_patch_spec.rb2
-rw-r--r--spec/initializers/rest-client-hostname_override_spec.rb2
-rw-r--r--spec/initializers/secret_token_spec.rb2
-rw-r--r--spec/initializers/settings_spec.rb2
-rw-r--r--spec/initializers/trusted_proxies_spec.rb2
-rw-r--r--spec/initializers/zz_metrics_spec.rb2
-rw-r--r--spec/lib/after_commit_queue_spec.rb2
-rw-r--r--spec/lib/api/api_spec.rb2
-rw-r--r--spec/lib/api/entities/branch_spec.rb2
-rw-r--r--spec/lib/api/entities/design_management/design_spec.rb2
-rw-r--r--spec/lib/api/entities/job_request/image_spec.rb2
-rw-r--r--spec/lib/api/entities/job_request/port_spec.rb2
-rw-r--r--spec/lib/api/entities/project_import_failed_relation_spec.rb2
-rw-r--r--spec/lib/api/entities/project_import_status_spec.rb2
-rw-r--r--spec/lib/api/entities/project_repository_storage_move_spec.rb2
-rw-r--r--spec/lib/api/entities/release_spec.rb2
-rw-r--r--spec/lib/api/entities/snippet_spec.rb2
-rw-r--r--spec/lib/api/entities/user_spec.rb2
-rw-r--r--spec/lib/api/helpers/graphql_helpers_spec.rb2
-rw-r--r--spec/lib/api/helpers/label_helpers_spec.rb2
-rw-r--r--spec/lib/api/helpers/pagination_spec.rb2
-rw-r--r--spec/lib/api/helpers/pagination_strategies_spec.rb2
-rw-r--r--spec/lib/api/helpers/related_resources_helpers_spec.rb2
-rw-r--r--spec/lib/api/helpers/version_spec.rb2
-rw-r--r--spec/lib/api/helpers_spec.rb2
-rw-r--r--spec/lib/api/support/git_access_actor_spec.rb2
-rw-r--r--spec/lib/api/validations/validators/absence_spec.rb2
-rw-r--r--spec/lib/api/validations/validators/array_none_any_spec.rb2
-rw-r--r--spec/lib/api/validations/validators/file_path_spec.rb2
-rw-r--r--spec/lib/api/validations/validators/git_ref_spec.rb2
-rw-r--r--spec/lib/api/validations/validators/git_sha_spec.rb2
-rw-r--r--spec/lib/api/validations/validators/integer_none_any_spec.rb2
-rw-r--r--spec/lib/api/validations/validators/limit_spec.rb2
-rw-r--r--spec/lib/backup/files_spec.rb2
-rw-r--r--spec/lib/backup/manager_spec.rb2
-rw-r--r--spec/lib/backup/repository_spec.rb2
-rw-r--r--spec/lib/backup/uploads_spec.rb2
-rw-r--r--spec/lib/banzai/color_parser_spec.rb2
-rw-r--r--spec/lib/banzai/commit_renderer_spec.rb2
-rw-r--r--spec/lib/banzai/cross_project_reference_spec.rb2
-rw-r--r--spec/lib/banzai/filter/absolute_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/abstract_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/asset_proxy_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/audio_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/autolink_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/blockquote_fence_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/broadcast_message_placeholders_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/broadcast_message_sanitization_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/color_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/commit_range_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/commit_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/commit_trailers_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/design_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/emoji_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/external_issue_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/external_link_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/footnote_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/front_matter_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/gollum_tags_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/html_entity_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/image_lazy_load_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/image_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/inline_diff_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/inline_metrics_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/inline_metrics_redactor_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/issuable_state_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/issue_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/label_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/markdown_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/math_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/merge_request_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/mermaid_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/output_safety_spec.rb2
-rw-r--r--spec/lib/banzai/filter/plantuml_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/project_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/reference_redactor_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/repository_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/sanitization_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/snippet_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/spaced_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/suggestion_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/syntax_highlight_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/table_of_contents_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/table_of_contents_tag_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/upload_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/user_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/video_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/wiki_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter_array_spec.rb2
-rw-r--r--spec/lib/banzai/issuable_extractor_spec.rb2
-rw-r--r--spec/lib/banzai/object_renderer_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/broadcast_message_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/description_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/email_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/emoji_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/full_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/gfm_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/post_process_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/wiki_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/querying_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/base_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/commit_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/commit_range_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/design_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/external_issue_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/issue_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/label_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/mentioned_group_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/mentioned_project_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/mentioned_user_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/merge_request_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/milestone_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/project_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/snippet_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/user_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_redactor_spec.rb2
-rw-r--r--spec/lib/banzai/render_context_spec.rb2
-rw-r--r--spec/lib/banzai/renderer_spec.rb2
-rw-r--r--spec/lib/bitbucket/collection_spec.rb2
-rw-r--r--spec/lib/bitbucket/connection_spec.rb2
-rw-r--r--spec/lib/bitbucket/page_spec.rb2
-rw-r--r--spec/lib/bitbucket/paginator_spec.rb2
-rw-r--r--spec/lib/bitbucket/representation/comment_spec.rb2
-rw-r--r--spec/lib/bitbucket/representation/issue_spec.rb2
-rw-r--r--spec/lib/bitbucket/representation/pull_request_comment_spec.rb2
-rw-r--r--spec/lib/bitbucket/representation/pull_request_spec.rb2
-rw-r--r--spec/lib/bitbucket/representation/repo_spec.rb2
-rw-r--r--spec/lib/bitbucket/representation/user_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/client_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/collection_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/connection_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/page_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/paginator_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/representation/activity_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/representation/comment_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/representation/pull_request_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/representation/repo_spec.rb2
-rw-r--r--spec/lib/constraints/admin_constrainer_spec.rb2
-rw-r--r--spec/lib/constraints/feature_constrainer_spec.rb2
-rw-r--r--spec/lib/constraints/group_url_constrainer_spec.rb2
-rw-r--r--spec/lib/constraints/project_url_constrainer_spec.rb2
-rw-r--r--spec/lib/constraints/user_url_constrainer_spec.rb2
-rw-r--r--spec/lib/container_registry/blob_spec.rb2
-rw-r--r--spec/lib/container_registry/client_spec.rb2
-rw-r--r--spec/lib/container_registry/path_spec.rb2
-rw-r--r--spec/lib/container_registry/registry_spec.rb2
-rw-r--r--spec/lib/container_registry/tag_spec.rb2
-rw-r--r--spec/lib/csv_builder_spec.rb2
-rw-r--r--spec/lib/declarative_policy_spec.rb2
-rw-r--r--spec/lib/event_filter_spec.rb2
-rw-r--r--spec/lib/expand_variables_spec.rb2
-rw-r--r--spec/lib/extracts_path_spec.rb2
-rw-r--r--spec/lib/feature/gitaly_spec.rb2
-rw-r--r--spec/lib/feature_spec.rb2
-rw-r--r--spec/lib/file_size_validator_spec.rb2
-rw-r--r--spec/lib/forever_spec.rb2
-rw-r--r--spec/lib/gitaly/server_spec.rb2
-rw-r--r--spec/lib/gitlab/access/branch_protection_spec.rb2
-rw-r--r--spec/lib/gitlab/alert_management/alert_params_spec.rb2
-rw-r--r--spec/lib/gitlab/alert_management/alert_status_counts_spec.rb2
-rw-r--r--spec/lib/gitlab/alert_management/fingerprint_spec.rb2
-rw-r--r--spec/lib/gitlab/alerting/alert_spec.rb2
-rw-r--r--spec/lib/gitlab/alerting/notification_payload_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/allowable_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/base_query_builder_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/records_fetcher_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb2
-rw-r--r--spec/lib/gitlab/anonymous_session_spec.rb2
-rw-r--r--spec/lib/gitlab/app_json_logger_spec.rb2
-rw-r--r--spec/lib/gitlab/app_logger_spec.rb2
-rw-r--r--spec/lib/gitlab/app_text_logger_spec.rb2
-rw-r--r--spec/lib/gitlab/application_context_spec.rb2
-rw-r--r--spec/lib/gitlab/application_rate_limiter_spec.rb2
-rw-r--r--spec/lib/gitlab/asciidoc/include_processor_spec.rb2
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb2
-rw-r--r--spec/lib/gitlab/asset_proxy_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/activity_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/auth_finders_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/blocked_user_tracker_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/current_user_mode_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ip_rate_limiter_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/key_status_checker_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ldap/access_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ldap/adapter_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ldap/auth_hash_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ldap/authentication_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ldap/config_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ldap/dn_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ldap/person_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ldap/user_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/o_auth/provider_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/o_auth/user_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/request_authenticator_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/saml/auth_hash_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/saml/identity_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/saml/origin_validator_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/saml/user_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/unique_ips_limiter_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/user_access_denied_reason_spec.rb2
-rw-r--r--spec/lib/gitlab/auth_spec.rb2
-rw-r--r--spec/lib/gitlab/authorized_keys_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_hashed_project_repositories_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_legacy_project_repositories_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_project_fullpath_in_repo_config_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_project_repositories_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/digest_column_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/encrypt_columns_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/encrypt_runners_tokens_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/fix_projects_without_project_feature_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/migrate_null_private_profile_to_false_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/migrate_pages_metadata_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/populate_cluster_kubernetes_namespace_table_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/populate_untracked_uploads_dependencies/untracked_file_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/populate_user_highest_roles_table_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/remove_restricted_todos_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/reset_merge_status_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/schedule_calculate_wiki_sizes_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration_spec.rb2
-rw-r--r--spec/lib/gitlab/backtrace_cleaner_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/coverage/metadata_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/coverage/report_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/coverage/template_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/pipeline/metadata_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/pipeline/status_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/pipeline/template_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/shared/metadata.rb2
-rw-r--r--spec/lib/gitlab/bare_repository_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/bare_repository_import/repository_spec.rb2
-rw-r--r--spec/lib/gitlab/batch_pop_queueing_spec.rb2
-rw-r--r--spec/lib/gitlab/batch_worker_context_spec.rb2
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/bitbucket_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/bitbucket_import/wiki_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/blame_spec.rb2
-rw-r--r--spec/lib/gitlab/blob_helper_spec.rb2
-rw-r--r--spec/lib/gitlab/branch_push_merge_commit_analyzer_spec.rb2
-rw-r--r--spec/lib/gitlab/build_access_spec.rb2
-rw-r--r--spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb2
-rw-r--r--spec/lib/gitlab/cache/import/caching_spec.rb2
-rw-r--r--spec/lib/gitlab/cache/request_cache_spec.rb2
-rw-r--r--spec/lib/gitlab/changes_list_spec.rb2
-rw-r--r--spec/lib/gitlab/chat/command_spec.rb2
-rw-r--r--spec/lib/gitlab/chat/output_spec.rb2
-rw-r--r--spec/lib/gitlab/chat/responder/base_spec.rb2
-rw-r--r--spec/lib/gitlab/chat/responder/mattermost_spec.rb2
-rw-r--r--spec/lib/gitlab/chat/responder/slack_spec.rb2
-rw-r--r--spec/lib/gitlab/chat/responder_spec.rb2
-rw-r--r--spec/lib/gitlab/chat_name_token_spec.rb2
-rw-r--r--spec/lib/gitlab/chat_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/branch_check_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/change_access_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/diff_check_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/force_push_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/lfs_check_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/lfs_integrity_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/project_created_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/project_moved_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/push_check_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/push_file_count_check_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/snippet_check_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/tag_check_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/timed_logger_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/ansi2html_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/ansi2json/line_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/ansi2json/parser_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/ansi2json/result_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/ansi2json/style_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/ansi2json_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/artifact_file_reader_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/adapters/gzip_stream_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/adapters/raw_stream_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/path_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/context/build_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/context/global_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/credentials/factory_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/credentials/registry_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/image_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/policy/changes_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/policy/refs_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/policy/variables_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/policy_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/port_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/rules/rule_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/rules_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/step_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/charts_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/artifacts_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/bridge_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/cache_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/commands_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/coverage_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/default_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/environment_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/files_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/hidden_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/image_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/include_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/inherit/default_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/inherit/variables_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/jobs_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/key_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/kubernetes_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/need_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/needs_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/paths_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/policy_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/port_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/ports_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/prefix_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/processable_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/release/assets/link_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/release/assets/links_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/release/assets_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/release_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/reports_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/retry_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/rules_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/script_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/service_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/services_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/stage_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/stages_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/trigger_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/variables_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/workflow_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/extendable/entry_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/extendable_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/context_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/artifact_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/base_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/local_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/project_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/remote_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/template_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/processor_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/normalizer_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/cron_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/jwt_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/mask_secret_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/parsers/accessibility/pa11y_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/parsers/coverage/cobertura_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/parsers/terraform/tfplan_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/parsers/test/junit_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/parsers_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/build/associations_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/build_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/command_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/create_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/duration_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/null_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/string_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/variable_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/token_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/preloader_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build/resource_group_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/coverage_reports_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/terraform_reports_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/test_case_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/test_reports_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/bridge/factory_spec.rb2
-rw-r--r--spec/lib/gitlab/static_site_editor/config_spec.rb16
826 files changed, 11770 insertions, 723 deletions
diff --git a/app/assets/javascripts/design_management/index.js b/app/assets/javascripts/design_management/index.js
index eb00e1742ea..1fc5779515a 100644
--- a/app/assets/javascripts/design_management/index.js
+++ b/app/assets/javascripts/design_management/index.js
@@ -1,3 +1,6 @@
+// This application is being moved, please do not touch this files
+// Please see https://gitlab.com/gitlab-org/gitlab/-/issues/14744#note_364468096 for details
+
import $ from 'jquery';
import Vue from 'vue';
import createRouter from './router';
diff --git a/app/assets/javascripts/design_management_new/components/app.vue b/app/assets/javascripts/design_management_new/components/app.vue
new file mode 100644
index 00000000000..98240aef810
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/app.vue
@@ -0,0 +1,3 @@
+<template>
+ <router-view />
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/delete_button.vue b/app/assets/javascripts/design_management_new/components/delete_button.vue
new file mode 100644
index 00000000000..1fd902c9ed7
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/delete_button.vue
@@ -0,0 +1,64 @@
+<script>
+import { GlDeprecatedButton, GlModal, GlModalDirective } from '@gitlab/ui';
+import { uniqueId } from 'lodash';
+
+export default {
+ name: 'DeleteButton',
+ components: {
+ GlDeprecatedButton,
+ GlModal,
+ },
+ directives: {
+ GlModalDirective,
+ },
+ props: {
+ isDeleting: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ buttonClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ buttonVariant: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ hasSelectedDesigns: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ },
+ data() {
+ return {
+ modalId: uniqueId('design-deletion-confirmation-'),
+ };
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-modal
+ :modal-id="modalId"
+ :title="s__('DesignManagement|Delete designs confirmation')"
+ :ok-title="s__('DesignManagement|Delete')"
+ ok-variant="danger"
+ @ok="$emit('deleteSelectedDesigns')"
+ >
+ <p>{{ s__('DesignManagement|Are you sure you want to delete the selected designs?') }}</p>
+ </gl-modal>
+ <gl-deprecated-button
+ v-gl-modal-directive="modalId"
+ :variant="buttonVariant"
+ :disabled="isDeleting || !hasSelectedDesigns"
+ :class="buttonClass"
+ >
+ <slot></slot>
+ </gl-deprecated-button>
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/design_destroyer.vue b/app/assets/javascripts/design_management_new/components/design_destroyer.vue
new file mode 100644
index 00000000000..62460ca551c
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/design_destroyer.vue
@@ -0,0 +1,66 @@
+<script>
+import { ApolloMutation } from 'vue-apollo';
+import getDesignListQuery from '../graphql/queries/get_design_list.query.graphql';
+import destroyDesignMutation from '../graphql/mutations/destroy_design.mutation.graphql';
+import { updateStoreAfterDesignsDelete } from '../utils/cache_update';
+
+export default {
+ components: {
+ ApolloMutation,
+ },
+ props: {
+ filenames: {
+ type: Array,
+ required: true,
+ },
+ projectPath: {
+ type: String,
+ required: true,
+ },
+ iid: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ projectQueryBody() {
+ return {
+ query: getDesignListQuery,
+ variables: { fullPath: this.projectPath, iid: this.iid, atVersion: null },
+ };
+ },
+ },
+ methods: {
+ updateStoreAfterDelete(
+ store,
+ {
+ data: { designManagementDelete },
+ },
+ ) {
+ updateStoreAfterDesignsDelete(
+ store,
+ designManagementDelete,
+ this.projectQueryBody,
+ this.filenames,
+ );
+ },
+ },
+ destroyDesignMutation,
+};
+</script>
+
+<template>
+ <apollo-mutation
+ #default="{ mutate, loading, error }"
+ :mutation="$options.destroyDesignMutation"
+ :variables="{
+ filenames,
+ projectPath,
+ iid,
+ }"
+ :update="updateStoreAfterDelete"
+ v-on="$listeners"
+ >
+ <slot v-bind="{ mutate, loading, error }"></slot>
+ </apollo-mutation>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/design_note_pin.vue b/app/assets/javascripts/design_management_new/components/design_note_pin.vue
new file mode 100644
index 00000000000..0811397fbad
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/design_note_pin.vue
@@ -0,0 +1,61 @@
+<script>
+import { __, sprintf } from '~/locale';
+import Icon from '~/vue_shared/components/icon.vue';
+
+export default {
+ name: 'DesignNotePin',
+ components: {
+ Icon,
+ },
+ props: {
+ position: {
+ type: Object,
+ required: true,
+ },
+ label: {
+ type: Number,
+ required: false,
+ default: null,
+ },
+ repositioning: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ isNewNote() {
+ return this.label === null;
+ },
+ pinStyle() {
+ return this.repositioning ? { ...this.position, cursor: 'move' } : this.position;
+ },
+ pinLabel() {
+ return this.isNewNote
+ ? __('Comment form position')
+ : sprintf(__("Comment '%{label}' position"), { label: this.label });
+ },
+ },
+};
+</script>
+
+<template>
+ <button
+ :style="pinStyle"
+ :aria-label="pinLabel"
+ :class="{
+ 'btn-transparent comment-indicator': isNewNote,
+ 'js-image-badge badge badge-pill': !isNewNote,
+ }"
+ class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center"
+ type="button"
+ @mousedown="$emit('mousedown', $event)"
+ @mouseup="$emit('mouseup', $event)"
+ @click="$emit('click', $event)"
+ >
+ <icon v-if="isNewNote" name="image-comment-dark" />
+ <template v-else>
+ {{ label }}
+ </template>
+ </button>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/design_notes/design_discussion.vue b/app/assets/javascripts/design_management_new/components/design_notes/design_discussion.vue
new file mode 100644
index 00000000000..4aaf43e3a5b
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/design_notes/design_discussion.vue
@@ -0,0 +1,297 @@
+<script>
+import { ApolloMutation } from 'vue-apollo';
+import { GlTooltipDirective, GlIcon, GlLoadingIcon, GlLink } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import allVersionsMixin from '../../mixins/all_versions';
+import createNoteMutation from '../../graphql/mutations/create_note.mutation.graphql';
+import toggleResolveDiscussionMutation from '../../graphql/mutations/toggle_resolve_discussion.mutation.graphql';
+import getDesignQuery from '../../graphql/queries/get_design.query.graphql';
+import activeDiscussionQuery from '../../graphql/queries/active_discussion.query.graphql';
+import DesignNote from './design_note.vue';
+import DesignReplyForm from './design_reply_form.vue';
+import { updateStoreAfterAddDiscussionComment } from '../../utils/cache_update';
+import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../../constants';
+import ToggleRepliesWidget from './toggle_replies_widget.vue';
+
+export default {
+ components: {
+ ApolloMutation,
+ DesignNote,
+ ReplyPlaceholder,
+ DesignReplyForm,
+ GlIcon,
+ GlLoadingIcon,
+ GlLink,
+ ToggleRepliesWidget,
+ TimeAgoTooltip,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [allVersionsMixin],
+ props: {
+ discussion: {
+ type: Object,
+ required: true,
+ },
+ noteableId: {
+ type: String,
+ required: true,
+ },
+ designId: {
+ type: String,
+ required: true,
+ },
+ markdownPreviewPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ resolvedDiscussionsExpanded: {
+ type: Boolean,
+ required: true,
+ },
+ discussionWithOpenForm: {
+ type: String,
+ required: true,
+ },
+ },
+ apollo: {
+ activeDiscussion: {
+ query: activeDiscussionQuery,
+ result({ data }) {
+ const discussionId = data.activeDiscussion.id;
+ if (this.discussion.resolved && !this.resolvedDiscussionsExpanded) {
+ return;
+ }
+ // We watch any changes to the active discussion from the design pins and scroll to this discussion if it exists
+ // We don't want scrollIntoView to be triggered from the discussion click itself
+ if (
+ discussionId &&
+ data.activeDiscussion.source === ACTIVE_DISCUSSION_SOURCE_TYPES.pin &&
+ discussionId === this.discussion.notes[0].id
+ ) {
+ this.$el.scrollIntoView({
+ behavior: 'smooth',
+ inline: 'start',
+ });
+ }
+ },
+ },
+ },
+ data() {
+ return {
+ discussionComment: '',
+ isFormRendered: false,
+ activeDiscussion: {},
+ isResolving: false,
+ shouldChangeResolvedStatus: false,
+ areRepliesCollapsed: this.discussion.resolved,
+ };
+ },
+ computed: {
+ mutationPayload() {
+ return {
+ noteableId: this.noteableId,
+ body: this.discussionComment,
+ discussionId: this.discussion.id,
+ };
+ },
+ designVariables() {
+ return {
+ fullPath: this.projectPath,
+ iid: this.issueIid,
+ filenames: [this.$route.params.id],
+ atVersion: this.designsVersion,
+ };
+ },
+ isDiscussionHighlighted() {
+ return this.discussion.notes[0].id === this.activeDiscussion.id;
+ },
+ resolveCheckboxText() {
+ return this.discussion.resolved
+ ? s__('DesignManagement|Unresolve thread')
+ : s__('DesignManagement|Resolve thread');
+ },
+ firstNote() {
+ return this.discussion.notes[0];
+ },
+ discussionReplies() {
+ return this.discussion.notes.slice(1);
+ },
+ areRepliesShown() {
+ return !this.discussion.resolved || !this.areRepliesCollapsed;
+ },
+ resolveIconName() {
+ return this.discussion.resolved ? 'check-circle-filled' : 'check-circle';
+ },
+ isRepliesWidgetVisible() {
+ return this.discussion.resolved && this.discussionReplies.length > 0;
+ },
+ isReplyPlaceholderVisible() {
+ return this.areRepliesShown || !this.discussionReplies.length;
+ },
+ isFormVisible() {
+ return this.isFormRendered && this.discussionWithOpenForm === this.discussion.id;
+ },
+ },
+ methods: {
+ addDiscussionComment(
+ store,
+ {
+ data: { createNote },
+ },
+ ) {
+ updateStoreAfterAddDiscussionComment(
+ store,
+ createNote,
+ getDesignQuery,
+ this.designVariables,
+ this.discussion.id,
+ );
+ },
+ onDone() {
+ this.discussionComment = '';
+ this.hideForm();
+ if (this.shouldChangeResolvedStatus) {
+ this.toggleResolvedStatus();
+ }
+ },
+ onCreateNoteError(err) {
+ this.$emit('createNoteError', err);
+ },
+ hideForm() {
+ this.isFormRendered = false;
+ this.discussionComment = '';
+ },
+ showForm() {
+ this.$emit('openForm', this.discussion.id);
+ this.isFormRendered = true;
+ },
+ toggleResolvedStatus() {
+ this.isResolving = true;
+ this.$apollo
+ .mutate({
+ mutation: toggleResolveDiscussionMutation,
+ variables: { id: this.discussion.id, resolve: !this.discussion.resolved },
+ })
+ .then(({ data }) => {
+ if (data.errors?.length > 0) {
+ this.$emit('resolveDiscussionError', data.errors[0]);
+ }
+ })
+ .catch(err => {
+ this.$emit('resolveDiscussionError', err);
+ })
+ .finally(() => {
+ this.isResolving = false;
+ });
+ },
+ },
+ createNoteMutation,
+};
+</script>
+
+<template>
+ <div class="design-discussion-wrapper">
+ <div
+ class="badge badge-pill gl-display-flex gl-align-items-center gl-justify-content-center"
+ :class="{ resolved: discussion.resolved }"
+ type="button"
+ >
+ {{ discussion.index }}
+ </div>
+ <ul
+ class="design-discussion bordered-box gl-relative gl-p-0 gl-list-style-none"
+ data-qa-selector="design_discussion_content"
+ >
+ <design-note
+ :note="firstNote"
+ :markdown-preview-path="markdownPreviewPath"
+ :is-resolving="isResolving"
+ :class="{ 'gl-bg-blue-50': isDiscussionHighlighted }"
+ @error="$emit('updateNoteError', $event)"
+ >
+ <template v-if="discussion.resolvable" #resolveDiscussion>
+ <button
+ v-gl-tooltip
+ :class="{ 'is-active': discussion.resolved }"
+ :title="resolveCheckboxText"
+ :aria-label="resolveCheckboxText"
+ type="button"
+ class="line-resolve-btn note-action-button gl-mr-3"
+ data-testid="resolve-button"
+ @click.stop="toggleResolvedStatus"
+ >
+ <gl-icon v-if="!isResolving" :name="resolveIconName" data-testid="resolve-icon" />
+ <gl-loading-icon v-else inline />
+ </button>
+ </template>
+ <template v-if="discussion.resolved" #resolvedStatus>
+ <p class="gl-text-gray-700 gl-font-sm gl-m-0 gl-mt-5" data-testid="resolved-message">
+ {{ __('Resolved by') }}
+ <gl-link
+ class="gl-text-gray-700 gl-text-decoration-none gl-font-sm link-inherit-color"
+ :href="discussion.resolvedBy.webUrl"
+ target="_blank"
+ >{{ discussion.resolvedBy.name }}</gl-link
+ >
+ <time-ago-tooltip :time="discussion.resolvedAt" tooltip-placement="bottom" />
+ </p>
+ </template>
+ </design-note>
+ <toggle-replies-widget
+ v-if="isRepliesWidgetVisible"
+ :collapsed="areRepliesCollapsed"
+ :replies="discussionReplies"
+ @toggle="areRepliesCollapsed = !areRepliesCollapsed"
+ />
+ <design-note
+ v-for="note in discussionReplies"
+ v-show="areRepliesShown"
+ :key="note.id"
+ :note="note"
+ :markdown-preview-path="markdownPreviewPath"
+ :is-resolving="isResolving"
+ :class="{ 'gl-bg-blue-50': isDiscussionHighlighted }"
+ @error="$emit('updateNoteError', $event)"
+ />
+ <li v-show="isReplyPlaceholderVisible" class="reply-wrapper">
+ <reply-placeholder
+ v-if="!isFormVisible"
+ class="qa-discussion-reply"
+ :button-text="__('Reply...')"
+ @onClick="showForm"
+ />
+ <apollo-mutation
+ v-else
+ #default="{ mutate, loading }"
+ :mutation="$options.createNoteMutation"
+ :variables="{
+ input: mutationPayload,
+ }"
+ :update="addDiscussionComment"
+ @done="onDone"
+ @error="onCreateNoteError"
+ >
+ <design-reply-form
+ v-model="discussionComment"
+ :is-saving="loading"
+ :markdown-preview-path="markdownPreviewPath"
+ @submitForm="mutate"
+ @cancelForm="hideForm"
+ >
+ <template v-if="discussion.resolvable" #resolveCheckbox>
+ <label data-testid="resolve-checkbox">
+ <input v-model="shouldChangeResolvedStatus" type="checkbox" />
+ {{ resolveCheckboxText }}
+ </label>
+ </template>
+ </design-reply-form>
+ </apollo-mutation>
+ </li>
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/design_notes/design_note.vue b/app/assets/javascripts/design_management_new/components/design_notes/design_note.vue
new file mode 100644
index 00000000000..b1f3a43a66d
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/design_notes/design_note.vue
@@ -0,0 +1,156 @@
+<script>
+import { ApolloMutation } from 'vue-apollo';
+import { GlTooltipDirective, GlIcon } from '@gitlab/ui';
+import updateNoteMutation from '../../graphql/mutations/update_note.mutation.graphql';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import DesignReplyForm from './design_reply_form.vue';
+import { findNoteId } from '../../utils/design_management_utils';
+import { hasErrors } from '../../utils/cache_update';
+
+export default {
+ components: {
+ UserAvatarLink,
+ TimelineEntryItem,
+ TimeAgoTooltip,
+ DesignReplyForm,
+ ApolloMutation,
+ GlIcon,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ note: {
+ type: Object,
+ required: true,
+ },
+ markdownPreviewPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ noteText: this.note.body,
+ isEditing: false,
+ };
+ },
+ computed: {
+ author() {
+ return this.note.author;
+ },
+ noteAnchorId() {
+ return findNoteId(this.note.id);
+ },
+ isNoteLinked() {
+ return this.$route.hash === `#note_${this.noteAnchorId}`;
+ },
+ mutationPayload() {
+ return {
+ id: this.note.id,
+ body: this.noteText,
+ };
+ },
+ isEditButtonVisible() {
+ return !this.isEditing && this.note.userPermissions.adminNote;
+ },
+ },
+ mounted() {
+ if (this.isNoteLinked) {
+ this.$refs.anchor.$el.scrollIntoView({ behavior: 'smooth', inline: 'start' });
+ }
+ },
+ methods: {
+ hideForm() {
+ this.isEditing = false;
+ this.noteText = this.note.body;
+ },
+ onDone({ data }) {
+ this.hideForm();
+ if (hasErrors(data.updateNote)) {
+ this.$emit('error', data.errors[0]);
+ }
+ },
+ },
+ updateNoteMutation,
+};
+</script>
+
+<template>
+ <timeline-entry-item :id="`note_${noteAnchorId}`" ref="anchor" class="design-note note-form">
+ <user-avatar-link
+ :link-href="author.webUrl"
+ :img-src="author.avatarUrl"
+ :img-alt="author.username"
+ :img-size="40"
+ />
+ <div class="d-flex justify-content-between">
+ <div>
+ <a
+ v-once
+ :href="author.webUrl"
+ class="js-user-link"
+ :data-user-id="author.id"
+ :data-username="author.username"
+ >
+ <span class="note-header-author-name bold">{{ author.name }}</span>
+ <span v-if="author.status_tooltip_html" v-html="author.status_tooltip_html"></span>
+ <span class="note-headline-light">@{{ author.username }}</span>
+ </a>
+ <span class="note-headline-light note-headline-meta">
+ <span class="system-note-message"> <slot></slot> </span>
+ <template v-if="note.createdAt">
+ <span class="system-note-separator"></span>
+ <a class="note-timestamp system-note-separator" :href="`#note_${noteAnchorId}`">
+ <time-ago-tooltip :time="note.createdAt" tooltip-placement="bottom" />
+ </a>
+ </template>
+ </span>
+ </div>
+ <div class="gl-display-flex">
+ <slot name="resolveDiscussion"></slot>
+ <button
+ v-if="isEditButtonVisible"
+ v-gl-tooltip
+ type="button"
+ :title="__('Edit comment')"
+ class="note-action-button js-note-edit btn btn-transparent qa-note-edit-button"
+ @click="isEditing = true"
+ >
+ <gl-icon name="pencil" class="link-highlight" />
+ </button>
+ </div>
+ </div>
+ <template v-if="!isEditing">
+ <div
+ class="note-text js-note-text md"
+ data-qa-selector="note_content"
+ v-html="note.bodyHtml"
+ ></div>
+ <slot name="resolvedStatus"></slot>
+ </template>
+ <apollo-mutation
+ v-else
+ #default="{ mutate, loading }"
+ :mutation="$options.updateNoteMutation"
+ :variables="{
+ input: mutationPayload,
+ }"
+ @error="$emit('error', $event)"
+ @done="onDone"
+ >
+ <design-reply-form
+ v-model="noteText"
+ :is-saving="loading"
+ :markdown-preview-path="markdownPreviewPath"
+ :is-new-comment="false"
+ class="mt-5"
+ @submitForm="mutate"
+ @cancelForm="hideForm"
+ />
+ </apollo-mutation>
+ </timeline-entry-item>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/design_notes/design_reply_form.vue b/app/assets/javascripts/design_management_new/components/design_notes/design_reply_form.vue
new file mode 100644
index 00000000000..969034909f2
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/design_notes/design_reply_form.vue
@@ -0,0 +1,141 @@
+<script>
+import { GlDeprecatedButton, GlModal } from '@gitlab/ui';
+import MarkdownField from '~/vue_shared/components/markdown/field.vue';
+import { s__ } from '~/locale';
+
+export default {
+ name: 'DesignReplyForm',
+ components: {
+ MarkdownField,
+ GlDeprecatedButton,
+ GlModal,
+ },
+ props: {
+ markdownPreviewPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ value: {
+ type: String,
+ required: true,
+ },
+ isSaving: {
+ type: Boolean,
+ required: true,
+ },
+ isNewComment: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ },
+ data() {
+ return {
+ formText: this.value,
+ };
+ },
+ computed: {
+ hasValue() {
+ return this.value.trim().length > 0;
+ },
+ modalSettings() {
+ if (this.isNewComment) {
+ return {
+ title: s__('DesignManagement|Cancel comment confirmation'),
+ okTitle: s__('DesignManagement|Discard comment'),
+ cancelTitle: s__('DesignManagement|Keep comment'),
+ content: s__('DesignManagement|Are you sure you want to cancel creating this comment?'),
+ };
+ }
+ return {
+ title: s__('DesignManagement|Cancel comment update confirmation'),
+ okTitle: s__('DesignManagement|Cancel changes'),
+ cancelTitle: s__('DesignManagement|Keep changes'),
+ content: s__('DesignManagement|Are you sure you want to cancel changes to this comment?'),
+ };
+ },
+ buttonText() {
+ return this.isNewComment
+ ? s__('DesignManagement|Comment')
+ : s__('DesignManagement|Save comment');
+ },
+ },
+ mounted() {
+ this.focusInput();
+ },
+ methods: {
+ submitForm() {
+ if (this.hasValue) this.$emit('submitForm');
+ },
+ cancelComment() {
+ if (this.hasValue && this.formText !== this.value) {
+ this.$refs.cancelCommentModal.show();
+ } else {
+ this.$emit('cancelForm');
+ }
+ },
+ focusInput() {
+ this.$refs.textarea.focus();
+ },
+ },
+};
+</script>
+
+<template>
+ <form class="new-note common-note-form" @submit.prevent>
+ <markdown-field
+ :markdown-preview-path="markdownPreviewPath"
+ :can-attach-file="false"
+ :enable-autocomplete="true"
+ :textarea-value="value"
+ markdown-docs-path="/help/user/markdown"
+ class="bordered-box"
+ >
+ <template #textarea>
+ <textarea
+ ref="textarea"
+ :value="value"
+ class="note-textarea js-gfm-input js-autosize markdown-area"
+ dir="auto"
+ data-supports-quick-actions="false"
+ data-qa-selector="note_textarea"
+ :aria-label="__('Description')"
+ :placeholder="__('Write a comment…')"
+ @input="$emit('input', $event.target.value)"
+ @keydown.meta.enter="submitForm"
+ @keydown.ctrl.enter="submitForm"
+ @keyup.esc.stop="cancelComment"
+ >
+ </textarea>
+ </template>
+ </markdown-field>
+ <slot name="resolveCheckbox"></slot>
+ <div class="note-form-actions gl-display-flex gl-justify-content-space-between">
+ <gl-deprecated-button
+ ref="submitButton"
+ :disabled="!hasValue || isSaving"
+ variant="success"
+ type="submit"
+ data-track-event="click_button"
+ data-qa-selector="save_comment_button"
+ @click="$emit('submitForm')"
+ >
+ {{ buttonText }}
+ </gl-deprecated-button>
+ <gl-deprecated-button ref="cancelButton" @click="cancelComment">{{
+ __('Cancel')
+ }}</gl-deprecated-button>
+ </div>
+ <gl-modal
+ ref="cancelCommentModal"
+ ok-variant="danger"
+ :title="modalSettings.title"
+ :ok-title="modalSettings.okTitle"
+ :cancel-title="modalSettings.cancelTitle"
+ modal-id="cancel-comment-modal"
+ @ok="$emit('cancelForm')"
+ >{{ modalSettings.content }}
+ </gl-modal>
+ </form>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/design_notes/toggle_replies_widget.vue b/app/assets/javascripts/design_management_new/components/design_notes/toggle_replies_widget.vue
new file mode 100644
index 00000000000..46c73e3eea8
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/design_notes/toggle_replies_widget.vue
@@ -0,0 +1,70 @@
+<script>
+import { GlIcon, GlButton, GlLink } from '@gitlab/ui';
+import { __, n__ } from '~/locale';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+export default {
+ name: 'ToggleNotesWidget',
+ components: {
+ GlIcon,
+ GlButton,
+ GlLink,
+ TimeAgoTooltip,
+ },
+ props: {
+ collapsed: {
+ type: Boolean,
+ required: true,
+ },
+ replies: {
+ type: Array,
+ required: true,
+ },
+ },
+ computed: {
+ lastReply() {
+ return this.replies[this.replies.length - 1];
+ },
+ iconName() {
+ return this.collapsed ? 'chevron-right' : 'chevron-down';
+ },
+ toggleText() {
+ return this.collapsed
+ ? `${this.replies.length} ${n__('reply', 'replies', this.replies.length)}`
+ : __('Collapse replies');
+ },
+ },
+};
+</script>
+
+<template>
+ <li
+ class="toggle-comments gl-bg-gray-50 gl-display-flex gl-align-items-center gl-py-3"
+ :class="{ expanded: !collapsed }"
+ data-testid="toggle-comments-wrapper"
+ >
+ <gl-icon :name="iconName" class="gl-ml-3" @click.stop="$emit('toggle')" />
+ <gl-button
+ variant="link"
+ class="toggle-comments-button gl-ml-2 gl-mr-2"
+ @click.stop="$emit('toggle')"
+ >
+ {{ toggleText }}
+ </gl-button>
+ <template v-if="collapsed">
+ <span class="gl-text-gray-700">{{ __('Last reply by') }}</span>
+ <gl-link
+ :href="lastReply.author.webUrl"
+ target="_blank"
+ class="link-inherit-color gl-text-black-normal gl-text-decoration-none gl-font-weight-bold gl-ml-2 gl-mr-2"
+ >
+ {{ lastReply.author.name }}
+ </gl-link>
+ <time-ago-tooltip
+ :time="lastReply.createdAt"
+ tooltip-placement="bottom"
+ class="gl-text-gray-700"
+ />
+ </template>
+ </li>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/design_overlay.vue b/app/assets/javascripts/design_management_new/components/design_overlay.vue
new file mode 100644
index 00000000000..926e7c74802
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/design_overlay.vue
@@ -0,0 +1,287 @@
+<script>
+import activeDiscussionQuery from '../graphql/queries/active_discussion.query.graphql';
+import updateActiveDiscussionMutation from '../graphql/mutations/update_active_discussion.mutation.graphql';
+import DesignNotePin from './design_note_pin.vue';
+import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../constants';
+
+export default {
+ name: 'DesignOverlay',
+ components: {
+ DesignNotePin,
+ },
+ props: {
+ dimensions: {
+ type: Object,
+ required: true,
+ },
+ position: {
+ type: Object,
+ required: true,
+ },
+ notes: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ currentCommentForm: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ disableCommenting: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ resolvedDiscussionsExpanded: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ apollo: {
+ activeDiscussion: {
+ query: activeDiscussionQuery,
+ },
+ },
+ data() {
+ return {
+ movingNoteNewPosition: null,
+ movingNoteStartPosition: null,
+ activeDiscussion: {},
+ };
+ },
+ computed: {
+ overlayStyle() {
+ const cursor = this.disableCommenting ? 'unset' : undefined;
+
+ return {
+ cursor,
+ width: `${this.dimensions.width}px`,
+ height: `${this.dimensions.height}px`,
+ ...this.position,
+ };
+ },
+ isMovingCurrentComment() {
+ return Boolean(this.movingNoteStartPosition && !this.movingNoteStartPosition.noteId);
+ },
+ currentCommentPositionStyle() {
+ return this.isMovingCurrentComment && this.movingNoteNewPosition
+ ? this.getNotePositionStyle(this.movingNoteNewPosition)
+ : this.getNotePositionStyle(this.currentCommentForm);
+ },
+ },
+ methods: {
+ setNewNoteCoordinates({ x, y }) {
+ this.$emit('openCommentForm', { x, y });
+ },
+ getNoteRelativePosition(position) {
+ const { x, y, width, height } = position;
+ const widthRatio = this.dimensions.width / width;
+ const heightRatio = this.dimensions.height / height;
+ return {
+ left: Math.round(x * widthRatio),
+ top: Math.round(y * heightRatio),
+ };
+ },
+ getNotePositionStyle(position) {
+ const { left, top } = this.getNoteRelativePosition(position);
+ return {
+ left: `${left}px`,
+ top: `${top}px`,
+ };
+ },
+ getMovingNotePositionDelta(e) {
+ let deltaX = 0;
+ let deltaY = 0;
+
+ if (this.movingNoteStartPosition) {
+ const { clientX, clientY } = this.movingNoteStartPosition;
+ deltaX = e.clientX - clientX;
+ deltaY = e.clientY - clientY;
+ }
+
+ return {
+ deltaX,
+ deltaY,
+ };
+ },
+ isMovingNote(noteId) {
+ const movingNoteId = this.movingNoteStartPosition?.noteId;
+ return Boolean(movingNoteId && movingNoteId === noteId);
+ },
+ canMoveNote(note) {
+ const { userPermissions } = note;
+ const { adminNote } = userPermissions || {};
+
+ return Boolean(adminNote);
+ },
+ isPositionInOverlay(position) {
+ const { top, left } = this.getNoteRelativePosition(position);
+ const { height, width } = this.dimensions;
+
+ return top >= 0 && top <= height && left >= 0 && left <= width;
+ },
+ onNewNoteMove(e) {
+ if (!this.isMovingCurrentComment) return;
+
+ const { deltaX, deltaY } = this.getMovingNotePositionDelta(e);
+ const x = this.currentCommentForm.x + deltaX;
+ const y = this.currentCommentForm.y + deltaY;
+
+ const movingNoteNewPosition = {
+ x,
+ y,
+ width: this.dimensions.width,
+ height: this.dimensions.height,
+ };
+
+ if (!this.isPositionInOverlay(movingNoteNewPosition)) {
+ this.onNewNoteMouseup();
+ return;
+ }
+
+ this.movingNoteNewPosition = movingNoteNewPosition;
+ },
+ onExistingNoteMove(e) {
+ const note = this.notes.find(({ id }) => id === this.movingNoteStartPosition.noteId);
+ if (!note || !this.canMoveNote(note)) return;
+
+ const { position } = note;
+ const { width, height } = position;
+ const widthRatio = this.dimensions.width / width;
+ const heightRatio = this.dimensions.height / height;
+
+ const { deltaX, deltaY } = this.getMovingNotePositionDelta(e);
+ const x = position.x * widthRatio + deltaX;
+ const y = position.y * heightRatio + deltaY;
+
+ const movingNoteNewPosition = {
+ x,
+ y,
+ width: this.dimensions.width,
+ height: this.dimensions.height,
+ };
+
+ if (!this.isPositionInOverlay(movingNoteNewPosition)) {
+ this.onExistingNoteMouseup();
+ return;
+ }
+
+ this.movingNoteNewPosition = movingNoteNewPosition;
+ },
+ onNewNoteMouseup() {
+ if (!this.movingNoteNewPosition) return;
+
+ const { x, y } = this.movingNoteNewPosition;
+ this.setNewNoteCoordinates({ x, y });
+ },
+ onExistingNoteMouseup(note) {
+ if (!this.movingNoteStartPosition || !this.movingNoteNewPosition) {
+ this.updateActiveDiscussion(note.id);
+ this.$emit('closeCommentForm');
+ return;
+ }
+
+ const { x, y } = this.movingNoteNewPosition;
+ this.$emit('moveNote', {
+ noteId: this.movingNoteStartPosition.noteId,
+ discussionId: this.movingNoteStartPosition.discussionId,
+ coordinates: { x, y },
+ });
+ },
+ onNoteMousedown({ clientX, clientY }, note) {
+ this.movingNoteStartPosition = {
+ noteId: note?.id,
+ discussionId: note?.discussion.id,
+ clientX,
+ clientY,
+ };
+ },
+ onOverlayMousemove(e) {
+ if (!this.movingNoteStartPosition) return;
+
+ if (this.isMovingCurrentComment) {
+ this.onNewNoteMove(e);
+ } else {
+ this.onExistingNoteMove(e);
+ }
+ },
+ onNoteMouseup(note) {
+ if (!this.movingNoteStartPosition) return;
+
+ if (this.isMovingCurrentComment) {
+ this.onNewNoteMouseup();
+ } else {
+ this.onExistingNoteMouseup(note);
+ }
+
+ this.movingNoteStartPosition = null;
+ this.movingNoteNewPosition = null;
+ },
+ onAddCommentMouseup({ offsetX, offsetY }) {
+ if (this.disableCommenting) return;
+ if (this.activeDiscussion.id) {
+ this.updateActiveDiscussion();
+ }
+
+ this.setNewNoteCoordinates({ x: offsetX, y: offsetY });
+ },
+ updateActiveDiscussion(id) {
+ this.$apollo.mutate({
+ mutation: updateActiveDiscussionMutation,
+ variables: {
+ id,
+ source: ACTIVE_DISCUSSION_SOURCE_TYPES.pin,
+ },
+ });
+ },
+ isNoteInactive(note) {
+ return this.activeDiscussion.id && this.activeDiscussion.id !== note.id;
+ },
+ designPinClass(note) {
+ return { inactive: this.isNoteInactive(note), resolved: note.resolved };
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ class="position-absolute image-diff-overlay frame"
+ :style="overlayStyle"
+ @mousemove="onOverlayMousemove"
+ @mouseleave="onNoteMouseup"
+ >
+ <button
+ v-show="!disableCommenting"
+ type="button"
+ class="btn-transparent position-absolute image-diff-overlay-add-comment w-100 h-100 js-add-image-diff-note-button"
+ data-qa-selector="design_image_button"
+ @mouseup="onAddCommentMouseup"
+ ></button>
+ <template v-for="note in notes">
+ <design-note-pin
+ v-if="resolvedDiscussionsExpanded || !note.resolved"
+ :key="note.id"
+ :label="note.index"
+ :repositioning="isMovingNote(note.id)"
+ :position="
+ isMovingNote(note.id) && movingNoteNewPosition
+ ? getNotePositionStyle(movingNoteNewPosition)
+ : getNotePositionStyle(note.position)
+ "
+ :class="designPinClass(note)"
+ @mousedown.stop="onNoteMousedown($event, note)"
+ @mouseup.stop="onNoteMouseup(note)"
+ />
+ </template>
+
+ <design-note-pin
+ v-if="currentCommentForm"
+ :position="currentCommentPositionStyle"
+ :repositioning="isMovingCurrentComment"
+ @mousedown.stop="onNoteMousedown"
+ @mouseup.stop="onNoteMouseup"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/design_presentation.vue b/app/assets/javascripts/design_management_new/components/design_presentation.vue
new file mode 100644
index 00000000000..84dbb2809d9
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/design_presentation.vue
@@ -0,0 +1,322 @@
+<script>
+import { throttle } from 'lodash';
+import DesignImage from './image.vue';
+import DesignOverlay from './design_overlay.vue';
+
+const CLICK_DRAG_BUFFER_PX = 2;
+
+export default {
+ components: {
+ DesignImage,
+ DesignOverlay,
+ },
+ props: {
+ image: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ imageName: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ discussions: {
+ type: Array,
+ required: true,
+ },
+ isAnnotating: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ scale: {
+ type: Number,
+ required: false,
+ default: 1,
+ },
+ resolvedDiscussionsExpanded: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ overlayDimensions: null,
+ overlayPosition: null,
+ currentAnnotationPosition: null,
+ zoomFocalPoint: {
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0,
+ },
+ initialLoad: true,
+ lastDragPosition: null,
+ isDraggingDesign: false,
+ };
+ },
+ computed: {
+ discussionStartingNotes() {
+ return this.discussions.map(discussion => ({
+ ...discussion.notes[0],
+ index: discussion.index,
+ }));
+ },
+ currentCommentForm() {
+ return (this.isAnnotating && this.currentAnnotationPosition) || null;
+ },
+ presentationStyle() {
+ return {
+ cursor: this.isDraggingDesign ? 'grabbing' : undefined,
+ };
+ },
+ },
+ beforeDestroy() {
+ const { presentationViewport } = this.$refs;
+ if (!presentationViewport) return;
+
+ presentationViewport.removeEventListener('scroll', this.scrollThrottled, false);
+ },
+ mounted() {
+ const { presentationViewport } = this.$refs;
+ if (!presentationViewport) return;
+
+ this.scrollThrottled = throttle(() => {
+ this.shiftZoomFocalPoint();
+ }, 400);
+
+ presentationViewport.addEventListener('scroll', this.scrollThrottled, false);
+ },
+ methods: {
+ syncCurrentAnnotationPosition() {
+ if (!this.currentAnnotationPosition) return;
+
+ const widthRatio = this.overlayDimensions.width / this.currentAnnotationPosition.width;
+ const heightRatio = this.overlayDimensions.height / this.currentAnnotationPosition.height;
+ const x = this.currentAnnotationPosition.x * widthRatio;
+ const y = this.currentAnnotationPosition.y * heightRatio;
+
+ this.currentAnnotationPosition = this.getAnnotationPositon({ x, y });
+ },
+ setOverlayDimensions(overlayDimensions) {
+ this.overlayDimensions = overlayDimensions;
+
+ // every time we set overlay dimensions, we need to
+ // update the current annotation as well
+ this.syncCurrentAnnotationPosition();
+ },
+ setOverlayPosition() {
+ if (!this.overlayDimensions) {
+ this.overlayPosition = {};
+ }
+
+ const { presentationViewport } = this.$refs;
+ if (!presentationViewport) return;
+
+ // default to center
+ this.overlayPosition = {
+ left: `calc(50% - ${this.overlayDimensions.width / 2}px)`,
+ top: `calc(50% - ${this.overlayDimensions.height / 2}px)`,
+ };
+
+ // if the overlay overflows, then don't center
+ if (this.overlayDimensions.width > presentationViewport.offsetWidth) {
+ this.overlayPosition.left = '0';
+ }
+ if (this.overlayDimensions.height > presentationViewport.offsetHeight) {
+ this.overlayPosition.top = '0';
+ }
+ },
+ /**
+ * Return a point that represents the center of an
+ * overflowing child element w.r.t it's parent
+ */
+ getViewportCenter() {
+ const { presentationViewport } = this.$refs;
+ if (!presentationViewport) return {};
+
+ // get height of scroll bars (i.e. the max values for scrollTop, scrollLeft)
+ const scrollBarWidth = presentationViewport.scrollWidth - presentationViewport.offsetWidth;
+ const scrollBarHeight = presentationViewport.scrollHeight - presentationViewport.offsetHeight;
+
+ // determine how many child pixels have been scrolled
+ const xScrollRatio =
+ presentationViewport.scrollLeft > 0 ? presentationViewport.scrollLeft / scrollBarWidth : 0;
+ const yScrollRatio =
+ presentationViewport.scrollTop > 0 ? presentationViewport.scrollTop / scrollBarHeight : 0;
+ const xScrollOffset =
+ (presentationViewport.scrollWidth - presentationViewport.offsetWidth - 0) * xScrollRatio;
+ const yScrollOffset =
+ (presentationViewport.scrollHeight - presentationViewport.offsetHeight - 0) * yScrollRatio;
+
+ const viewportCenterX = presentationViewport.offsetWidth / 2;
+ const viewportCenterY = presentationViewport.offsetHeight / 2;
+ const focalPointX = viewportCenterX + xScrollOffset;
+ const focalPointY = viewportCenterY + yScrollOffset;
+
+ return {
+ x: focalPointX,
+ y: focalPointY,
+ };
+ },
+ /**
+ * Scroll the viewport such that the focal point is positioned centrally
+ */
+ scrollToFocalPoint() {
+ const { presentationViewport } = this.$refs;
+ if (!presentationViewport) return;
+
+ const scrollX = this.zoomFocalPoint.x - presentationViewport.offsetWidth / 2;
+ const scrollY = this.zoomFocalPoint.y - presentationViewport.offsetHeight / 2;
+
+ presentationViewport.scrollTo(scrollX, scrollY);
+ },
+ scaleZoomFocalPoint() {
+ const { x, y, width, height } = this.zoomFocalPoint;
+ const widthRatio = this.overlayDimensions.width / width;
+ const heightRatio = this.overlayDimensions.height / height;
+
+ this.zoomFocalPoint = {
+ x: Math.round(x * widthRatio * 100) / 100,
+ y: Math.round(y * heightRatio * 100) / 100,
+ ...this.overlayDimensions,
+ };
+ },
+ shiftZoomFocalPoint() {
+ this.zoomFocalPoint = {
+ ...this.getViewportCenter(),
+ ...this.overlayDimensions,
+ };
+ },
+ onImageResize(imageDimensions) {
+ this.setOverlayDimensions(imageDimensions);
+ this.setOverlayPosition();
+
+ this.$nextTick(() => {
+ if (this.initialLoad) {
+ // set focal point on initial load
+ this.shiftZoomFocalPoint();
+ this.initialLoad = false;
+ } else {
+ this.scaleZoomFocalPoint();
+ this.scrollToFocalPoint();
+ }
+ });
+ },
+ getAnnotationPositon(coordinates) {
+ const { x, y } = coordinates;
+ const { width, height } = this.overlayDimensions;
+ return {
+ x: Math.round(x),
+ y: Math.round(y),
+ width: Math.round(width),
+ height: Math.round(height),
+ };
+ },
+ openCommentForm(coordinates) {
+ this.currentAnnotationPosition = this.getAnnotationPositon(coordinates);
+ this.$emit('openCommentForm', this.currentAnnotationPosition);
+ },
+ closeCommentForm() {
+ this.currentAnnotationPosition = null;
+ this.$emit('closeCommentForm');
+ },
+ moveNote({ noteId, discussionId, coordinates }) {
+ const position = this.getAnnotationPositon(coordinates);
+ this.$emit('moveNote', { noteId, discussionId, position });
+ },
+ onPresentationMousedown({ clientX, clientY }) {
+ if (!this.isDesignOverflowing()) return;
+
+ this.lastDragPosition = {
+ x: clientX,
+ y: clientY,
+ };
+ },
+ getDragDelta(clientX, clientY) {
+ return {
+ deltaX: this.lastDragPosition.x - clientX,
+ deltaY: this.lastDragPosition.y - clientY,
+ };
+ },
+ exceedsDragThreshold(clientX, clientY) {
+ const { deltaX, deltaY } = this.getDragDelta(clientX, clientY);
+
+ return Math.abs(deltaX) > CLICK_DRAG_BUFFER_PX || Math.abs(deltaY) > CLICK_DRAG_BUFFER_PX;
+ },
+ shouldDragDesign(clientX, clientY) {
+ return (
+ this.lastDragPosition &&
+ (this.isDraggingDesign || this.exceedsDragThreshold(clientX, clientY))
+ );
+ },
+ onPresentationMousemove({ clientX, clientY }) {
+ const { presentationViewport } = this.$refs;
+ if (!presentationViewport || !this.shouldDragDesign(clientX, clientY)) return;
+
+ this.isDraggingDesign = true;
+
+ const { scrollLeft, scrollTop } = presentationViewport;
+ const { deltaX, deltaY } = this.getDragDelta(clientX, clientY);
+ presentationViewport.scrollTo(scrollLeft + deltaX, scrollTop + deltaY);
+
+ this.lastDragPosition = {
+ x: clientX,
+ y: clientY,
+ };
+ },
+ onPresentationMouseup() {
+ this.lastDragPosition = null;
+ this.isDraggingDesign = false;
+ },
+ isDesignOverflowing() {
+ const { presentationViewport } = this.$refs;
+ if (!presentationViewport) return false;
+
+ return (
+ presentationViewport.scrollWidth > presentationViewport.offsetWidth ||
+ presentationViewport.scrollHeight > presentationViewport.offsetHeight
+ );
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ ref="presentationViewport"
+ class="h-100 w-100 p-3 overflow-auto position-relative"
+ :style="presentationStyle"
+ @mousedown="onPresentationMousedown"
+ @mousemove="onPresentationMousemove"
+ @mouseup="onPresentationMouseup"
+ @mouseleave="onPresentationMouseup"
+ @touchstart="onPresentationMousedown"
+ @touchmove="onPresentationMousemove"
+ @touchend="onPresentationMouseup"
+ @touchcancel="onPresentationMouseup"
+ >
+ <div class="h-100 w-100 d-flex align-items-center position-relative">
+ <design-image
+ v-if="image"
+ :image="image"
+ :name="imageName"
+ :scale="scale"
+ @resize="onImageResize"
+ />
+ <design-overlay
+ v-if="overlayDimensions && overlayPosition"
+ :dimensions="overlayDimensions"
+ :position="overlayPosition"
+ :notes="discussionStartingNotes"
+ :current-comment-form="currentCommentForm"
+ :disable-commenting="isDraggingDesign"
+ :resolved-discussions-expanded="resolvedDiscussionsExpanded"
+ @openCommentForm="openCommentForm"
+ @closeCommentForm="closeCommentForm"
+ @moveNote="moveNote"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/design_scaler.vue b/app/assets/javascripts/design_management_new/components/design_scaler.vue
new file mode 100644
index 00000000000..55dee74bef5
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/design_scaler.vue
@@ -0,0 +1,65 @@
+<script>
+import { GlIcon } from '@gitlab/ui';
+
+const SCALE_STEP_SIZE = 0.2;
+const DEFAULT_SCALE = 1;
+const MIN_SCALE = 1;
+const MAX_SCALE = 2;
+
+export default {
+ components: {
+ GlIcon,
+ },
+ data() {
+ return {
+ scale: DEFAULT_SCALE,
+ };
+ },
+ computed: {
+ disableReset() {
+ return this.scale <= MIN_SCALE;
+ },
+ disableDecrease() {
+ return this.scale === DEFAULT_SCALE;
+ },
+ disableIncrease() {
+ return this.scale >= MAX_SCALE;
+ },
+ },
+ methods: {
+ setScale(scale) {
+ if (scale < MIN_SCALE) {
+ return;
+ }
+
+ this.scale = Math.round(scale * 100) / 100;
+ this.$emit('scale', this.scale);
+ },
+ incrementScale() {
+ this.setScale(this.scale + SCALE_STEP_SIZE);
+ },
+ decrementScale() {
+ this.setScale(this.scale - SCALE_STEP_SIZE);
+ },
+ resetScale() {
+ this.setScale(DEFAULT_SCALE);
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="design-scaler btn-group" role="group">
+ <button class="btn" :disabled="disableDecrease" @click="decrementScale">
+ <span class="d-flex-center gl-icon s16">
+ –
+ </span>
+ </button>
+ <button class="btn" :disabled="disableReset" @click="resetScale">
+ <gl-icon name="redo" />
+ </button>
+ <button class="btn" :disabled="disableIncrease" @click="incrementScale">
+ <gl-icon name="plus" />
+ </button>
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/design_sidebar.vue b/app/assets/javascripts/design_management_new/components/design_sidebar.vue
new file mode 100644
index 00000000000..333ad2557e8
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/design_sidebar.vue
@@ -0,0 +1,178 @@
+<script>
+import { s__ } from '~/locale';
+import Cookies from 'js-cookie';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import { GlCollapse, GlButton, GlPopover } from '@gitlab/ui';
+import updateActiveDiscussionMutation from '../graphql/mutations/update_active_discussion.mutation.graphql';
+import { extractDiscussions, extractParticipants } from '../utils/design_management_utils';
+import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../constants';
+import DesignDiscussion from './design_notes/design_discussion.vue';
+import Participants from '~/sidebar/components/participants/participants.vue';
+
+export default {
+ components: {
+ DesignDiscussion,
+ Participants,
+ GlCollapse,
+ GlButton,
+ GlPopover,
+ },
+ props: {
+ design: {
+ type: Object,
+ required: true,
+ },
+ resolvedDiscussionsExpanded: {
+ type: Boolean,
+ required: true,
+ },
+ markdownPreviewPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isResolvedCommentsPopoverHidden: parseBoolean(Cookies.get(this.$options.cookieKey)),
+ discussionWithOpenForm: '',
+ };
+ },
+ computed: {
+ discussions() {
+ return extractDiscussions(this.design.discussions);
+ },
+ issue() {
+ return {
+ ...this.design.issue,
+ webPath: this.design.issue.webPath.substr(1),
+ };
+ },
+ discussionParticipants() {
+ return extractParticipants(this.issue.participants);
+ },
+ resolvedDiscussions() {
+ return this.discussions.filter(discussion => discussion.resolved);
+ },
+ unresolvedDiscussions() {
+ return this.discussions.filter(discussion => !discussion.resolved);
+ },
+ resolvedCommentsToggleIcon() {
+ return this.resolvedDiscussionsExpanded ? 'chevron-down' : 'chevron-right';
+ },
+ },
+ methods: {
+ handleSidebarClick() {
+ this.isResolvedCommentsPopoverHidden = true;
+ Cookies.set(this.$options.cookieKey, 'true', { expires: 365 * 10 });
+ this.updateActiveDiscussion();
+ },
+ updateActiveDiscussion(id) {
+ this.$apollo.mutate({
+ mutation: updateActiveDiscussionMutation,
+ variables: {
+ id,
+ source: ACTIVE_DISCUSSION_SOURCE_TYPES.discussion,
+ },
+ });
+ },
+ closeCommentForm() {
+ this.comment = '';
+ this.$emit('closeCommentForm');
+ },
+ updateDiscussionWithOpenForm(id) {
+ this.discussionWithOpenForm = id;
+ },
+ },
+ resolveCommentsToggleText: s__('DesignManagement|Resolved Comments'),
+ cookieKey: 'hide_design_resolved_comments_popover',
+};
+</script>
+
+<template>
+ <div class="image-notes" @click="handleSidebarClick">
+ <h2 class="gl-font-weight-bold gl-mt-0">
+ {{ issue.title }}
+ </h2>
+ <a
+ class="gl-text-gray-600 gl-text-decoration-none gl-mb-6 gl-display-block"
+ :href="issue.webUrl"
+ >{{ issue.webPath }}</a
+ >
+ <participants
+ :participants="discussionParticipants"
+ :show-participant-label="false"
+ class="gl-mb-4"
+ />
+ <h2
+ v-if="unresolvedDiscussions.length === 0"
+ class="new-discussion-disclaimer gl-font-base gl-m-0 gl-mb-4"
+ data-testid="new-discussion-disclaimer"
+ >
+ {{ s__("DesignManagement|Click the image where you'd like to start a new discussion") }}
+ </h2>
+ <design-discussion
+ v-for="discussion in unresolvedDiscussions"
+ :key="discussion.id"
+ :discussion="discussion"
+ :design-id="$route.params.id"
+ :noteable-id="design.id"
+ :markdown-preview-path="markdownPreviewPath"
+ :resolved-discussions-expanded="resolvedDiscussionsExpanded"
+ :discussion-with-open-form="discussionWithOpenForm"
+ data-testid="unresolved-discussion"
+ @createNoteError="$emit('onDesignDiscussionError', $event)"
+ @updateNoteError="$emit('updateNoteError', $event)"
+ @resolveDiscussionError="$emit('resolveDiscussionError', $event)"
+ @click.native.stop="updateActiveDiscussion(discussion.notes[0].id)"
+ @openForm="updateDiscussionWithOpenForm"
+ />
+ <template v-if="resolvedDiscussions.length > 0">
+ <gl-button
+ id="resolved-comments"
+ data-testid="resolved-comments"
+ :icon="resolvedCommentsToggleIcon"
+ variant="link"
+ class="link-inherit-color gl-text-black-normal gl-text-decoration-none gl-font-weight-bold gl-mb-4"
+ @click="$emit('toggleResolvedComments')"
+ >{{ $options.resolveCommentsToggleText }} ({{ resolvedDiscussions.length }})
+ </gl-button>
+ <gl-popover
+ v-if="!isResolvedCommentsPopoverHidden"
+ :show="!isResolvedCommentsPopoverHidden"
+ target="resolved-comments"
+ container="popovercontainer"
+ placement="top"
+ :title="s__('DesignManagement|Resolved Comments')"
+ >
+ <p>
+ {{
+ s__(
+ 'DesignManagement|Comments you resolve can be viewed and unresolved by going to the "Resolved Comments" section below',
+ )
+ }}
+ </p>
+ <a href="#" rel="noopener noreferrer" target="_blank">{{
+ s__('DesignManagement|Learn more about resolving comments')
+ }}</a>
+ </gl-popover>
+ <gl-collapse :visible="resolvedDiscussionsExpanded" class="gl-mt-3">
+ <design-discussion
+ v-for="discussion in resolvedDiscussions"
+ :key="discussion.id"
+ :discussion="discussion"
+ :design-id="$route.params.id"
+ :noteable-id="design.id"
+ :markdown-preview-path="markdownPreviewPath"
+ :resolved-discussions-expanded="resolvedDiscussionsExpanded"
+ :discussion-with-open-form="discussionWithOpenForm"
+ data-testid="resolved-discussion"
+ @error="$emit('onDesignDiscussionError', $event)"
+ @updateNoteError="$emit('updateNoteError', $event)"
+ @openForm="updateDiscussionWithOpenForm"
+ @click.native.stop="updateActiveDiscussion(discussion.notes[0].id)"
+ />
+ </gl-collapse>
+ </template>
+ <slot name="replyForm"></slot>
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/image.vue b/app/assets/javascripts/design_management_new/components/image.vue
new file mode 100644
index 00000000000..91b7b576e0c
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/image.vue
@@ -0,0 +1,110 @@
+<script>
+import { throttle } from 'lodash';
+import { GlIcon } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlIcon,
+ },
+ props: {
+ image: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ name: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ scale: {
+ type: Number,
+ required: false,
+ default: 1,
+ },
+ },
+ data() {
+ return {
+ baseImageSize: null,
+ imageStyle: null,
+ imageError: false,
+ };
+ },
+ watch: {
+ scale(val) {
+ this.zoom(val);
+ },
+ },
+ beforeDestroy() {
+ window.removeEventListener('resize', this.resizeThrottled, false);
+ },
+ mounted() {
+ this.onImgLoad();
+
+ this.resizeThrottled = throttle(() => {
+ // NOTE: if imageStyle is set, then baseImageSize
+ // won't change due to resize. We must still emit a
+ // `resize` event so that the parent can handle
+ // resizes appropriately (e.g. for design_overlay)
+ this.setBaseImageSize();
+ }, 400);
+ window.addEventListener('resize', this.resizeThrottled, false);
+ },
+ methods: {
+ onImgLoad() {
+ requestIdleCallback(this.setBaseImageSize, { timeout: 1000 });
+ },
+ onImgError() {
+ this.imageError = true;
+ },
+ setBaseImageSize() {
+ const { contentImg } = this.$refs;
+ if (!contentImg || contentImg.offsetHeight === 0 || contentImg.offsetWidth === 0) return;
+
+ this.baseImageSize = {
+ height: contentImg.offsetHeight,
+ width: contentImg.offsetWidth,
+ };
+ this.onResize({ width: this.baseImageSize.width, height: this.baseImageSize.height });
+ },
+ onResize({ width, height }) {
+ this.$emit('resize', { width, height });
+ },
+ zoom(amount) {
+ if (amount === 1) {
+ this.imageStyle = null;
+ this.$nextTick(() => {
+ this.setBaseImageSize();
+ });
+ return;
+ }
+ const width = this.baseImageSize.width * amount;
+ const height = this.baseImageSize.height * amount;
+
+ this.imageStyle = {
+ width: `${width}px`,
+ height: `${height}px`,
+ };
+
+ this.onResize({ width, height });
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="m-auto js-design-image">
+ <gl-icon v-if="imageError" class="text-secondary-100" name="media-broken" :size="48" />
+ <img
+ v-show="!imageError"
+ ref="contentImg"
+ class="mh-100"
+ :src="image"
+ :alt="name"
+ :style="imageStyle"
+ :class="{ 'img-fluid': !imageStyle }"
+ @error="onImgError"
+ @load="onImgLoad"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/list/item.vue b/app/assets/javascripts/design_management_new/components/list/item.vue
new file mode 100644
index 00000000000..eaa641d85d6
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/list/item.vue
@@ -0,0 +1,174 @@
+<script>
+import { GlLoadingIcon, GlIcon, GlIntersectionObserver } from '@gitlab/ui';
+import Icon from '~/vue_shared/components/icon.vue';
+import Timeago from '~/vue_shared/components/time_ago_tooltip.vue';
+import { n__, __ } from '~/locale';
+import { DESIGN_ROUTE_NAME } from '../../router/constants';
+
+export default {
+ components: {
+ GlLoadingIcon,
+ GlIntersectionObserver,
+ GlIcon,
+ Icon,
+ Timeago,
+ },
+ props: {
+ id: {
+ type: [Number, String],
+ required: true,
+ },
+ event: {
+ type: String,
+ required: true,
+ },
+ notesCount: {
+ type: Number,
+ required: true,
+ },
+ image: {
+ type: String,
+ required: true,
+ },
+ filename: {
+ type: String,
+ required: true,
+ },
+ updatedAt: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ isUploading: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ imageV432x230: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ imageLoading: true,
+ imageError: false,
+ wasInView: false,
+ };
+ },
+ computed: {
+ icon() {
+ const normalizedEvent = this.event.toLowerCase();
+ const icons = {
+ creation: {
+ name: 'file-addition-solid',
+ classes: 'text-success-500',
+ tooltip: __('Added in this version'),
+ },
+ modification: {
+ name: 'file-modified-solid',
+ classes: 'text-primary-500',
+ tooltip: __('Modified in this version'),
+ },
+ deletion: {
+ name: 'file-deletion-solid',
+ classes: 'text-danger-500',
+ tooltip: __('Deleted in this version'),
+ },
+ };
+
+ return icons[normalizedEvent] ? icons[normalizedEvent] : {};
+ },
+ notesLabel() {
+ return n__('%d comment', '%d comments', this.notesCount);
+ },
+ imageLink() {
+ return this.wasInView ? this.imageV432x230 || this.image : '';
+ },
+ showLoadingSpinner() {
+ return this.imageLoading || this.isUploading;
+ },
+ showImageErrorIcon() {
+ return this.wasInView && this.imageError;
+ },
+ showImage() {
+ return !this.showLoadingSpinner && !this.showImageErrorIcon;
+ },
+ },
+ methods: {
+ onImageLoad() {
+ this.imageLoading = false;
+ this.imageError = false;
+ },
+ onImageError() {
+ this.imageLoading = false;
+ this.imageError = true;
+ },
+ onAppear() {
+ // do nothing if image has previously
+ // been in view
+ if (this.wasInView) {
+ return;
+ }
+
+ this.wasInView = true;
+ this.imageLoading = true;
+ },
+ },
+ DESIGN_ROUTE_NAME,
+};
+</script>
+
+<template>
+ <router-link
+ :to="{
+ name: $options.DESIGN_ROUTE_NAME,
+ params: { id: filename },
+ query: $route.query,
+ }"
+ class="card cursor-pointer text-plain js-design-list-item design-list-item"
+ >
+ <div class="card-body p-0 d-flex-center overflow-hidden position-relative">
+ <div v-if="icon.name" class="design-event position-absolute">
+ <span :title="icon.tooltip" :aria-label="icon.tooltip">
+ <icon :name="icon.name" :size="18" :class="icon.classes" />
+ </span>
+ </div>
+ <gl-intersection-observer @appear="onAppear">
+ <gl-loading-icon v-if="showLoadingSpinner" size="md" />
+ <gl-icon
+ v-else-if="showImageErrorIcon"
+ name="media-broken"
+ class="text-secondary"
+ :size="32"
+ />
+ <img
+ v-show="showImage"
+ :src="imageLink"
+ :alt="filename"
+ class="block mx-auto mw-100 mh-100 design-img"
+ data-qa-selector="design_image"
+ @load="onImageLoad"
+ @error="onImageError"
+ />
+ </gl-intersection-observer>
+ </div>
+ <div class="card-footer d-flex w-100">
+ <div class="d-flex flex-column str-truncated-100">
+ <span class="bold str-truncated-100" data-qa-selector="design_file_name">{{
+ filename
+ }}</span>
+ <span v-if="updatedAt" class="str-truncated-100">
+ {{ __('Updated') }} <timeago :time="updatedAt" tooltip-placement="bottom" />
+ </span>
+ </div>
+ <div v-if="notesCount" class="ml-auto d-flex align-items-center text-secondary">
+ <icon name="comments" class="ml-1" />
+ <span :aria-label="notesLabel" class="ml-1">
+ {{ notesCount }}
+ </span>
+ </div>
+ </div>
+ </router-link>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/toolbar/index.vue b/app/assets/javascripts/design_management_new/components/toolbar/index.vue
new file mode 100644
index 00000000000..b998dfc47b8
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/toolbar/index.vue
@@ -0,0 +1,126 @@
+<script>
+import { GlDeprecatedButton } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
+import Icon from '~/vue_shared/components/icon.vue';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
+import Pagination from './pagination.vue';
+import DeleteButton from '../delete_button.vue';
+import permissionsQuery from '../../graphql/queries/design_permissions.query.graphql';
+import appDataQuery from '../../graphql/queries/app_data.query.graphql';
+import { DESIGNS_ROUTE_NAME } from '../../router/constants';
+
+export default {
+ components: {
+ Icon,
+ Pagination,
+ DeleteButton,
+ GlDeprecatedButton,
+ },
+ mixins: [timeagoMixin],
+ props: {
+ id: {
+ type: String,
+ required: true,
+ },
+ isDeleting: {
+ type: Boolean,
+ required: true,
+ },
+ filename: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ updatedAt: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ updatedBy: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ isLatestVersion: {
+ type: Boolean,
+ required: true,
+ },
+ image: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ permissions: {
+ createDesign: false,
+ },
+ projectPath: '',
+ issueIid: null,
+ };
+ },
+ apollo: {
+ appData: {
+ query: appDataQuery,
+ manual: true,
+ result({ data: { projectPath, issueIid } }) {
+ this.projectPath = projectPath;
+ this.issueIid = issueIid;
+ },
+ },
+ permissions: {
+ query: permissionsQuery,
+ variables() {
+ return {
+ fullPath: this.projectPath,
+ iid: this.issueIid,
+ };
+ },
+ update: data => data.project.issue.userPermissions,
+ },
+ },
+ computed: {
+ updatedText() {
+ return sprintf(__('Updated %{updated_at} by %{updated_by}'), {
+ updated_at: this.timeFormatted(this.updatedAt),
+ updated_by: this.updatedBy.name,
+ });
+ },
+ canDeleteDesign() {
+ return this.permissions.createDesign;
+ },
+ },
+ DESIGNS_ROUTE_NAME,
+};
+</script>
+
+<template>
+ <header class="d-flex p-2 bg-white align-items-center js-design-header">
+ <router-link
+ :to="{
+ name: $options.DESIGNS_ROUTE_NAME,
+ query: $route.query,
+ }"
+ :aria-label="s__('DesignManagement|Go back to designs')"
+ class="mr-3 text-plain d-flex justify-content-center align-items-center"
+ >
+ <icon :size="18" name="close" />
+ </router-link>
+ <div class="overflow-hidden d-flex align-items-center">
+ <h2 class="m-0 str-truncated-100 gl-font-base">{{ filename }}</h2>
+ <small v-if="updatedAt" class="text-secondary">{{ updatedText }}</small>
+ </div>
+ <pagination :id="id" class="ml-auto flex-shrink-0" />
+ <gl-deprecated-button :href="image" class="mr-2">
+ <icon :size="18" name="download" />
+ </gl-deprecated-button>
+ <delete-button
+ v-if="isLatestVersion && canDeleteDesign"
+ :is-deleting="isDeleting"
+ button-variant="danger"
+ @deleteSelectedDesigns="$emit('delete')"
+ >
+ <icon :size="18" name="remove" />
+ </delete-button>
+ </header>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/toolbar/pagination.vue b/app/assets/javascripts/design_management_new/components/toolbar/pagination.vue
new file mode 100644
index 00000000000..bf62a8f66a6
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/toolbar/pagination.vue
@@ -0,0 +1,83 @@
+<script>
+/* global Mousetrap */
+import 'mousetrap';
+import { s__, sprintf } from '~/locale';
+import PaginationButton from './pagination_button.vue';
+import allDesignsMixin from '../../mixins/all_designs';
+import { DESIGN_ROUTE_NAME } from '../../router/constants';
+
+export default {
+ components: {
+ PaginationButton,
+ },
+ mixins: [allDesignsMixin],
+ props: {
+ id: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ designsCount() {
+ return this.designs.length;
+ },
+ currentIndex() {
+ return this.designs.findIndex(design => design.filename === this.id);
+ },
+ paginationText() {
+ return sprintf(s__('DesignManagement|%{current_design} of %{designs_count}'), {
+ current_design: this.currentIndex + 1,
+ designs_count: this.designsCount,
+ });
+ },
+ previousDesign() {
+ if (!this.designsCount) return null;
+
+ return this.designs[this.currentIndex - 1];
+ },
+ nextDesign() {
+ if (!this.designsCount) return null;
+
+ return this.designs[this.currentIndex + 1];
+ },
+ },
+ mounted() {
+ Mousetrap.bind('left', () => this.navigateToDesign(this.previousDesign));
+ Mousetrap.bind('right', () => this.navigateToDesign(this.nextDesign));
+ },
+ beforeDestroy() {
+ Mousetrap.unbind(['left', 'right'], this.navigateToDesign);
+ },
+ methods: {
+ navigateToDesign(design) {
+ if (design) {
+ this.$router.push({
+ name: DESIGN_ROUTE_NAME,
+ params: { id: design.filename },
+ query: this.$route.query,
+ });
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div v-if="designsCount" class="d-flex align-items-center">
+ {{ paginationText }}
+ <div class="btn-group ml-3 mr-3">
+ <pagination-button
+ :design="previousDesign"
+ :title="s__('DesignManagement|Go to previous design')"
+ icon-name="angle-left"
+ class="js-previous-design"
+ />
+ <pagination-button
+ :design="nextDesign"
+ :title="s__('DesignManagement|Go to next design')"
+ icon-name="angle-right"
+ class="js-next-design"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/toolbar/pagination_button.vue b/app/assets/javascripts/design_management_new/components/toolbar/pagination_button.vue
new file mode 100644
index 00000000000..f00ecefca01
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/toolbar/pagination_button.vue
@@ -0,0 +1,48 @@
+<script>
+import Icon from '~/vue_shared/components/icon.vue';
+import { DESIGN_ROUTE_NAME } from '../../router/constants';
+
+export default {
+ components: {
+ Icon,
+ },
+ props: {
+ design: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ title: {
+ type: String,
+ required: true,
+ },
+ iconName: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ designLink() {
+ if (!this.design) return {};
+
+ return {
+ name: DESIGN_ROUTE_NAME,
+ params: { id: this.design.filename },
+ query: this.$route.query,
+ };
+ },
+ },
+};
+</script>
+
+<template>
+ <router-link
+ :to="designLink"
+ :disabled="!design"
+ :class="{ disabled: !design }"
+ :aria-label="title"
+ class="btn btn-default"
+ >
+ <icon :name="iconName" />
+ </router-link>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/upload/button.vue b/app/assets/javascripts/design_management_new/components/upload/button.vue
new file mode 100644
index 00000000000..68555104a3c
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/upload/button.vue
@@ -0,0 +1,58 @@
+<script>
+import { GlDeprecatedButton, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
+import { VALID_DESIGN_FILE_MIMETYPE } from '../../constants';
+
+export default {
+ components: {
+ GlDeprecatedButton,
+ GlLoadingIcon,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ isSaving: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ methods: {
+ openFileUpload() {
+ this.$refs.fileUpload.click();
+ },
+ onFileUploadChange(e) {
+ this.$emit('upload', e.target.files);
+ },
+ },
+ VALID_DESIGN_FILE_MIMETYPE,
+};
+</script>
+
+<template>
+ <div>
+ <gl-deprecated-button
+ v-gl-tooltip.hover
+ :title="
+ s__(
+ 'DesignManagement|Adding a design with the same filename replaces the file in a new version.',
+ )
+ "
+ :disabled="isSaving"
+ variant="success"
+ @click="openFileUpload"
+ >
+ {{ s__('DesignManagement|Upload designs') }}
+ <gl-loading-icon v-if="isSaving" inline class="ml-1" />
+ </gl-deprecated-button>
+
+ <input
+ ref="fileUpload"
+ type="file"
+ name="design_file"
+ :accept="$options.VALID_DESIGN_FILE_MIMETYPE.mimetype"
+ class="hide"
+ multiple
+ @change="onFileUploadChange"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/upload/design_dropzone.vue b/app/assets/javascripts/design_management_new/components/upload/design_dropzone.vue
new file mode 100644
index 00000000000..33261134c15
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/upload/design_dropzone.vue
@@ -0,0 +1,134 @@
+<script>
+import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
+import createFlash from '~/flash';
+import uploadDesignMutation from '../../graphql/mutations/upload_design.mutation.graphql';
+import { UPLOAD_DESIGN_INVALID_FILETYPE_ERROR } from '../../utils/error_messages';
+import { isValidDesignFile } from '../../utils/design_management_utils';
+import { VALID_DATA_TRANSFER_TYPE, VALID_DESIGN_FILE_MIMETYPE } from '../../constants';
+
+export default {
+ components: {
+ GlIcon,
+ GlLink,
+ GlSprintf,
+ },
+ data() {
+ return {
+ dragCounter: 0,
+ isDragDataValid: false,
+ };
+ },
+ computed: {
+ dragging() {
+ return this.dragCounter !== 0;
+ },
+ },
+ methods: {
+ isValidUpload(files) {
+ return files.every(isValidDesignFile);
+ },
+ isValidDragDataType({ dataTransfer }) {
+ return Boolean(dataTransfer && dataTransfer.types.some(t => t === VALID_DATA_TRANSFER_TYPE));
+ },
+ ondrop({ dataTransfer = {} }) {
+ this.dragCounter = 0;
+ // User already had feedback when dropzone was active, so bail here
+ if (!this.isDragDataValid) {
+ return;
+ }
+
+ const { files } = dataTransfer;
+ if (!this.isValidUpload(Array.from(files))) {
+ createFlash(UPLOAD_DESIGN_INVALID_FILETYPE_ERROR);
+ return;
+ }
+
+ this.$emit('change', files);
+ },
+ ondragenter(e) {
+ this.dragCounter += 1;
+ this.isDragDataValid = this.isValidDragDataType(e);
+ },
+ ondragleave() {
+ this.dragCounter -= 1;
+ },
+ openFileUpload() {
+ this.$refs.fileUpload.click();
+ },
+ onDesignInputChange(e) {
+ this.$emit('change', e.target.files);
+ },
+ },
+ uploadDesignMutation,
+ VALID_DESIGN_FILE_MIMETYPE,
+};
+</script>
+
+<template>
+ <div
+ class="w-100 position-relative"
+ @dragstart.prevent.stop
+ @dragend.prevent.stop
+ @dragover.prevent.stop
+ @dragenter.prevent.stop="ondragenter"
+ @dragleave.prevent.stop="ondragleave"
+ @drop.prevent.stop="ondrop"
+ >
+ <slot>
+ <button
+ class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
+ @click="openFileUpload"
+ >
+ <div class="d-flex-center flex-column text-center">
+ <gl-icon name="doc-new" :size="48" class="mb-4" />
+ <p>
+ <gl-sprintf
+ :message="
+ __(
+ '%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}.',
+ )
+ "
+ >
+ <template #lineOne="{ content }"
+ ><span class="d-block">{{ content }}</span>
+ </template>
+
+ <template #link="{ content }">
+ <gl-link class="h-100 w-100" @click.stop="openFileUpload">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </div>
+ </button>
+
+ <input
+ ref="fileUpload"
+ type="file"
+ name="design_file"
+ :accept="$options.VALID_DESIGN_FILE_MIMETYPE.mimetype"
+ class="hide"
+ multiple
+ @change="onDesignInputChange"
+ />
+ </slot>
+ <transition name="design-dropzone-fade">
+ <div
+ v-show="dragging"
+ class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ >
+ <div v-show="!isDragDataValid" class="mw-50 text-center">
+ <h3>{{ __('Oh no!') }}</h3>
+ <span>{{
+ __(
+ 'You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.',
+ )
+ }}</span>
+ </div>
+ <div v-show="isDragDataValid" class="mw-50 text-center">
+ <h3>{{ __('Incoming!') }}</h3>
+ <span>{{ __('Drop your designs to start your upload.') }}</span>
+ </div>
+ </div>
+ </transition>
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/components/upload/design_version_dropdown.vue b/app/assets/javascripts/design_management_new/components/upload/design_version_dropdown.vue
new file mode 100644
index 00000000000..993eac6f37f
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/components/upload/design_version_dropdown.vue
@@ -0,0 +1,76 @@
+<script>
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
+import allVersionsMixin from '../../mixins/all_versions';
+import { findVersionId } from '../../utils/design_management_utils';
+
+export default {
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ },
+ mixins: [allVersionsMixin],
+ computed: {
+ queryVersion() {
+ return this.$route.query.version;
+ },
+ currentVersionIdx() {
+ if (!this.queryVersion) return 0;
+
+ const idx = this.allVersions.findIndex(
+ version => this.findVersionId(version.node.id) === this.queryVersion,
+ );
+
+ // if the currentVersionId isn't a valid version (i.e. not in allVersions)
+ // then return the latest version (index 0)
+ return idx !== -1 ? idx : 0;
+ },
+ currentVersionId() {
+ if (this.queryVersion) return this.queryVersion;
+
+ const currentVersion = this.allVersions[this.currentVersionIdx];
+ return this.findVersionId(currentVersion.node.id);
+ },
+ dropdownText() {
+ if (this.isLatestVersion) {
+ return __('Showing Latest Version');
+ }
+ // allVersions is sorted in reverse chronological order (latest first)
+ const currentVersionNumber = this.allVersions.length - this.currentVersionIdx;
+
+ return sprintf(__('Showing Version #%{versionNumber}'), {
+ versionNumber: currentVersionNumber,
+ });
+ },
+ },
+ methods: {
+ findVersionId,
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown :text="dropdownText" variant="link" class="design-version-dropdown">
+ <gl-dropdown-item v-for="(version, index) in allVersions" :key="version.node.id">
+ <router-link
+ class="d-flex js-version-link"
+ :to="{ path: $route.path, query: { version: findVersionId(version.node.id) } }"
+ >
+ <div class="flex-grow-1 ml-2">
+ <div>
+ <strong
+ >{{ __('Version') }} {{ allVersions.length - index }}
+ <span v-if="findVersionId(version.node.id) === latestVersionId"
+ >({{ __('latest') }})</span
+ >
+ </strong>
+ </div>
+ </div>
+ <i
+ v-if="findVersionId(version.node.id) === currentVersionId"
+ class="fa fa-check pull-right"
+ ></i>
+ </router-link>
+ </gl-dropdown-item>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/design_management_new/constants.js b/app/assets/javascripts/design_management_new/constants.js
new file mode 100644
index 00000000000..21ff361a277
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/constants.js
@@ -0,0 +1,16 @@
+// WARNING: replace this with something
+// more sensical as per https://gitlab.com/gitlab-org/gitlab/issues/118611
+export const VALID_DESIGN_FILE_MIMETYPE = {
+ mimetype: 'image/*',
+ regex: /image\/.+/,
+};
+
+// https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types
+export const VALID_DATA_TRANSFER_TYPE = 'Files';
+
+export const ACTIVE_DISCUSSION_SOURCE_TYPES = {
+ pin: 'pin',
+ discussion: 'discussion',
+};
+
+export const DESIGN_DETAIL_LAYOUT_CLASSLIST = ['design-detail-layout', 'overflow-hidden', 'm-0'];
diff --git a/app/assets/javascripts/design_management_new/graphql.js b/app/assets/javascripts/design_management_new/graphql.js
new file mode 100644
index 00000000000..fae337aa75b
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql.js
@@ -0,0 +1,45 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { uniqueId } from 'lodash';
+import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
+import createDefaultClient from '~/lib/graphql';
+import activeDiscussionQuery from './graphql/queries/active_discussion.query.graphql';
+import typeDefs from './graphql/typedefs.graphql';
+
+Vue.use(VueApollo);
+
+const resolvers = {
+ Mutation: {
+ updateActiveDiscussion: (_, { id = null, source }, { cache }) => {
+ const data = cache.readQuery({ query: activeDiscussionQuery });
+ data.activeDiscussion = {
+ __typename: 'ActiveDiscussion',
+ id,
+ source,
+ };
+ cache.writeQuery({ query: activeDiscussionQuery, data });
+ },
+ },
+};
+
+const defaultClient = createDefaultClient(
+ resolvers,
+ // This config is added temporarily to resolve an issue with duplicate design IDs.
+ // Should be removed as soon as https://gitlab.com/gitlab-org/gitlab/issues/13495 is resolved
+ {
+ cacheConfig: {
+ dataIdFromObject: object => {
+ // eslint-disable-next-line no-underscore-dangle, @gitlab/require-i18n-strings
+ if (object.__typename === 'Design') {
+ return object.id && object.image ? `${object.id}-${object.image}` : uniqueId();
+ }
+ return defaultDataIdFromObject(object);
+ },
+ },
+ typeDefs,
+ },
+);
+
+export default new VueApollo({
+ defaultClient,
+});
diff --git a/app/assets/javascripts/design_management_new/graphql/fragments/design.fragment.graphql b/app/assets/javascripts/design_management_new/graphql/fragments/design.fragment.graphql
new file mode 100644
index 00000000000..4b1703e41c3
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/fragments/design.fragment.graphql
@@ -0,0 +1,24 @@
+#import "./design_note.fragment.graphql"
+#import "./design_list.fragment.graphql"
+#import "./diff_refs.fragment.graphql"
+#import "./discussion_resolved_status.fragment.graphql"
+
+fragment DesignItem on Design {
+ ...DesignListItem
+ fullPath
+ diffRefs {
+ ...DesignDiffRefs
+ }
+ discussions {
+ nodes {
+ id
+ replyId
+ ...ResolvedStatus
+ notes {
+ nodes {
+ ...DesignNote
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/fragments/design_list.fragment.graphql b/app/assets/javascripts/design_management_new/graphql/fragments/design_list.fragment.graphql
new file mode 100644
index 00000000000..bc3132f9b42
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/fragments/design_list.fragment.graphql
@@ -0,0 +1,8 @@
+fragment DesignListItem on Design {
+ id
+ event
+ filename
+ notesCount
+ image
+ imageV432x230
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/fragments/design_note.fragment.graphql b/app/assets/javascripts/design_management_new/graphql/fragments/design_note.fragment.graphql
new file mode 100644
index 00000000000..26edd2c0be1
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/fragments/design_note.fragment.graphql
@@ -0,0 +1,29 @@
+#import "./diff_refs.fragment.graphql"
+#import "~/graphql_shared/fragments/author.fragment.graphql"
+#import "./note_permissions.fragment.graphql"
+
+fragment DesignNote on Note {
+ id
+ author {
+ ...Author
+ }
+ body
+ bodyHtml
+ createdAt
+ resolved
+ position {
+ diffRefs {
+ ...DesignDiffRefs
+ }
+ x
+ y
+ height
+ width
+ }
+ userPermissions {
+ ...DesignNotePermissions
+ }
+ discussion {
+ id
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/fragments/diff_refs.fragment.graphql b/app/assets/javascripts/design_management_new/graphql/fragments/diff_refs.fragment.graphql
new file mode 100644
index 00000000000..984a55814b0
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/fragments/diff_refs.fragment.graphql
@@ -0,0 +1,5 @@
+fragment DesignDiffRefs on DiffRefs {
+ baseSha
+ startSha
+ headSha
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/fragments/discussion_resolved_status.fragment.graphql b/app/assets/javascripts/design_management_new/graphql/fragments/discussion_resolved_status.fragment.graphql
new file mode 100644
index 00000000000..7483b508721
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/fragments/discussion_resolved_status.fragment.graphql
@@ -0,0 +1,9 @@
+fragment ResolvedStatus on Discussion {
+ resolvable
+ resolved
+ resolvedAt
+ resolvedBy {
+ name
+ webUrl
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/fragments/note_permissions.fragment.graphql b/app/assets/javascripts/design_management_new/graphql/fragments/note_permissions.fragment.graphql
new file mode 100644
index 00000000000..c243e39f3d3
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/fragments/note_permissions.fragment.graphql
@@ -0,0 +1,3 @@
+fragment DesignNotePermissions on NotePermissions {
+ adminNote
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/fragments/version.fragment.graphql b/app/assets/javascripts/design_management_new/graphql/fragments/version.fragment.graphql
new file mode 100644
index 00000000000..7eb40b12f51
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/fragments/version.fragment.graphql
@@ -0,0 +1,4 @@
+fragment VersionListItem on DesignVersion {
+ id
+ sha
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/mutations/create_image_diff_note.mutation.graphql b/app/assets/javascripts/design_management_new/graphql/mutations/create_image_diff_note.mutation.graphql
new file mode 100644
index 00000000000..c8ade328120
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/mutations/create_image_diff_note.mutation.graphql
@@ -0,0 +1,21 @@
+#import "../fragments/design_note.fragment.graphql"
+
+mutation createImageDiffNote($input: CreateImageDiffNoteInput!) {
+ createImageDiffNote(input: $input) {
+ note {
+ ...DesignNote
+ discussion {
+ id
+ replyId
+ notes {
+ edges {
+ node {
+ ...DesignNote
+ }
+ }
+ }
+ }
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/mutations/create_note.mutation.graphql b/app/assets/javascripts/design_management_new/graphql/mutations/create_note.mutation.graphql
new file mode 100644
index 00000000000..184ee6955dc
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/mutations/create_note.mutation.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/design_note.fragment.graphql"
+
+mutation createNote($input: CreateNoteInput!) {
+ createNote(input: $input) {
+ note {
+ ...DesignNote
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/mutations/destroy_design.mutation.graphql b/app/assets/javascripts/design_management_new/graphql/mutations/destroy_design.mutation.graphql
new file mode 100644
index 00000000000..0b3cf636cdb
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/mutations/destroy_design.mutation.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/version.fragment.graphql"
+
+mutation destroyDesign($filenames: [String!]!, $projectPath: ID!, $iid: ID!) {
+ designManagementDelete(input: { projectPath: $projectPath, iid: $iid, filenames: $filenames }) {
+ version {
+ ...VersionListItem
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/mutations/toggle_resolve_discussion.mutation.graphql b/app/assets/javascripts/design_management_new/graphql/mutations/toggle_resolve_discussion.mutation.graphql
new file mode 100644
index 00000000000..1157fc05d5f
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/mutations/toggle_resolve_discussion.mutation.graphql
@@ -0,0 +1,17 @@
+#import "../fragments/design_note.fragment.graphql"
+#import "../fragments/discussion_resolved_status.fragment.graphql"
+
+mutation toggleResolveDiscussion($id: ID!, $resolve: Boolean!) {
+ discussionToggleResolve(input: { id: $id, resolve: $resolve }) {
+ discussion {
+ id
+ ...ResolvedStatus
+ notes {
+ nodes {
+ ...DesignNote
+ }
+ }
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/mutations/update_active_discussion.mutation.graphql b/app/assets/javascripts/design_management_new/graphql/mutations/update_active_discussion.mutation.graphql
new file mode 100644
index 00000000000..343de4e3025
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/mutations/update_active_discussion.mutation.graphql
@@ -0,0 +1,3 @@
+mutation updateActiveDiscussion($id: String, $source: String) {
+ updateActiveDiscussion (id: $id, source: $source ) @client
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/mutations/update_image_diff_note.mutation.graphql b/app/assets/javascripts/design_management_new/graphql/mutations/update_image_diff_note.mutation.graphql
new file mode 100644
index 00000000000..5562ca9d89f
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/mutations/update_image_diff_note.mutation.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/design_note.fragment.graphql"
+
+mutation updateImageDiffNote($input: UpdateImageDiffNoteInput!) {
+ updateImageDiffNote(input: $input) {
+ errors
+ note {
+ ...DesignNote
+ }
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/mutations/update_note.mutation.graphql b/app/assets/javascripts/design_management_new/graphql/mutations/update_note.mutation.graphql
new file mode 100644
index 00000000000..b995e99fb6a
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/mutations/update_note.mutation.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/design_note.fragment.graphql"
+
+mutation updateNote($input: UpdateNoteInput!) {
+ updateNote(input: $input) {
+ note {
+ ...DesignNote
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/mutations/upload_design.mutation.graphql b/app/assets/javascripts/design_management_new/graphql/mutations/upload_design.mutation.graphql
new file mode 100644
index 00000000000..904acef599b
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/mutations/upload_design.mutation.graphql
@@ -0,0 +1,21 @@
+#import "../fragments/design.fragment.graphql"
+
+mutation uploadDesign($files: [Upload!]!, $projectPath: ID!, $iid: ID!) {
+ designManagementUpload(input: { projectPath: $projectPath, iid: $iid, files: $files }) {
+ designs {
+ ...DesignItem
+ versions {
+ edges {
+ node {
+ id
+ sha
+ }
+ }
+ },
+ }
+ skippedDesigns {
+ filename
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/queries/active_discussion.query.graphql b/app/assets/javascripts/design_management_new/graphql/queries/active_discussion.query.graphql
new file mode 100644
index 00000000000..111023cea68
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/queries/active_discussion.query.graphql
@@ -0,0 +1,6 @@
+query activeDiscussion {
+ activeDiscussion @client {
+ id
+ source
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/queries/app_data.query.graphql b/app/assets/javascripts/design_management_new/graphql/queries/app_data.query.graphql
new file mode 100644
index 00000000000..e1269761206
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/queries/app_data.query.graphql
@@ -0,0 +1,4 @@
+query projectFullPath {
+ projectPath @client
+ issueIid @client
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/queries/design_permissions.query.graphql b/app/assets/javascripts/design_management_new/graphql/queries/design_permissions.query.graphql
new file mode 100644
index 00000000000..a87b256dc95
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/queries/design_permissions.query.graphql
@@ -0,0 +1,10 @@
+query permissions($fullPath: ID!, $iid: String!) {
+ project(fullPath: $fullPath) {
+ id
+ issue(iid: $iid) {
+ userPermissions {
+ createDesign
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/queries/get_design.query.graphql b/app/assets/javascripts/design_management_new/graphql/queries/get_design.query.graphql
new file mode 100644
index 00000000000..07a9af55787
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/queries/get_design.query.graphql
@@ -0,0 +1,31 @@
+#import "../fragments/design.fragment.graphql"
+#import "~/graphql_shared/fragments/author.fragment.graphql"
+
+query getDesign($fullPath: ID!, $iid: String!, $atVersion: ID, $filenames: [String!]) {
+ project(fullPath: $fullPath) {
+ id
+ issue(iid: $iid) {
+ designCollection {
+ designs(atVersion: $atVersion, filenames: $filenames) {
+ edges {
+ node {
+ ...DesignItem
+ issue {
+ title
+ webPath
+ webUrl
+ participants {
+ edges {
+ node {
+ ...Author
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/queries/get_design_list.query.graphql b/app/assets/javascripts/design_management_new/graphql/queries/get_design_list.query.graphql
new file mode 100644
index 00000000000..121a50555b3
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/queries/get_design_list.query.graphql
@@ -0,0 +1,26 @@
+#import "../fragments/design_list.fragment.graphql"
+#import "../fragments/version.fragment.graphql"
+
+query getDesignList($fullPath: ID!, $iid: String!, $atVersion: ID) {
+ project(fullPath: $fullPath) {
+ id
+ issue(iid: $iid) {
+ designCollection {
+ designs(atVersion: $atVersion) {
+ edges {
+ node {
+ ...DesignListItem
+ }
+ }
+ }
+ versions {
+ edges {
+ node {
+ ...VersionListItem
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/design_management_new/graphql/typedefs.graphql b/app/assets/javascripts/design_management_new/graphql/typedefs.graphql
new file mode 100644
index 00000000000..fdbad4a90e0
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/graphql/typedefs.graphql
@@ -0,0 +1,12 @@
+type ActiveDiscussion {
+ id: ID
+ source: String
+}
+
+extend type Query {
+ activeDiscussion: ActiveDiscussion
+}
+
+extend type Mutation {
+ updateActiveDiscussion(id: ID!, source: String!): Boolean
+}
diff --git a/app/assets/javascripts/design_management_new/index.js b/app/assets/javascripts/design_management_new/index.js
new file mode 100644
index 00000000000..bf9cb9d4776
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/index.js
@@ -0,0 +1,58 @@
+import $ from 'jquery';
+import Vue from 'vue';
+import createRouter from './router';
+import App from './components/app.vue';
+import apolloProvider from './graphql';
+import getDesignListQuery from './graphql/queries/get_design_list.query.graphql';
+import { DESIGNS_ROUTE_NAME, ROOT_ROUTE_NAME } from './router/constants';
+
+export default () => {
+ const el = document.querySelector('.js-design-management-new');
+ const badge = document.querySelector('.js-designs-count');
+ const { issueIid, projectPath, issuePath } = el.dataset;
+ const router = createRouter(issuePath);
+
+ $('.js-issue-tabs').on('shown.bs.tab', ({ target: { id } }) => {
+ if (id === 'designs' && router.currentRoute.name === ROOT_ROUTE_NAME) {
+ router.push({ name: DESIGNS_ROUTE_NAME });
+ } else if (id === 'discussion') {
+ router.push({ name: ROOT_ROUTE_NAME });
+ }
+ });
+
+ apolloProvider.clients.defaultClient.cache.writeData({
+ data: {
+ projectPath,
+ issueIid,
+ activeDiscussion: {
+ __typename: 'ActiveDiscussion',
+ id: null,
+ source: null,
+ },
+ },
+ });
+
+ apolloProvider.clients.defaultClient
+ .watchQuery({
+ query: getDesignListQuery,
+ variables: {
+ fullPath: projectPath,
+ iid: issueIid,
+ atVersion: null,
+ },
+ })
+ .subscribe(({ data }) => {
+ if (badge) {
+ badge.textContent = data.project.issue.designCollection.designs.edges.length;
+ }
+ });
+
+ return new Vue({
+ el,
+ router,
+ apolloProvider,
+ render(createElement) {
+ return createElement(App);
+ },
+ });
+};
diff --git a/app/assets/javascripts/design_management_new/mixins/all_designs.js b/app/assets/javascripts/design_management_new/mixins/all_designs.js
new file mode 100644
index 00000000000..f7d6551c46c
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/mixins/all_designs.js
@@ -0,0 +1,49 @@
+import { propertyOf } from 'lodash';
+import createFlash from '~/flash';
+import { s__ } from '~/locale';
+import getDesignListQuery from '../graphql/queries/get_design_list.query.graphql';
+import { extractNodes } from '../utils/design_management_utils';
+import allVersionsMixin from './all_versions';
+import { DESIGNS_ROUTE_NAME } from '../router/constants';
+
+export default {
+ mixins: [allVersionsMixin],
+ apollo: {
+ designs: {
+ query: getDesignListQuery,
+ variables() {
+ return {
+ fullPath: this.projectPath,
+ iid: this.issueIid,
+ atVersion: this.designsVersion,
+ };
+ },
+ update: data => {
+ const designEdges = propertyOf(data)(['project', 'issue', 'designCollection', 'designs']);
+ if (designEdges) {
+ return extractNodes(designEdges);
+ }
+ return [];
+ },
+ error() {
+ this.error = true;
+ },
+ result() {
+ if (this.$route.query.version && !this.hasValidVersion) {
+ createFlash(
+ s__(
+ 'DesignManagement|Requested design version does not exist. Showing latest version instead',
+ ),
+ );
+ this.$router.replace({ name: DESIGNS_ROUTE_NAME, query: { version: undefined } });
+ }
+ },
+ },
+ },
+ data() {
+ return {
+ designs: [],
+ error: false,
+ };
+ },
+};
diff --git a/app/assets/javascripts/design_management_new/mixins/all_versions.js b/app/assets/javascripts/design_management_new/mixins/all_versions.js
new file mode 100644
index 00000000000..3966fe71732
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/mixins/all_versions.js
@@ -0,0 +1,62 @@
+import getDesignListQuery from '../graphql/queries/get_design_list.query.graphql';
+import appDataQuery from '../graphql/queries/app_data.query.graphql';
+import { findVersionId } from '../utils/design_management_utils';
+
+export default {
+ apollo: {
+ appData: {
+ query: appDataQuery,
+ manual: true,
+ result({ data: { projectPath, issueIid } }) {
+ this.projectPath = projectPath;
+ this.issueIid = issueIid;
+ },
+ },
+ allVersions: {
+ query: getDesignListQuery,
+ variables() {
+ return {
+ fullPath: this.projectPath,
+ iid: this.issueIid,
+ atVersion: null,
+ };
+ },
+ update: data => data.project.issue.designCollection.versions.edges,
+ },
+ },
+ computed: {
+ hasValidVersion() {
+ return (
+ this.$route.query.version &&
+ this.allVersions &&
+ this.allVersions.some(version => version.node.id.endsWith(this.$route.query.version))
+ );
+ },
+ designsVersion() {
+ return this.hasValidVersion
+ ? `gid://gitlab/DesignManagement::Version/${this.$route.query.version}`
+ : null;
+ },
+ latestVersionId() {
+ const latestVersion = this.allVersions[0];
+ return latestVersion && findVersionId(latestVersion.node.id);
+ },
+ isLatestVersion() {
+ if (this.allVersions.length > 0) {
+ return (
+ !this.$route.query.version ||
+ !this.latestVersionId ||
+ this.$route.query.version === this.latestVersionId
+ );
+ }
+ return true;
+ },
+ },
+ data() {
+ return {
+ allVersions: [],
+ projectPath: '',
+ issueIid: null,
+ };
+ },
+};
diff --git a/app/assets/javascripts/design_management_new/pages/design/index.vue b/app/assets/javascripts/design_management_new/pages/design/index.vue
new file mode 100644
index 00000000000..9a959222e22
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/pages/design/index.vue
@@ -0,0 +1,378 @@
+<script>
+import Mousetrap from 'mousetrap';
+import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
+import { ApolloMutation } from 'vue-apollo';
+import createFlash from '~/flash';
+import { fetchPolicies } from '~/lib/graphql';
+import allVersionsMixin from '../../mixins/all_versions';
+import Toolbar from '../../components/toolbar/index.vue';
+import DesignDestroyer from '../../components/design_destroyer.vue';
+import DesignScaler from '../../components/design_scaler.vue';
+import DesignPresentation from '../../components/design_presentation.vue';
+import DesignReplyForm from '../../components/design_notes/design_reply_form.vue';
+import DesignSidebar from '../../components/design_sidebar.vue';
+import getDesignQuery from '../../graphql/queries/get_design.query.graphql';
+import appDataQuery from '../../graphql/queries/app_data.query.graphql';
+import createImageDiffNoteMutation from '../../graphql/mutations/create_image_diff_note.mutation.graphql';
+import updateImageDiffNoteMutation from '../../graphql/mutations/update_image_diff_note.mutation.graphql';
+import updateActiveDiscussionMutation from '../../graphql/mutations/update_active_discussion.mutation.graphql';
+import {
+ extractDiscussions,
+ extractDesign,
+ updateImageDiffNoteOptimisticResponse,
+} from '../../utils/design_management_utils';
+import {
+ updateStoreAfterAddImageDiffNote,
+ updateStoreAfterUpdateImageDiffNote,
+} from '../../utils/cache_update';
+import {
+ ADD_DISCUSSION_COMMENT_ERROR,
+ ADD_IMAGE_DIFF_NOTE_ERROR,
+ UPDATE_IMAGE_DIFF_NOTE_ERROR,
+ DESIGN_NOT_FOUND_ERROR,
+ DESIGN_VERSION_NOT_EXIST_ERROR,
+ UPDATE_NOTE_ERROR,
+ designDeletionError,
+} from '../../utils/error_messages';
+import { trackDesignDetailView } from '../../utils/tracking';
+import { DESIGNS_ROUTE_NAME } from '../../router/constants';
+import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../../constants';
+
+export default {
+ components: {
+ ApolloMutation,
+ DesignReplyForm,
+ DesignPresentation,
+ DesignScaler,
+ DesignDestroyer,
+ Toolbar,
+ GlLoadingIcon,
+ GlAlert,
+ DesignSidebar,
+ },
+ mixins: [allVersionsMixin],
+ props: {
+ id: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ design: {},
+ comment: '',
+ annotationCoordinates: null,
+ projectPath: '',
+ errorMessage: '',
+ issueIid: '',
+ scale: 1,
+ resolvedDiscussionsExpanded: false,
+ };
+ },
+ apollo: {
+ appData: {
+ query: appDataQuery,
+ manual: true,
+ result({ data: { projectPath, issueIid } }) {
+ this.projectPath = projectPath;
+ this.issueIid = issueIid;
+ },
+ },
+ design: {
+ query: getDesignQuery,
+ // We want to see cached design version if we have one, and fetch newer version on the background to update discussions
+ fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
+ variables() {
+ return this.designVariables;
+ },
+ update: data => extractDesign(data),
+ result(res) {
+ this.onDesignQueryResult(res);
+ },
+ error() {
+ this.onQueryError(DESIGN_NOT_FOUND_ERROR);
+ },
+ },
+ },
+ computed: {
+ isFirstLoading() {
+ // We only want to show spinner on initial design load (when opened from a deep link to design)
+ // If we already have cached a design, loading shouldn't be indicated to user
+ return this.$apollo.queries.design.loading && !this.design.filename;
+ },
+ discussions() {
+ if (!this.design.discussions) {
+ return [];
+ }
+ return extractDiscussions(this.design.discussions);
+ },
+ markdownPreviewPath() {
+ return `/${this.projectPath}/preview_markdown?target_type=Issue`;
+ },
+ isSubmitButtonDisabled() {
+ return this.comment.trim().length === 0;
+ },
+ designVariables() {
+ return {
+ fullPath: this.projectPath,
+ iid: this.issueIid,
+ filenames: [this.$route.params.id],
+ atVersion: this.designsVersion,
+ };
+ },
+ mutationPayload() {
+ const { x, y, width, height } = this.annotationCoordinates;
+ return {
+ noteableId: this.design.id,
+ body: this.comment,
+ position: {
+ headSha: this.design.diffRefs.headSha,
+ baseSha: this.design.diffRefs.baseSha,
+ startSha: this.design.diffRefs.startSha,
+ x,
+ y,
+ width,
+ height,
+ paths: {
+ newPath: this.design.fullPath,
+ },
+ },
+ };
+ },
+ isAnnotating() {
+ return Boolean(this.annotationCoordinates);
+ },
+ resolvedDiscussions() {
+ return this.discussions.filter(discussion => discussion.resolved);
+ },
+ },
+ watch: {
+ resolvedDiscussions(val) {
+ if (!val.length) {
+ this.resolvedDiscussionsExpanded = false;
+ }
+ },
+ },
+ mounted() {
+ Mousetrap.bind('esc', this.closeDesign);
+ this.trackEvent();
+ // We need to reset the active discussion when opening a new design
+ this.updateActiveDiscussion();
+ },
+ beforeDestroy() {
+ Mousetrap.unbind('esc', this.closeDesign);
+ },
+ methods: {
+ addImageDiffNoteToStore(
+ store,
+ {
+ data: { createImageDiffNote },
+ },
+ ) {
+ updateStoreAfterAddImageDiffNote(
+ store,
+ createImageDiffNote,
+ getDesignQuery,
+ this.designVariables,
+ );
+ },
+ updateImageDiffNoteInStore(
+ store,
+ {
+ data: { updateImageDiffNote },
+ },
+ ) {
+ return updateStoreAfterUpdateImageDiffNote(
+ store,
+ updateImageDiffNote,
+ getDesignQuery,
+ this.designVariables,
+ );
+ },
+ onMoveNote({ noteId, discussionId, position }) {
+ const discussion = this.discussions.find(({ id }) => id === discussionId);
+ const note = discussion.notes.find(
+ ({ discussion: noteDiscussion }) => noteDiscussion.id === discussionId,
+ );
+
+ const mutationPayload = {
+ optimisticResponse: updateImageDiffNoteOptimisticResponse(note, {
+ position,
+ }),
+ variables: {
+ input: {
+ id: noteId,
+ position,
+ },
+ },
+ mutation: updateImageDiffNoteMutation,
+ update: this.updateImageDiffNoteInStore,
+ };
+
+ return this.$apollo.mutate(mutationPayload).catch(e => this.onUpdateImageDiffNoteError(e));
+ },
+ onDesignQueryResult({ data, loading }) {
+ // On the initial load with cache-and-network policy data is undefined while loading is true
+ // To prevent throwing an error, we don't perform any logic until loading is false
+ if (loading) {
+ return;
+ }
+
+ if (!data || !extractDesign(data)) {
+ this.onQueryError(DESIGN_NOT_FOUND_ERROR);
+ } else if (this.$route.query.version && !this.hasValidVersion) {
+ this.onQueryError(DESIGN_VERSION_NOT_EXIST_ERROR);
+ }
+ },
+ onQueryError(message) {
+ // because we redirect user to /designs (the issue page),
+ // we want to create these flashes on the issue page
+ createFlash(message);
+ this.$router.push({ name: this.$options.DESIGNS_ROUTE_NAME });
+ },
+ onError(message, e) {
+ this.errorMessage = message;
+ throw e;
+ },
+ onCreateImageDiffNoteError(e) {
+ this.onError(ADD_IMAGE_DIFF_NOTE_ERROR, e);
+ },
+ onUpdateNoteError(e) {
+ this.onError(UPDATE_NOTE_ERROR, e);
+ },
+ onDesignDiscussionError(e) {
+ this.onError(ADD_DISCUSSION_COMMENT_ERROR, e);
+ },
+ onUpdateImageDiffNoteError(e) {
+ this.onError(UPDATE_IMAGE_DIFF_NOTE_ERROR, e);
+ },
+ onDesignDeleteError(e) {
+ this.onError(designDeletionError({ singular: true }), e);
+ },
+ onResolveDiscussionError(e) {
+ this.onError(UPDATE_IMAGE_DIFF_NOTE_ERROR, e);
+ },
+ openCommentForm(annotationCoordinates) {
+ this.annotationCoordinates = annotationCoordinates;
+ if (this.$refs.newDiscussionForm) {
+ this.$refs.newDiscussionForm.focusInput();
+ }
+ },
+ closeCommentForm() {
+ this.comment = '';
+ this.annotationCoordinates = null;
+ },
+ closeDesign() {
+ this.$router.push({
+ name: this.$options.DESIGNS_ROUTE_NAME,
+ query: this.$route.query,
+ });
+ },
+ trackEvent() {
+ // TODO: This needs to be made aware of referers, or if it's rendered in a different context than a Issue
+ trackDesignDetailView(
+ 'issue-design-collection',
+ 'issue',
+ this.$route.query.version || this.latestVersionId,
+ this.isLatestVersion,
+ );
+ },
+ updateActiveDiscussion(id) {
+ this.$apollo.mutate({
+ mutation: updateActiveDiscussionMutation,
+ variables: {
+ id,
+ source: ACTIVE_DISCUSSION_SOURCE_TYPES.discussion,
+ },
+ });
+ },
+ toggleResolvedComments() {
+ this.resolvedDiscussionsExpanded = !this.resolvedDiscussionsExpanded;
+ },
+ },
+ createImageDiffNoteMutation,
+ DESIGNS_ROUTE_NAME,
+};
+</script>
+
+<template>
+ <div
+ class="design-detail js-design-detail fixed-top w-100 position-bottom-0 d-flex justify-content-center flex-column flex-lg-row"
+ >
+ <gl-loading-icon v-if="isFirstLoading" size="xl" class="align-self-center" />
+ <template v-else>
+ <div class="d-flex overflow-hidden flex-grow-1 flex-column position-relative">
+ <design-destroyer
+ :filenames="[design.filename]"
+ :project-path="projectPath"
+ :iid="issueIid"
+ @done="$router.push({ name: $options.DESIGNS_ROUTE_NAME })"
+ @error="onDesignDeleteError"
+ >
+ <template #default="{ mutate, loading }">
+ <toolbar
+ :id="id"
+ :is-deleting="loading"
+ :is-latest-version="isLatestVersion"
+ v-bind="design"
+ @delete="mutate"
+ />
+ </template>
+ </design-destroyer>
+
+ <div v-if="errorMessage" class="p-3">
+ <gl-alert variant="danger" @dismiss="errorMessage = null">
+ {{ errorMessage }}
+ </gl-alert>
+ </div>
+ <design-presentation
+ :image="design.image"
+ :image-name="design.filename"
+ :discussions="discussions"
+ :is-annotating="isAnnotating"
+ :scale="scale"
+ :resolved-discussions-expanded="resolvedDiscussionsExpanded"
+ @openCommentForm="openCommentForm"
+ @closeCommentForm="closeCommentForm"
+ @moveNote="onMoveNote"
+ />
+
+ <div class="design-scaler-wrapper position-absolute mb-4 d-flex-center">
+ <design-scaler @scale="scale = $event" />
+ </div>
+ </div>
+ <design-sidebar
+ :design="design"
+ :resolved-discussions-expanded="resolvedDiscussionsExpanded"
+ :markdown-preview-path="markdownPreviewPath"
+ @onDesignDiscussionError="onDesignDiscussionError"
+ @onCreateImageDiffNoteError="onCreateImageDiffNoteError"
+ @updateNoteError="onUpdateNoteError"
+ @resolveDiscussionError="onResolveDiscussionError"
+ @toggleResolvedComments="toggleResolvedComments"
+ >
+ <template #replyForm>
+ <apollo-mutation
+ v-if="isAnnotating"
+ #default="{ mutate, loading }"
+ :mutation="$options.createImageDiffNoteMutation"
+ :variables="{
+ input: mutationPayload,
+ }"
+ :update="addImageDiffNoteToStore"
+ @done="closeCommentForm"
+ @error="onCreateImageDiffNoteError"
+ >
+ <design-reply-form
+ ref="newDiscussionForm"
+ v-model="comment"
+ :is-saving="loading"
+ :markdown-preview-path="markdownPreviewPath"
+ @submitForm="mutate"
+ @cancelForm="closeCommentForm"
+ /> </apollo-mutation
+ ></template>
+ </design-sidebar>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/pages/index.vue b/app/assets/javascripts/design_management_new/pages/index.vue
new file mode 100644
index 00000000000..d14a1fc8c1c
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/pages/index.vue
@@ -0,0 +1,323 @@
+<script>
+import { GlLoadingIcon, GlDeprecatedButton, GlAlert } from '@gitlab/ui';
+import createFlash from '~/flash';
+import { s__, sprintf } from '~/locale';
+import UploadButton from '../components/upload/button.vue';
+import DeleteButton from '../components/delete_button.vue';
+import Design from '../components/list/item.vue';
+import DesignDestroyer from '../components/design_destroyer.vue';
+import DesignVersionDropdown from '../components/upload/design_version_dropdown.vue';
+import DesignDropzone from '../components/upload/design_dropzone.vue';
+import uploadDesignMutation from '../graphql/mutations/upload_design.mutation.graphql';
+import permissionsQuery from '../graphql/queries/design_permissions.query.graphql';
+import getDesignListQuery from '../graphql/queries/get_design_list.query.graphql';
+import allDesignsMixin from '../mixins/all_designs';
+import {
+ UPLOAD_DESIGN_ERROR,
+ EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE,
+ EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE,
+ designUploadSkippedWarning,
+ designDeletionError,
+} from '../utils/error_messages';
+import { updateStoreAfterUploadDesign } from '../utils/cache_update';
+import {
+ designUploadOptimisticResponse,
+ isValidDesignFile,
+} from '../utils/design_management_utils';
+import { getFilename } from '~/lib/utils/file_upload';
+import { DESIGNS_ROUTE_NAME } from '../router/constants';
+
+const MAXIMUM_FILE_UPLOAD_LIMIT = 10;
+
+export default {
+ components: {
+ GlLoadingIcon,
+ GlAlert,
+ GlDeprecatedButton,
+ UploadButton,
+ Design,
+ DesignDestroyer,
+ DesignVersionDropdown,
+ DeleteButton,
+ DesignDropzone,
+ },
+ mixins: [allDesignsMixin],
+ apollo: {
+ permissions: {
+ query: permissionsQuery,
+ variables() {
+ return {
+ fullPath: this.projectPath,
+ iid: this.issueIid,
+ };
+ },
+ update: data => data.project.issue.userPermissions,
+ },
+ },
+ data() {
+ return {
+ permissions: {
+ createDesign: false,
+ },
+ filesToBeSaved: [],
+ selectedDesigns: [],
+ };
+ },
+ computed: {
+ isLoading() {
+ return this.$apollo.queries.designs.loading || this.$apollo.queries.permissions.loading;
+ },
+ isSaving() {
+ return this.filesToBeSaved.length > 0;
+ },
+ canCreateDesign() {
+ return this.permissions.createDesign;
+ },
+ showToolbar() {
+ return this.canCreateDesign && this.allVersions.length > 0;
+ },
+ hasDesigns() {
+ return this.designs.length > 0;
+ },
+ hasSelectedDesigns() {
+ return this.selectedDesigns.length > 0;
+ },
+ canDeleteDesigns() {
+ return this.isLatestVersion && this.hasSelectedDesigns;
+ },
+ projectQueryBody() {
+ return {
+ query: getDesignListQuery,
+ variables: { fullPath: this.projectPath, iid: this.issueIid, atVersion: null },
+ };
+ },
+ selectAllButtonText() {
+ return this.hasSelectedDesigns
+ ? s__('DesignManagement|Deselect all')
+ : s__('DesignManagement|Select all');
+ },
+ },
+ mounted() {
+ this.toggleOnPasteListener(this.$route.name);
+ },
+ methods: {
+ resetFilesToBeSaved() {
+ this.filesToBeSaved = [];
+ },
+ /**
+ * Determine if a design upload is valid, given [files]
+ * @param {Array<File>} files
+ */
+ isValidDesignUpload(files) {
+ if (!this.canCreateDesign) return false;
+
+ if (files.length > MAXIMUM_FILE_UPLOAD_LIMIT) {
+ createFlash(
+ sprintf(
+ s__(
+ 'DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again.',
+ ),
+ {
+ upload_limit: MAXIMUM_FILE_UPLOAD_LIMIT,
+ },
+ ),
+ );
+
+ return false;
+ }
+ return true;
+ },
+ onUploadDesign(files) {
+ // convert to Array so that we have Array methods (.map, .some, etc.)
+ this.filesToBeSaved = Array.from(files);
+ if (!this.isValidDesignUpload(this.filesToBeSaved)) return null;
+
+ const mutationPayload = {
+ optimisticResponse: designUploadOptimisticResponse(this.filesToBeSaved),
+ variables: {
+ files: this.filesToBeSaved,
+ projectPath: this.projectPath,
+ iid: this.issueIid,
+ },
+ context: {
+ hasUpload: true,
+ },
+ mutation: uploadDesignMutation,
+ update: this.afterUploadDesign,
+ };
+
+ return this.$apollo
+ .mutate(mutationPayload)
+ .then(res => this.onUploadDesignDone(res))
+ .catch(() => this.onUploadDesignError());
+ },
+ afterUploadDesign(
+ store,
+ {
+ data: { designManagementUpload },
+ },
+ ) {
+ updateStoreAfterUploadDesign(store, designManagementUpload, this.projectQueryBody);
+ },
+ onUploadDesignDone(res) {
+ const skippedFiles = res?.data?.designManagementUpload?.skippedDesigns || [];
+ const skippedWarningMessage = designUploadSkippedWarning(this.filesToBeSaved, skippedFiles);
+ if (skippedWarningMessage) {
+ createFlash(skippedWarningMessage, 'warning');
+ }
+
+ // if this upload resulted in a new version being created, redirect user to the latest version
+ if (!this.isLatestVersion) {
+ this.$router.push({ name: DESIGNS_ROUTE_NAME });
+ }
+ this.resetFilesToBeSaved();
+ },
+ onUploadDesignError() {
+ this.resetFilesToBeSaved();
+ createFlash(UPLOAD_DESIGN_ERROR);
+ },
+ changeSelectedDesigns(filename) {
+ if (this.isDesignSelected(filename)) {
+ this.selectedDesigns = this.selectedDesigns.filter(design => design !== filename);
+ } else {
+ this.selectedDesigns.push(filename);
+ }
+ },
+ toggleDesignsSelection() {
+ if (this.hasSelectedDesigns) {
+ this.selectedDesigns = [];
+ } else {
+ this.selectedDesigns = this.designs.map(design => design.filename);
+ }
+ },
+ isDesignSelected(filename) {
+ return this.selectedDesigns.includes(filename);
+ },
+ isDesignToBeSaved(filename) {
+ return this.filesToBeSaved.some(file => file.name === filename);
+ },
+ canSelectDesign(filename) {
+ return this.isLatestVersion && this.canCreateDesign && !this.isDesignToBeSaved(filename);
+ },
+ onDesignDelete() {
+ this.selectedDesigns = [];
+ if (this.$route.query.version) this.$router.push({ name: DESIGNS_ROUTE_NAME });
+ },
+ onDesignDeleteError() {
+ const errorMessage = designDeletionError({ singular: this.selectedDesigns.length === 1 });
+ createFlash(errorMessage);
+ },
+ onExistingDesignDropzoneChange(files, existingDesignFilename) {
+ const filesArr = Array.from(files);
+
+ if (filesArr.length > 1) {
+ createFlash(EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE);
+ return;
+ }
+
+ if (!filesArr.some(({ name }) => existingDesignFilename === name)) {
+ createFlash(EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE);
+ return;
+ }
+
+ this.onUploadDesign(files);
+ },
+ onDesignPaste(event) {
+ const { clipboardData } = event;
+ const files = Array.from(clipboardData.files);
+ if (clipboardData && files.length > 0) {
+ if (!files.some(isValidDesignFile)) {
+ return;
+ }
+ event.preventDefault();
+ let filename = getFilename(event);
+ if (!filename || filename === 'image.png') {
+ filename = `design_${Date.now()}.png`;
+ }
+ const newFile = new File([files[0]], filename);
+ this.onUploadDesign([newFile]);
+ }
+ },
+ toggleOnPasteListener(route) {
+ if (route === DESIGNS_ROUTE_NAME) {
+ document.addEventListener('paste', this.onDesignPaste);
+ } else {
+ document.removeEventListener('paste', this.onDesignPaste);
+ }
+ },
+ },
+ beforeRouteUpdate(to, from, next) {
+ this.toggleOnPasteListener(to.name);
+ this.selectedDesigns = [];
+ next();
+ },
+ beforeRouteLeave(to, from, next) {
+ this.toggleOnPasteListener(to.name);
+ next();
+ },
+};
+</script>
+
+<template>
+ <div>
+ <header v-if="showToolbar" class="row-content-block border-top-0 p-2 d-flex">
+ <div class="d-flex justify-content-between align-items-center w-100">
+ <design-version-dropdown />
+ <div :class="['qa-selector-toolbar', { 'd-flex': hasDesigns, 'd-none': !hasDesigns }]">
+ <gl-deprecated-button
+ v-if="isLatestVersion"
+ variant="link"
+ class="mr-2 js-select-all"
+ @click="toggleDesignsSelection"
+ >{{ selectAllButtonText }}</gl-deprecated-button
+ >
+ <design-destroyer
+ #default="{ mutate, loading }"
+ :filenames="selectedDesigns"
+ :project-path="projectPath"
+ :iid="issueIid"
+ @done="onDesignDelete"
+ @error="onDesignDeleteError"
+ >
+ <delete-button
+ v-if="isLatestVersion"
+ :is-deleting="loading"
+ button-class="btn-danger btn-inverted mr-2"
+ :has-selected-designs="hasSelectedDesigns"
+ @deleteSelectedDesigns="mutate()"
+ >
+ {{ s__('DesignManagement|Delete selected') }}
+ <gl-loading-icon v-if="loading" inline class="ml-1" />
+ </delete-button>
+ </design-destroyer>
+ <upload-button v-if="canCreateDesign" :is-saving="isSaving" @upload="onUploadDesign" />
+ </div>
+ </div>
+ </header>
+ <div class="mt-4">
+ <gl-loading-icon v-if="isLoading" size="md" />
+ <gl-alert v-else-if="error" variant="danger" :dismissible="false">
+ {{ __('An error occurred while loading designs. Please try again.') }}
+ </gl-alert>
+ <ol v-else class="list-unstyled row">
+ <li class="col-md-6 col-lg-4 mb-3">
+ <design-dropzone class="design-list-item" @change="onUploadDesign" />
+ </li>
+ <li v-for="design in designs" :key="design.id" class="col-md-6 col-lg-4 mb-3">
+ <design-dropzone @change="onExistingDesignDropzoneChange($event, design.filename)"
+ ><design v-bind="design" :is-uploading="isDesignToBeSaved(design.filename)"
+ /></design-dropzone>
+
+ <input
+ v-if="canSelectDesign(design.filename)"
+ :checked="isDesignSelected(design.filename)"
+ type="checkbox"
+ class="design-checkbox"
+ @change="changeSelectedDesigns(design.filename)"
+ />
+ </li>
+ </ol>
+ </div>
+ <router-view :key="$route.fullPath" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management_new/router/constants.js b/app/assets/javascripts/design_management_new/router/constants.js
new file mode 100644
index 00000000000..abeef520e33
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/router/constants.js
@@ -0,0 +1,3 @@
+export const ROOT_ROUTE_NAME = 'root';
+export const DESIGNS_ROUTE_NAME = 'designs';
+export const DESIGN_ROUTE_NAME = 'design';
diff --git a/app/assets/javascripts/design_management_new/router/index.js b/app/assets/javascripts/design_management_new/router/index.js
new file mode 100644
index 00000000000..23537609a40
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/router/index.js
@@ -0,0 +1,35 @@
+import $ from 'jquery';
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+import routes from './routes';
+import { DESIGN_ROUTE_NAME } from './constants';
+import { getPageLayoutElement } from '~/design_management_new/utils/design_management_utils';
+import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '../constants';
+
+Vue.use(VueRouter);
+
+export default function createRouter(base) {
+ const router = new VueRouter({
+ base,
+ mode: 'history',
+ routes,
+ });
+ const pageEl = getPageLayoutElement();
+
+ router.beforeEach(({ meta: { el }, name }, _, next) => {
+ $(`#${el}`).tab('show');
+
+ // apply a fullscreen layout style in Design View (a.k.a design detail)
+ if (pageEl) {
+ if (name === DESIGN_ROUTE_NAME) {
+ pageEl.classList.add(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
+ } else {
+ pageEl.classList.remove(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
+ }
+ }
+
+ next();
+ });
+
+ return router;
+}
diff --git a/app/assets/javascripts/design_management_new/router/routes.js b/app/assets/javascripts/design_management_new/router/routes.js
new file mode 100644
index 00000000000..788910e5514
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/router/routes.js
@@ -0,0 +1,44 @@
+import Home from '../pages/index.vue';
+import DesignDetail from '../pages/design/index.vue';
+import { ROOT_ROUTE_NAME, DESIGNS_ROUTE_NAME, DESIGN_ROUTE_NAME } from './constants';
+
+export default [
+ {
+ name: ROOT_ROUTE_NAME,
+ path: '/',
+ component: Home,
+ meta: {
+ el: 'discussion',
+ },
+ },
+ {
+ name: DESIGNS_ROUTE_NAME,
+ path: '/designs',
+ component: Home,
+ meta: {
+ el: 'designs',
+ },
+ children: [
+ {
+ name: DESIGN_ROUTE_NAME,
+ path: ':id',
+ component: DesignDetail,
+ meta: {
+ el: 'designs',
+ },
+ beforeEnter(
+ {
+ params: { id },
+ },
+ from,
+ next,
+ ) {
+ if (typeof id === 'string') {
+ next();
+ }
+ },
+ props: ({ params: { id } }) => ({ id }),
+ },
+ ],
+ },
+];
diff --git a/app/assets/javascripts/design_management_new/utils/cache_update.js b/app/assets/javascripts/design_management_new/utils/cache_update.js
new file mode 100644
index 00000000000..24b374b79fd
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/utils/cache_update.js
@@ -0,0 +1,276 @@
+/* eslint-disable @gitlab/require-i18n-strings */
+
+import createFlash from '~/flash';
+import { extractCurrentDiscussion, extractDesign } from './design_management_utils';
+import {
+ ADD_IMAGE_DIFF_NOTE_ERROR,
+ UPDATE_IMAGE_DIFF_NOTE_ERROR,
+ ADD_DISCUSSION_COMMENT_ERROR,
+ designDeletionError,
+} from './error_messages';
+
+const deleteDesignsFromStore = (store, query, selectedDesigns) => {
+ const data = store.readQuery(query);
+
+ const changedDesigns = data.project.issue.designCollection.designs.edges.filter(
+ ({ node }) => !selectedDesigns.includes(node.filename),
+ );
+ data.project.issue.designCollection.designs.edges = [...changedDesigns];
+
+ store.writeQuery({
+ ...query,
+ data,
+ });
+};
+
+/**
+ * Adds a new version of designs to store
+ *
+ * @param {Object} store
+ * @param {Object} query
+ * @param {Object} version
+ */
+const addNewVersionToStore = (store, query, version) => {
+ if (!version) return;
+
+ const data = store.readQuery(query);
+ const newEdge = { node: version, __typename: 'DesignVersionEdge' };
+
+ data.project.issue.designCollection.versions.edges = [
+ newEdge,
+ ...data.project.issue.designCollection.versions.edges,
+ ];
+
+ store.writeQuery({
+ ...query,
+ data,
+ });
+};
+
+const addDiscussionCommentToStore = (store, createNote, query, queryVariables, discussionId) => {
+ const data = store.readQuery({
+ query,
+ variables: queryVariables,
+ });
+
+ const design = extractDesign(data);
+ const currentDiscussion = extractCurrentDiscussion(design.discussions, discussionId);
+ currentDiscussion.notes.nodes = [...currentDiscussion.notes.nodes, createNote.note];
+
+ design.notesCount += 1;
+ if (
+ !design.issue.participants.edges.some(
+ participant => participant.node.username === createNote.note.author.username,
+ )
+ ) {
+ design.issue.participants.edges = [
+ ...design.issue.participants.edges,
+ {
+ __typename: 'UserEdge',
+ node: {
+ __typename: 'User',
+ ...createNote.note.author,
+ },
+ },
+ ];
+ }
+ store.writeQuery({
+ query,
+ variables: queryVariables,
+ data: {
+ ...data,
+ design: {
+ ...design,
+ },
+ },
+ });
+};
+
+const addImageDiffNoteToStore = (store, createImageDiffNote, query, variables) => {
+ const data = store.readQuery({
+ query,
+ variables,
+ });
+ const newDiscussion = {
+ __typename: 'Discussion',
+ id: createImageDiffNote.note.discussion.id,
+ replyId: createImageDiffNote.note.discussion.replyId,
+ resolvable: true,
+ resolved: false,
+ resolvedAt: null,
+ resolvedBy: null,
+ notes: {
+ __typename: 'NoteConnection',
+ nodes: [createImageDiffNote.note],
+ },
+ };
+ const design = extractDesign(data);
+ const notesCount = design.notesCount + 1;
+ design.discussions.nodes = [...design.discussions.nodes, newDiscussion];
+ if (
+ !design.issue.participants.edges.some(
+ participant => participant.node.username === createImageDiffNote.note.author.username,
+ )
+ ) {
+ design.issue.participants.edges = [
+ ...design.issue.participants.edges,
+ {
+ __typename: 'UserEdge',
+ node: {
+ __typename: 'User',
+ ...createImageDiffNote.note.author,
+ },
+ },
+ ];
+ }
+ store.writeQuery({
+ query,
+ variables,
+ data: {
+ ...data,
+ design: {
+ ...design,
+ notesCount,
+ },
+ },
+ });
+};
+
+const updateImageDiffNoteInStore = (store, updateImageDiffNote, query, variables) => {
+ const data = store.readQuery({
+ query,
+ variables,
+ });
+
+ const design = extractDesign(data);
+ const discussion = extractCurrentDiscussion(
+ design.discussions,
+ updateImageDiffNote.note.discussion.id,
+ );
+
+ discussion.notes = {
+ ...discussion.notes,
+ nodes: [updateImageDiffNote.note, ...discussion.notes.nodes.slice(1)],
+ };
+
+ store.writeQuery({
+ query,
+ variables,
+ data: {
+ ...data,
+ design,
+ },
+ });
+};
+
+const addNewDesignToStore = (store, designManagementUpload, query) => {
+ const data = store.readQuery(query);
+
+ const newDesigns = data.project.issue.designCollection.designs.edges.reduce((acc, design) => {
+ if (!acc.find(d => d.filename === design.node.filename)) {
+ acc.push(design.node);
+ }
+
+ return acc;
+ }, designManagementUpload.designs);
+
+ let newVersionNode;
+ const findNewVersions = designManagementUpload.designs.find(design => design.versions);
+
+ if (findNewVersions) {
+ const findNewVersionsEdges = findNewVersions.versions.edges;
+
+ if (findNewVersionsEdges && findNewVersionsEdges.length) {
+ newVersionNode = [findNewVersionsEdges[0]];
+ }
+ }
+
+ const newVersions = [
+ ...(newVersionNode || []),
+ ...data.project.issue.designCollection.versions.edges,
+ ];
+
+ const updatedDesigns = {
+ __typename: 'DesignCollection',
+ designs: {
+ __typename: 'DesignConnection',
+ edges: newDesigns.map(design => ({
+ __typename: 'DesignEdge',
+ node: design,
+ })),
+ },
+ versions: {
+ __typename: 'DesignVersionConnection',
+ edges: newVersions,
+ },
+ };
+
+ data.project.issue.designCollection = updatedDesigns;
+
+ store.writeQuery({
+ ...query,
+ data,
+ });
+};
+
+const onError = (data, message) => {
+ createFlash(message);
+ throw new Error(data.errors);
+};
+
+export const hasErrors = ({ errors = [] }) => errors?.length;
+
+/**
+ * Updates a store after design deletion
+ *
+ * @param {Object} store
+ * @param {Object} data
+ * @param {Object} query
+ * @param {Array} designs
+ */
+export const updateStoreAfterDesignsDelete = (store, data, query, designs) => {
+ if (hasErrors(data)) {
+ onError(data, designDeletionError({ singular: designs.length === 1 }));
+ } else {
+ deleteDesignsFromStore(store, query, designs);
+ addNewVersionToStore(store, query, data.version);
+ }
+};
+
+export const updateStoreAfterAddDiscussionComment = (
+ store,
+ data,
+ query,
+ queryVariables,
+ discussionId,
+) => {
+ if (hasErrors(data)) {
+ onError(data, ADD_DISCUSSION_COMMENT_ERROR);
+ } else {
+ addDiscussionCommentToStore(store, data, query, queryVariables, discussionId);
+ }
+};
+
+export const updateStoreAfterAddImageDiffNote = (store, data, query, queryVariables) => {
+ if (hasErrors(data)) {
+ onError(data, ADD_IMAGE_DIFF_NOTE_ERROR);
+ } else {
+ addImageDiffNoteToStore(store, data, query, queryVariables);
+ }
+};
+
+export const updateStoreAfterUpdateImageDiffNote = (store, data, query, queryVariables) => {
+ if (hasErrors(data)) {
+ onError(data, UPDATE_IMAGE_DIFF_NOTE_ERROR);
+ } else {
+ updateImageDiffNoteInStore(store, data, query, queryVariables);
+ }
+};
+
+export const updateStoreAfterUploadDesign = (store, data, query) => {
+ if (hasErrors(data)) {
+ onError(data, data.errors[0]);
+ } else {
+ addNewDesignToStore(store, data, query);
+ }
+};
diff --git a/app/assets/javascripts/design_management_new/utils/design_management_utils.js b/app/assets/javascripts/design_management_new/utils/design_management_utils.js
new file mode 100644
index 00000000000..22705cf67a1
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/utils/design_management_utils.js
@@ -0,0 +1,128 @@
+import { uniqueId } from 'lodash';
+import { VALID_DESIGN_FILE_MIMETYPE } from '../constants';
+
+export const isValidDesignFile = ({ type }) =>
+ (type.match(VALID_DESIGN_FILE_MIMETYPE.regex) || []).length > 0;
+
+/**
+ * Returns formatted array that doesn't contain
+ * `edges`->`node` nesting
+ *
+ * @param {Array} elements
+ */
+
+export const extractNodes = elements => elements.edges.map(({ node }) => node);
+
+/**
+ * Returns formatted array of discussions that doesn't contain
+ * `edges`->`node` nesting for child notes
+ *
+ * @param {Array} discussions
+ */
+
+export const extractDiscussions = discussions =>
+ discussions.nodes.map((discussion, index) => ({
+ ...discussion,
+ index: index + 1,
+ notes: discussion.notes.nodes,
+ }));
+
+/**
+ * Returns a discussion with the given id from discussions array
+ *
+ * @param {Array} discussions
+ */
+
+export const extractCurrentDiscussion = (discussions, id) =>
+ discussions.nodes.find(discussion => discussion.id === id);
+
+export const findVersionId = id => (id.match('::Version/(.+$)') || [])[1];
+
+export const findNoteId = id => (id.match('DiffNote/(.+$)') || [])[1];
+
+export const extractDesigns = data => data.project.issue.designCollection.designs.edges;
+
+export const extractDesign = data => (extractDesigns(data) || [])[0]?.node;
+
+/**
+ * Generates optimistic response for a design upload mutation
+ * @param {Array<File>} files
+ */
+export const designUploadOptimisticResponse = files => {
+ const designs = files.map(file => ({
+ // False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ __typename: 'Design',
+ id: -uniqueId(),
+ image: '',
+ imageV432x230: '',
+ filename: file.name,
+ fullPath: '',
+ notesCount: 0,
+ event: 'NONE',
+ diffRefs: {
+ __typename: 'DiffRefs',
+ baseSha: '',
+ startSha: '',
+ headSha: '',
+ },
+ discussions: {
+ __typename: 'DesignDiscussion',
+ nodes: [],
+ },
+ versions: {
+ __typename: 'DesignVersionConnection',
+ edges: {
+ __typename: 'DesignVersionEdge',
+ node: {
+ __typename: 'DesignVersion',
+ id: -uniqueId(),
+ sha: -uniqueId(),
+ },
+ },
+ },
+ }));
+
+ return {
+ // False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ __typename: 'Mutation',
+ designManagementUpload: {
+ __typename: 'DesignManagementUploadPayload',
+ designs,
+ skippedDesigns: [],
+ errors: [],
+ },
+ };
+};
+
+/**
+ * Generates optimistic response for a design upload mutation
+ * @param {Array<File>} files
+ */
+export const updateImageDiffNoteOptimisticResponse = (note, { position }) => ({
+ // False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ __typename: 'Mutation',
+ updateImageDiffNote: {
+ __typename: 'UpdateImageDiffNotePayload',
+ note: {
+ ...note,
+ position: {
+ ...note.position,
+ ...position,
+ },
+ },
+ errors: [],
+ },
+});
+
+const normalizeAuthor = author => ({
+ ...author,
+ web_url: author.webUrl,
+ avatar_url: author.avatarUrl,
+});
+
+export const extractParticipants = users => users.edges.map(({ node }) => normalizeAuthor(node));
+
+export const getPageLayoutElement = () => document.querySelector('.layout-page');
diff --git a/app/assets/javascripts/design_management_new/utils/error_messages.js b/app/assets/javascripts/design_management_new/utils/error_messages.js
new file mode 100644
index 00000000000..7666c726c2f
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/utils/error_messages.js
@@ -0,0 +1,95 @@
+import { __, s__, n__, sprintf } from '~/locale';
+
+export const ADD_DISCUSSION_COMMENT_ERROR = s__(
+ 'DesignManagement|Could not add a new comment. Please try again.',
+);
+
+export const ADD_IMAGE_DIFF_NOTE_ERROR = s__(
+ 'DesignManagement|Could not create new discussion. Please try again.',
+);
+
+export const UPDATE_IMAGE_DIFF_NOTE_ERROR = s__(
+ 'DesignManagement|Could not update discussion. Please try again.',
+);
+
+export const UPDATE_NOTE_ERROR = s__('DesignManagement|Could not update note. Please try again.');
+
+export const UPLOAD_DESIGN_ERROR = s__(
+ 'DesignManagement|Error uploading a new design. Please try again.',
+);
+
+export const UPLOAD_DESIGN_INVALID_FILETYPE_ERROR = __(
+ 'Could not upload your designs as one or more files uploaded are not supported.',
+);
+
+export const DESIGN_NOT_FOUND_ERROR = __('Could not find design.');
+
+export const DESIGN_VERSION_NOT_EXIST_ERROR = __('Requested design version does not exist.');
+
+const DESIGN_UPLOAD_SKIPPED_MESSAGE = s__('DesignManagement|Upload skipped.');
+
+const ALL_DESIGNS_SKIPPED_MESSAGE = `${DESIGN_UPLOAD_SKIPPED_MESSAGE} ${s__(
+ 'The designs you tried uploading did not change.',
+)}`;
+
+export const EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE = __(
+ 'You can only upload one design when dropping onto an existing design.',
+);
+
+export const EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE = __(
+ 'You must upload a file with the same file name when dropping onto an existing design.',
+);
+
+const MAX_SKIPPED_FILES_LISTINGS = 5;
+
+const oneDesignSkippedMessage = filename =>
+ `${DESIGN_UPLOAD_SKIPPED_MESSAGE} ${sprintf(s__('DesignManagement|%{filename} did not change.'), {
+ filename,
+ })}`;
+
+/**
+ * Return warning message indicating that some (but not all) uploaded
+ * files were skipped.
+ * @param {Array<{ filename }>} skippedFiles
+ */
+const someDesignsSkippedMessage = skippedFiles => {
+ const designsSkippedMessage = `${DESIGN_UPLOAD_SKIPPED_MESSAGE} ${s__(
+ 'Some of the designs you tried uploading did not change:',
+ )}`;
+
+ const moreText = sprintf(s__(`DesignManagement|and %{moreCount} more.`), {
+ moreCount: skippedFiles.length - MAX_SKIPPED_FILES_LISTINGS,
+ });
+
+ return `${designsSkippedMessage} ${skippedFiles
+ .slice(0, MAX_SKIPPED_FILES_LISTINGS)
+ .map(({ filename }) => filename)
+ .join(', ')}${skippedFiles.length > MAX_SKIPPED_FILES_LISTINGS ? `, ${moreText}` : '.'}`;
+};
+
+export const designDeletionError = ({ singular = true } = {}) => {
+ const design = singular ? __('a design') : __('designs');
+ return sprintf(s__('Could not delete %{design}. Please try again.'), {
+ design,
+ });
+};
+
+/**
+ * Return warning message, if applicable, that one, some or all uploaded
+ * files were skipped.
+ * @param {Array<{ filename }>} uploadedDesigns
+ * @param {Array<{ filename }>} skippedFiles
+ */
+export const designUploadSkippedWarning = (uploadedDesigns, skippedFiles) => {
+ if (skippedFiles.length === 0) {
+ return null;
+ }
+
+ if (skippedFiles.length === uploadedDesigns.length) {
+ const { filename } = skippedFiles[0];
+
+ return n__(oneDesignSkippedMessage(filename), ALL_DESIGNS_SKIPPED_MESSAGE, skippedFiles.length);
+ }
+
+ return someDesignsSkippedMessage(skippedFiles);
+};
diff --git a/app/assets/javascripts/design_management_new/utils/tracking.js b/app/assets/javascripts/design_management_new/utils/tracking.js
new file mode 100644
index 00000000000..39c20376271
--- /dev/null
+++ b/app/assets/javascripts/design_management_new/utils/tracking.js
@@ -0,0 +1,28 @@
+import Tracking from '~/tracking';
+
+function assembleDesignPayload(payloadArr) {
+ return {
+ value: {
+ 'internal-object-refrerer': payloadArr[0],
+ 'design-collection-owner': payloadArr[1],
+ 'design-version-number': payloadArr[2],
+ 'design-is-current-version': payloadArr[3],
+ },
+ };
+}
+
+// Tracking Constants
+const DESIGN_TRACKING_PAGE_NAME = 'projects:issues:design';
+
+// eslint-disable-next-line import/prefer-default-export
+export function trackDesignDetailView(
+ referer = '',
+ owner = '',
+ designVersion = 1,
+ latestVersion = false,
+) {
+ Tracking.event(DESIGN_TRACKING_PAGE_NAME, 'design_viewed', {
+ label: 'design_viewed',
+ ...assembleDesignPayload([referer, owner, designVersion, latestVersion]),
+ });
+}
diff --git a/app/assets/javascripts/pages/projects/issues/show.js b/app/assets/javascripts/pages/projects/issues/show.js
index 46c9b2fe0af..e700d2bef47 100644
--- a/app/assets/javascripts/pages/projects/issues/show.js
+++ b/app/assets/javascripts/pages/projects/issues/show.js
@@ -13,14 +13,15 @@ export default function() {
initSentryErrorStackTraceApp();
initRelatedMergeRequestsApp();
- // .js-design-management is currently EE-only.
- // This will be moved to CE as part of https://gitlab.com/gitlab-org/gitlab/-/issues/212566#frontend
- // at which point this conditional can be removed.
- if (document.querySelector('.js-design-management')) {
- import(/* webpackChunkName: 'design_management' */ '~/design_management')
- .then(module => module.default())
- .catch(() => {});
- }
+ import(/* webpackChunkName: 'design_management' */ '~/design_management')
+ .then(module => module.default())
+ .catch(() => {});
+
+ // This will be removed when we remove the `design_management_moved` feature flag
+ // See https://gitlab.com/gitlab-org/gitlab/-/issues/223197
+ import(/* webpackChunkName: 'design_management' */ '~/design_management_new')
+ .then(module => module.default())
+ .catch(() => {});
new Issue(); // eslint-disable-line no-new
new ShortcutsIssuable(); // eslint-disable-line no-new
diff --git a/app/views/projects/issues/_design_management.html.haml b/app/views/projects/issues/_design_management.html.haml
index 96f1dc0155c..7bb0991aabd 100644
--- a/app/views/projects/issues/_design_management.html.haml
+++ b/app/views/projects/issues/_design_management.html.haml
@@ -1,5 +1,8 @@
- if @project.design_management_enabled?
- .js-design-management{ data: { project_path: @project.full_path, issue_iid: @issue.iid, issue_path: project_issue_path(@project, @issue) } }
+ - if Feature.enabled?(:design_management_moved, @project)
+ .js-design-management-new{ data: { project_path: @project.full_path, issue_iid: @issue.iid, issue_path: project_issue_path(@project, @issue) } }
+ - else
+ .js-design-management{ data: { project_path: @project.full_path, issue_iid: @issue.iid, issue_path: project_issue_path(@project, @issue) } }
- else
.mt-4
.row.empty-state
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index ab4bd88cfe5..00113b2c2c0 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -42,7 +42,7 @@
= _('Milestone')
= icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- if can_edit_issuable
- = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { track_label: "right_sidebar", track_property: "milestone", track_event: "click_edit_button", track_value: "" }
+ = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { qa_selector: "edit_milestone_link", track_label: "right_sidebar", track_property: "milestone", track_event: "click_edit_button", track_value: "" }
.value.hide-collapsed
- if milestone.present?
= link_to milestone[:title], milestone[:web_url], class: "bold has-tooltip", title: sidebar_milestone_remaining_days(milestone), data: { container: "body", html: 'true', boundary: 'viewport', qa_selector: 'milestone_link', qa_title: milestone[:title] }
@@ -107,7 +107,7 @@
= _('Labels')
= icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- if can_edit_issuable
- = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link qa-edit-link-labels float-right', data: { track_label: "right_sidebar", track_property: "labels", track_event: "click_edit_button", track_value: "" }
+ = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { qa_selector: "edit_labels_link", track_label: "right_sidebar", track_property: "labels", track_event: "click_edit_button", track_value: "" }
.value.issuable-show-labels.dont-hide.hide-collapsed{ class: ("has-labels" if selected_labels.any?), data: { qa_selector: 'labels_block' } }
- if selected_labels.any?
- selected_labels.each do |label_hash|
diff --git a/changelogs/unreleased/223171_allow_erb_extension_for_sse.yml b/changelogs/unreleased/223171_allow_erb_extension_for_sse.yml
new file mode 100644
index 00000000000..7feae278c54
--- /dev/null
+++ b/changelogs/unreleased/223171_allow_erb_extension_for_sse.yml
@@ -0,0 +1,5 @@
+---
+title: Allow files with .md.erb extension for the Static Site Editor
+merge_request: 35136
+author:
+type: added
diff --git a/changelogs/unreleased/223185-add-project-key-to-jira-tracker-data.yml b/changelogs/unreleased/223185-add-project-key-to-jira-tracker-data.yml
new file mode 100644
index 00000000000..ddfcb337c11
--- /dev/null
+++ b/changelogs/unreleased/223185-add-project-key-to-jira-tracker-data.yml
@@ -0,0 +1,5 @@
+---
+title: Add project_key column to jira_tracker_data table
+merge_request: 34949
+author:
+type: other
diff --git a/changelogs/unreleased/upgrade-codequality-template.yml b/changelogs/unreleased/upgrade-codequality-template.yml
new file mode 100644
index 00000000000..7af201cddd0
--- /dev/null
+++ b/changelogs/unreleased/upgrade-codequality-template.yml
@@ -0,0 +1,5 @@
+---
+title: Use CodeQuality 0.85.10 in the CI template
+merge_request: 34329
+author:
+type: changed
diff --git a/db/migrate/20200619154527_add_project_key_to_jira_tracker_data.rb b/db/migrate/20200619154527_add_project_key_to_jira_tracker_data.rb
new file mode 100644
index 00000000000..574eb99a6cc
--- /dev/null
+++ b/db/migrate/20200619154527_add_project_key_to_jira_tracker_data.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class AddProjectKeyToJiraTrackerData < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # limit is added in 20200619154528_add_text_limit_to_jira_tracker_data_project_key
+ def change
+ add_column :jira_tracker_data, :project_key, :text
+ end
+ # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20200619154528_add_text_limit_to_jira_tracker_data_project_key.rb b/db/migrate/20200619154528_add_text_limit_to_jira_tracker_data_project_key.rb
new file mode 100644
index 00000000000..6cf8a787381
--- /dev/null
+++ b/db/migrate/20200619154528_add_text_limit_to_jira_tracker_data_project_key.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddTextLimitToJiraTrackerDataProjectKey < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :jira_tracker_data, :project_key, 255
+ end
+
+ def down
+ remove_text_limit :jira_tracker_data, :project_key
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index e3c57c15fe6..4721c7ed809 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -3655,7 +3655,9 @@ CREATE TABLE public.jira_tracker_data (
encrypted_username_iv character varying,
encrypted_password character varying,
encrypted_password_iv character varying,
- jira_issue_transition_id character varying
+ jira_issue_transition_id character varying,
+ project_key text,
+ CONSTRAINT check_214cf6a48b CHECK ((char_length(project_key) <= 255))
);
CREATE SEQUENCE public.jira_tracker_data_id_seq
@@ -14113,6 +14115,8 @@ COPY "schema_migrations" (version) FROM STDIN;
20200618105638
20200618134223
20200618134723
+20200619154527
+20200619154528
20200622103836
20200622235737
20200623000148
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index 44802214d7b..d9552f68194 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -526,14 +526,14 @@ To enable it:
```ruby
# Instance-wide
-Feature.enable(:batched_suggestions)
+Feature.enable(:batch_suggestions)
```
To disable it:
```ruby
# Instance-wide
-Feature.disable(:batched_suggestions)
+Feature.disable(:batch_suggestions)
```
## Start a thread by replying to a standard comment
diff --git a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
index bde6f185d3a..088b1feff7c 100644
--- a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
@@ -7,7 +7,7 @@ code_quality:
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
- CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.9"
+ CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.10"
script:
- |
if ! docker info &>/dev/null; then
diff --git a/lib/gitlab/static_site_editor/config.rb b/lib/gitlab/static_site_editor/config.rb
index 65c567ec2a6..ddafbb22a6d 100644
--- a/lib/gitlab/static_site_editor/config.rb
+++ b/lib/gitlab/static_site_editor/config.rb
@@ -3,7 +3,7 @@
module Gitlab
module StaticSiteEditor
class Config
- SUPPORTED_EXTENSIONS = %w[.md].freeze
+ SUPPORTED_EXTENSIONS = %w[.md .md.erb].freeze
def initialize(repository, ref, file_path, return_url)
@repository = repository
@@ -42,11 +42,11 @@ module Gitlab
end
def extension_supported?
- File.extname(file_path).in?(SUPPORTED_EXTENSIONS)
+ SUPPORTED_EXTENSIONS.any? { |ext| file_path.end_with?(ext) }
end
def file_exists?
- commit_id.present? && repository.blob_at(commit_id, file_path).present?
+ commit_id.present? && !repository.blob_at(commit_id, file_path).nil?
end
def full_path
diff --git a/qa/qa/page/component/issuable/sidebar.rb b/qa/qa/page/component/issuable/sidebar.rb
index 175477c7aef..1bb13b4cd20 100644
--- a/qa/qa/page/component/issuable/sidebar.rb
+++ b/qa/qa/page/component/issuable/sidebar.rb
@@ -25,13 +25,27 @@ module QA
base.view 'app/views/shared/issuable/_sidebar.html.haml' do
element :assignee_block
element :dropdown_menu_labels
- element :edit_link_labels
+ element :edit_labels_link
+ element :edit_milestone_link
element :labels_block
element :milestone_block
element :milestone_link
end
end
+ def assign_milestone(milestone)
+ click_element(:edit_milestone_link)
+ within_element(:milestone_block) do
+ click_link("#{milestone.title}")
+ end
+
+ wait_until(reload: false) do
+ has_element?(:milestone_block, text: milestone.title, wait: 0)
+ end
+
+ refresh
+ end
+
def click_milestone_link
click_element(:milestone_link)
end
@@ -55,7 +69,7 @@ module QA
end
def has_milestone?(milestone_title)
- within_element(:milestone_block) do
+ wait_milestone_block_finish_loading do
has_element?(:milestone_link, title: milestone_title)
end
end
@@ -66,7 +80,7 @@ module QA
def select_labels_and_refresh(labels)
Support::Retrier.retry_until do
- click_element(:edit_link_labels)
+ click_element(:edit_labels_link)
has_element?(:dropdown_menu_labels, text: labels.first)
end
@@ -76,7 +90,7 @@ module QA
end
end
- click_element(:edit_link_labels)
+ click_element(:edit_labels_link)
labels.each do |label|
has_element?(:labels_block, text: label, wait: 0)
@@ -103,6 +117,15 @@ module QA
end
end
end
+
+ def wait_milestone_block_finish_loading
+ within_element(:milestone_block) do
+ wait_until(reload: false, max_duration: 10, sleep_interval: 1) do
+ finished_loading_block?
+ yield
+ end
+ end
+ end
end
end
end
diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb
index b4295a35263..d96d8d744d2 100644
--- a/qa/qa/resource/issue.rb
+++ b/qa/qa/resource/issue.rb
@@ -34,6 +34,7 @@ module QA
Page::Project::Issue::New.perform do |new_page|
new_page.fill_title(@title)
new_page.fill_description(@description)
+ new_page.choose_milestone(@milestone) if @milestone
new_page.create_new_issue
end
end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_project_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_project_milestone_spec.rb
new file mode 100644
index 00000000000..e7d7e160741
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_project_milestone_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module QA
+ context 'Plan' do
+ describe 'Project milestone' do
+ include Support::Dates
+
+ let(:title) { 'Project milestone' }
+ let(:start_date) { current_date_yyyy_mm_dd }
+ let(:due_date) { next_month_yyyy_mm_dd }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project-to-test-milestones'
+ end
+ end
+
+ let(:issue) do
+ Resource::Issue.fabricate_via_api! do |issue|
+ issue.project = project
+ end
+ end
+
+ let(:project_milestone) do
+ Resource::ProjectMilestone.fabricate_via_api! do |milestone|
+ milestone.project = project
+ milestone.start_date = start_date
+ milestone.due_date = due_date
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ it 'assigns a project milestone to an existing issue' do
+ issue.visit!
+
+ Page::Project::Issue::Show.perform do |existing_issue|
+ existing_issue.assign_milestone(project_milestone)
+
+ expect(existing_issue).to have_milestone(project_milestone.title)
+ end
+ end
+
+ it 'assigns a project milestone to a new issue' do
+ Resource::Issue.fabricate_via_browser_ui! do |issue|
+ issue.project = project
+ issue.milestone = project_milestone
+ end
+
+ Page::Project::Issue::Show.perform do |issue|
+ expect(issue).to have_milestone(project_milestone.title)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb b/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb
index 8d5e99d7e2b..1b3231bf9ee 100644
--- a/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb
+++ b/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb
@@ -27,6 +27,10 @@ RSpec.describe 'viewing issues with design references' do
MD
end
+ before do
+ stub_feature_flags(design_management_moved: false)
+ end
+
def visit_page_with_design_references
public_issue = create(:issue, project: public_project, description: description)
visit project_issue_path(public_issue.project, public_issue)
diff --git a/spec/features/projects/issues/design_management/user_paginates_designs_spec.rb b/spec/features/projects/issues/design_management/user_paginates_designs_spec.rb
index f871ca60596..72638125f09 100644
--- a/spec/features/projects/issues/design_management/user_paginates_designs_spec.rb
+++ b/spec/features/projects/issues/design_management/user_paginates_designs_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe 'User paginates issue designs', :js do
before do
enable_design_management
+ stub_feature_flags(design_management_moved: false)
create_list(:design, 2, :with_file, issue: issue)
diff --git a/spec/features/projects/issues/design_management/user_permissions_upload_spec.rb b/spec/features/projects/issues/design_management/user_permissions_upload_spec.rb
index 902a84afc83..25686774e7d 100644
--- a/spec/features/projects/issues/design_management/user_permissions_upload_spec.rb
+++ b/spec/features/projects/issues/design_management/user_permissions_upload_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe 'User design permissions', :js do
before do
enable_design_management
+ stub_feature_flags(design_management_moved: false)
visit project_issue_path(project, issue)
diff --git a/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
index 66b449a9de5..0861c0bd631 100644
--- a/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
+++ b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
@@ -16,6 +16,7 @@ RSpec.describe 'User uploads new design', :js do
context "when the feature is available" do
before do
enable_design_management
+ stub_feature_flags(design_management_moved: false)
visit project_issue_path(project, issue)
diff --git a/spec/features/projects/issues/design_management/user_views_design_images_spec.rb b/spec/features/projects/issues/design_management/user_views_design_images_spec.rb
index 4a4c33cb881..14c418e26b8 100644
--- a/spec/features/projects/issues/design_management/user_views_design_images_spec.rb
+++ b/spec/features/projects/issues/design_management/user_views_design_images_spec.rb
@@ -13,6 +13,7 @@ RSpec.describe 'Users views raw design image files' do
before do
enable_design_management
+ stub_feature_flags(design_management_moved: false)
end
it 'serves the latest design version when no ref is given' do
diff --git a/spec/features/projects/issues/design_management/user_views_design_spec.rb b/spec/features/projects/issues/design_management/user_views_design_spec.rb
index 527442d5339..da2928e9092 100644
--- a/spec/features/projects/issues/design_management/user_views_design_spec.rb
+++ b/spec/features/projects/issues/design_management/user_views_design_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe 'User views issue designs', :js do
before do
enable_design_management
+ stub_feature_flags(design_management_moved: false)
visit project_issue_path(project, issue)
diff --git a/spec/features/projects/issues/design_management/user_views_designs_spec.rb b/spec/features/projects/issues/design_management/user_views_designs_spec.rb
index d371ae1aad7..5d6571f8339 100644
--- a/spec/features/projects/issues/design_management/user_views_designs_spec.rb
+++ b/spec/features/projects/issues/design_management/user_views_designs_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe 'User views issue designs', :js do
before do
enable_design_management
+ stub_feature_flags(design_management_moved: false)
end
context 'navigates from the issue view' do
diff --git a/spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb b/spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb
index 5bc1271309c..bde8df0393b 100644
--- a/spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb
+++ b/spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe 'User views an SVG design that contains XSS', :js do
before do
enable_design_management
+ stub_feature_flags(design_management_moved: false)
visit designs_project_issue_path(
project,
diff --git a/spec/frontend/design_management_new/components/__snapshots__/design_note_pin_spec.js.snap b/spec/frontend/design_management_new/components/__snapshots__/design_note_pin_spec.js.snap
new file mode 100644
index 00000000000..4c848256e5b
--- /dev/null
+++ b/spec/frontend/design_management_new/components/__snapshots__/design_note_pin_spec.js.snap
@@ -0,0 +1,42 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design note pin component should match the snapshot of note when repositioning 1`] = `
+<button
+ aria-label="Comment form position"
+ class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center btn-transparent comment-indicator"
+ style="left: 10px; top: 10px; cursor: move;"
+ type="button"
+>
+ <icon-stub
+ name="image-comment-dark"
+ size="16"
+ />
+</button>
+`;
+
+exports[`Design note pin component should match the snapshot of note with index 1`] = `
+<button
+ aria-label="Comment '1' position"
+ class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center js-image-badge badge badge-pill"
+ style="left: 10px; top: 10px;"
+ type="button"
+>
+
+ 1
+
+</button>
+`;
+
+exports[`Design note pin component should match the snapshot of note without index 1`] = `
+<button
+ aria-label="Comment form position"
+ class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center btn-transparent comment-indicator"
+ style="left: 10px; top: 10px;"
+ type="button"
+>
+ <icon-stub
+ name="image-comment-dark"
+ size="16"
+ />
+</button>
+`;
diff --git a/spec/frontend/design_management_new/components/__snapshots__/design_presentation_spec.js.snap b/spec/frontend/design_management_new/components/__snapshots__/design_presentation_spec.js.snap
new file mode 100644
index 00000000000..189962c5b2e
--- /dev/null
+++ b/spec/frontend/design_management_new/components/__snapshots__/design_presentation_spec.js.snap
@@ -0,0 +1,104 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management design presentation component currentCommentForm is equal to current annotation position when isAnnotating is true 1`] = `
+<div
+ class="h-100 w-100 p-3 overflow-auto position-relative"
+>
+ <div
+ class="h-100 w-100 d-flex align-items-center position-relative"
+ >
+ <design-image-stub
+ image="test.jpg"
+ name="test"
+ scale="1"
+ />
+
+ <design-overlay-stub
+ currentcommentform="[object Object]"
+ dimensions="[object Object]"
+ notes=""
+ position="[object Object]"
+ />
+ </div>
+</div>
+`;
+
+exports[`Design management design presentation component currentCommentForm is null when isAnnotating is false 1`] = `
+<div
+ class="h-100 w-100 p-3 overflow-auto position-relative"
+>
+ <div
+ class="h-100 w-100 d-flex align-items-center position-relative"
+ >
+ <design-image-stub
+ image="test.jpg"
+ name="test"
+ scale="1"
+ />
+
+ <design-overlay-stub
+ dimensions="[object Object]"
+ notes=""
+ position="[object Object]"
+ />
+ </div>
+</div>
+`;
+
+exports[`Design management design presentation component currentCommentForm is null when isAnnotating is true but annotation position is falsey 1`] = `
+<div
+ class="h-100 w-100 p-3 overflow-auto position-relative"
+>
+ <div
+ class="h-100 w-100 d-flex align-items-center position-relative"
+ >
+ <design-image-stub
+ image="test.jpg"
+ name="test"
+ scale="1"
+ />
+
+ <design-overlay-stub
+ dimensions="[object Object]"
+ notes=""
+ position="[object Object]"
+ />
+ </div>
+</div>
+`;
+
+exports[`Design management design presentation component renders empty state when no image provided 1`] = `
+<div
+ class="h-100 w-100 p-3 overflow-auto position-relative"
+>
+ <div
+ class="h-100 w-100 d-flex align-items-center position-relative"
+ >
+ <!---->
+
+ <!---->
+ </div>
+</div>
+`;
+
+exports[`Design management design presentation component renders image and overlay when image provided 1`] = `
+<div
+ class="h-100 w-100 p-3 overflow-auto position-relative"
+>
+ <div
+ class="h-100 w-100 d-flex align-items-center position-relative"
+ >
+ <design-image-stub
+ image="test.jpg"
+ name="test"
+ scale="1"
+ />
+
+ <design-overlay-stub
+ dimensions="[object Object]"
+ notes=""
+ position="[object Object]"
+ />
+ </div>
+</div>
+`;
diff --git a/spec/frontend/design_management_new/components/__snapshots__/design_scaler_spec.js.snap b/spec/frontend/design_management_new/components/__snapshots__/design_scaler_spec.js.snap
new file mode 100644
index 00000000000..cb4575cbd11
--- /dev/null
+++ b/spec/frontend/design_management_new/components/__snapshots__/design_scaler_spec.js.snap
@@ -0,0 +1,115 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management design scaler component minus and reset buttons are disabled when scale === 1 1`] = `
+<div
+ class="design-scaler btn-group"
+ role="group"
+>
+ <button
+ class="btn"
+ disabled="disabled"
+ >
+ <span
+ class="d-flex-center gl-icon s16"
+ >
+
+ –
+
+ </span>
+ </button>
+
+ <button
+ class="btn"
+ disabled="disabled"
+ >
+ <gl-icon-stub
+ name="redo"
+ size="16"
+ />
+ </button>
+
+ <button
+ class="btn"
+ >
+ <gl-icon-stub
+ name="plus"
+ size="16"
+ />
+ </button>
+</div>
+`;
+
+exports[`Design management design scaler component minus and reset buttons are enabled when scale > 1 1`] = `
+<div
+ class="design-scaler btn-group"
+ role="group"
+>
+ <button
+ class="btn"
+ >
+ <span
+ class="d-flex-center gl-icon s16"
+ >
+
+ –
+
+ </span>
+ </button>
+
+ <button
+ class="btn"
+ >
+ <gl-icon-stub
+ name="redo"
+ size="16"
+ />
+ </button>
+
+ <button
+ class="btn"
+ >
+ <gl-icon-stub
+ name="plus"
+ size="16"
+ />
+ </button>
+</div>
+`;
+
+exports[`Design management design scaler component plus button is disabled when scale === 2 1`] = `
+<div
+ class="design-scaler btn-group"
+ role="group"
+>
+ <button
+ class="btn"
+ >
+ <span
+ class="d-flex-center gl-icon s16"
+ >
+
+ –
+
+ </span>
+ </button>
+
+ <button
+ class="btn"
+ >
+ <gl-icon-stub
+ name="redo"
+ size="16"
+ />
+ </button>
+
+ <button
+ class="btn"
+ disabled="disabled"
+ >
+ <gl-icon-stub
+ name="plus"
+ size="16"
+ />
+ </button>
+</div>
+`;
diff --git a/spec/frontend/design_management_new/components/__snapshots__/image_spec.js.snap b/spec/frontend/design_management_new/components/__snapshots__/image_spec.js.snap
new file mode 100644
index 00000000000..acaa62b11eb
--- /dev/null
+++ b/spec/frontend/design_management_new/components/__snapshots__/image_spec.js.snap
@@ -0,0 +1,68 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management large image component renders image 1`] = `
+<div
+ class="m-auto js-design-image"
+>
+ <!---->
+
+ <img
+ alt="test"
+ class="mh-100 img-fluid"
+ src="test.jpg"
+ />
+</div>
+`;
+
+exports[`Design management large image component renders loading state 1`] = `
+<div
+ class="m-auto js-design-image"
+ isloading="true"
+>
+ <!---->
+
+ <img
+ alt=""
+ class="mh-100 img-fluid"
+ src=""
+ />
+</div>
+`;
+
+exports[`Design management large image component renders media broken icon on error 1`] = `
+<gl-icon-stub
+ class="text-secondary-100"
+ name="media-broken"
+ size="48"
+/>
+`;
+
+exports[`Design management large image component sets correct classes and styles if imageStyle is set 1`] = `
+<div
+ class="m-auto js-design-image"
+>
+ <!---->
+
+ <img
+ alt="test"
+ class="mh-100"
+ src="test.jpg"
+ style="width: 100px; height: 100px;"
+ />
+</div>
+`;
+
+exports[`Design management large image component zoom sets image style when zoomed 1`] = `
+<div
+ class="m-auto js-design-image"
+>
+ <!---->
+
+ <img
+ alt="test"
+ class="mh-100"
+ src="test.jpg"
+ style="width: 200px; height: 200px;"
+ />
+</div>
+`;
diff --git a/spec/frontend/design_management_new/components/delete_button_spec.js b/spec/frontend/design_management_new/components/delete_button_spec.js
new file mode 100644
index 00000000000..700a178828d
--- /dev/null
+++ b/spec/frontend/design_management_new/components/delete_button_spec.js
@@ -0,0 +1,51 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlDeprecatedButton, GlModal, GlModalDirective } from '@gitlab/ui';
+import BatchDeleteButton from '~/design_management_new/components/delete_button.vue';
+
+describe('Batch delete button component', () => {
+ let wrapper;
+
+ const findButton = () => wrapper.find(GlDeprecatedButton);
+ const findModal = () => wrapper.find(GlModal);
+
+ function createComponent(isDeleting = false) {
+ wrapper = shallowMount(BatchDeleteButton, {
+ propsData: {
+ isDeleting,
+ },
+ directives: {
+ GlModalDirective,
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders non-disabled button by default', () => {
+ createComponent();
+
+ expect(findButton().exists()).toBe(true);
+ expect(findButton().attributes('disabled')).toBeFalsy();
+ });
+
+ it('renders disabled button when design is deleting', () => {
+ createComponent(true);
+ expect(findButton().attributes('disabled')).toBeTruthy();
+ });
+
+ it('emits `deleteSelectedDesigns` event on modal ok click', () => {
+ createComponent();
+ findButton().vm.$emit('click');
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ findModal().vm.$emit('ok');
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ expect(wrapper.emitted().deleteSelectedDesigns).toBeTruthy();
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/design_note_pin_spec.js b/spec/frontend/design_management_new/components/design_note_pin_spec.js
new file mode 100644
index 00000000000..8e2caa604f4
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_note_pin_spec.js
@@ -0,0 +1,49 @@
+import { shallowMount } from '@vue/test-utils';
+import DesignNotePin from '~/design_management_new/components/design_note_pin.vue';
+
+describe('Design note pin component', () => {
+ let wrapper;
+
+ function createComponent(propsData = {}) {
+ wrapper = shallowMount(DesignNotePin, {
+ propsData: {
+ position: {
+ left: '10px',
+ top: '10px',
+ },
+ ...propsData,
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should match the snapshot of note without index', () => {
+ createComponent();
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('should match the snapshot of note with index', () => {
+ createComponent({ label: 1 });
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('should match the snapshot of note when repositioning', () => {
+ createComponent({ repositioning: true });
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ describe('pinStyle', () => {
+ it('sets cursor to `move` when repositioning = true', () => {
+ createComponent({ repositioning: true });
+ expect(wrapper.vm.pinStyle.cursor).toBe('move');
+ });
+
+ it('does not set cursor when repositioning = false', () => {
+ createComponent();
+ expect(wrapper.vm.pinStyle.cursor).toBe(undefined);
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/design_notes/__snapshots__/design_note_spec.js.snap b/spec/frontend/design_management_new/components/design_notes/__snapshots__/design_note_spec.js.snap
new file mode 100644
index 00000000000..b55bacb6fc5
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_notes/__snapshots__/design_note_spec.js.snap
@@ -0,0 +1,67 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design note component should match the snapshot 1`] = `
+<timeline-entry-item-stub
+ class="design-note note-form"
+ id="note_123"
+>
+ <user-avatar-link-stub
+ imgalt=""
+ imgcssclasses=""
+ imgsize="40"
+ imgsrc=""
+ linkhref=""
+ tooltipplacement="top"
+ tooltiptext=""
+ username=""
+ />
+
+ <div
+ class="d-flex justify-content-between"
+ >
+ <div>
+ <a
+ class="js-user-link"
+ data-user-id="author-id"
+ >
+ <span
+ class="note-header-author-name bold"
+ >
+
+ </span>
+
+ <!---->
+
+ <span
+ class="note-headline-light"
+ >
+ @
+ </span>
+ </a>
+
+ <span
+ class="note-headline-light note-headline-meta"
+ >
+ <span
+ class="system-note-message"
+ />
+
+ <!---->
+ </span>
+ </div>
+
+ <div
+ class="gl-display-flex"
+ >
+
+ <!---->
+ </div>
+ </div>
+
+ <div
+ class="note-text js-note-text md"
+ data-qa-selector="note_content"
+ />
+
+</timeline-entry-item-stub>
+`;
diff --git a/spec/frontend/design_management_new/components/design_notes/__snapshots__/design_reply_form_spec.js.snap b/spec/frontend/design_management_new/components/design_notes/__snapshots__/design_reply_form_spec.js.snap
new file mode 100644
index 00000000000..e01c79e3520
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_notes/__snapshots__/design_reply_form_spec.js.snap
@@ -0,0 +1,15 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design reply form component renders button text as "Comment" when creating a comment 1`] = `
+"<button data-track-event=\\"click_button\\" data-qa-selector=\\"save_comment_button\\" type=\\"submit\\" disabled=\\"disabled\\" class=\\"btn btn-success btn-md disabled\\">
+ <!---->
+ Comment
+</button>"
+`;
+
+exports[`Design reply form component renders button text as "Save comment" when creating a comment 1`] = `
+"<button data-track-event=\\"click_button\\" data-qa-selector=\\"save_comment_button\\" type=\\"submit\\" disabled=\\"disabled\\" class=\\"btn btn-success btn-md disabled\\">
+ <!---->
+ Save comment
+</button>"
+`;
diff --git a/spec/frontend/design_management_new/components/design_notes/design_discussion_spec.js b/spec/frontend/design_management_new/components/design_notes/design_discussion_spec.js
new file mode 100644
index 00000000000..4c6db8a9ce0
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_notes/design_discussion_spec.js
@@ -0,0 +1,318 @@
+import { mount } from '@vue/test-utils';
+import { GlLoadingIcon } from '@gitlab/ui';
+import notes from '../../mock_data/notes';
+import DesignDiscussion from '~/design_management_new/components/design_notes/design_discussion.vue';
+import DesignNote from '~/design_management_new/components/design_notes/design_note.vue';
+import DesignReplyForm from '~/design_management_new/components/design_notes/design_reply_form.vue';
+import createNoteMutation from '~/design_management_new/graphql/mutations/create_note.mutation.graphql';
+import toggleResolveDiscussionMutation from '~/design_management_new/graphql/mutations/toggle_resolve_discussion.mutation.graphql';
+import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue';
+import ToggleRepliesWidget from '~/design_management_new/components/design_notes/toggle_replies_widget.vue';
+
+const discussion = {
+ id: '0',
+ resolved: false,
+ resolvable: true,
+ notes,
+};
+
+describe('Design discussions component', () => {
+ let wrapper;
+
+ const findDesignNotes = () => wrapper.findAll(DesignNote);
+ const findReplyPlaceholder = () => wrapper.find(ReplyPlaceholder);
+ const findReplyForm = () => wrapper.find(DesignReplyForm);
+ const findRepliesWidget = () => wrapper.find(ToggleRepliesWidget);
+ const findResolveButton = () => wrapper.find('[data-testid="resolve-button"]');
+ const findResolveIcon = () => wrapper.find('[data-testid="resolve-icon"]');
+ const findResolvedMessage = () => wrapper.find('[data-testid="resolved-message"]');
+ const findResolveLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findResolveCheckbox = () => wrapper.find('[data-testid="resolve-checkbox"]');
+
+ const mutationVariables = {
+ mutation: createNoteMutation,
+ update: expect.anything(),
+ variables: {
+ input: {
+ noteableId: 'noteable-id',
+ body: 'test',
+ discussionId: '0',
+ },
+ },
+ };
+ const mutate = jest.fn(() => Promise.resolve());
+ const $apollo = {
+ mutate,
+ };
+
+ function createComponent(props = {}, data = {}) {
+ wrapper = mount(DesignDiscussion, {
+ propsData: {
+ resolvedDiscussionsExpanded: true,
+ discussion,
+ noteableId: 'noteable-id',
+ designId: 'design-id',
+ discussionIndex: 1,
+ discussionWithOpenForm: '',
+ ...props,
+ },
+ data() {
+ return {
+ ...data,
+ };
+ },
+ mocks: {
+ $apollo,
+ $route: {
+ hash: '#note_1',
+ },
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when discussion is not resolvable', () => {
+ beforeEach(() => {
+ createComponent({
+ discussion: {
+ ...discussion,
+ resolvable: false,
+ },
+ });
+ });
+
+ it('does not render an icon to resolve a thread', () => {
+ expect(findResolveIcon().exists()).toBe(false);
+ });
+
+ it('does not render a checkbox in reply form', () => {
+ findReplyPlaceholder().vm.$emit('onMouseDown');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findResolveCheckbox().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('when discussion is unresolved', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders correct amount of discussion notes', () => {
+ expect(findDesignNotes()).toHaveLength(2);
+ expect(findDesignNotes().wrappers.every(w => w.isVisible())).toBe(true);
+ });
+
+ it('renders reply placeholder', () => {
+ expect(findReplyPlaceholder().isVisible()).toBe(true);
+ });
+
+ it('does not render toggle replies widget', () => {
+ expect(findRepliesWidget().exists()).toBe(false);
+ });
+
+ it('renders a correct icon to resolve a thread', () => {
+ expect(findResolveIcon().props('name')).toBe('check-circle');
+ });
+
+ it('renders a checkbox with Resolve thread text in reply form', () => {
+ findReplyPlaceholder().vm.$emit('onClick');
+ wrapper.setProps({ discussionWithOpenForm: discussion.id });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findResolveCheckbox().text()).toBe('Resolve thread');
+ });
+ });
+
+ it('does not render resolved message', () => {
+ expect(findResolvedMessage().exists()).toBe(false);
+ });
+ });
+
+ describe('when discussion is resolved', () => {
+ beforeEach(() => {
+ createComponent({
+ discussion: {
+ ...discussion,
+ resolved: true,
+ resolvedBy: notes[0].author,
+ resolvedAt: '2020-05-08T07:10:45Z',
+ },
+ });
+ });
+
+ it('shows only the first note', () => {
+ expect(
+ findDesignNotes()
+ .at(0)
+ .isVisible(),
+ ).toBe(true);
+ expect(
+ findDesignNotes()
+ .at(1)
+ .isVisible(),
+ ).toBe(false);
+ });
+
+ it('renders resolved message', () => {
+ expect(findResolvedMessage().exists()).toBe(true);
+ });
+
+ it('does not show renders reply placeholder', () => {
+ expect(findReplyPlaceholder().isVisible()).toBe(false);
+ });
+
+ it('renders toggle replies widget with correct props', () => {
+ expect(findRepliesWidget().exists()).toBe(true);
+ expect(findRepliesWidget().props()).toEqual({
+ collapsed: true,
+ replies: notes.slice(1),
+ });
+ });
+
+ it('renders a correct icon to resolve a thread', () => {
+ expect(findResolveIcon().props('name')).toBe('check-circle-filled');
+ });
+
+ describe('when replies are expanded', () => {
+ beforeEach(() => {
+ findRepliesWidget().vm.$emit('toggle');
+ return wrapper.vm.$nextTick();
+ });
+
+ it('renders replies widget with collapsed prop equal to false', () => {
+ expect(findRepliesWidget().props('collapsed')).toBe(false);
+ });
+
+ it('renders the second note', () => {
+ expect(
+ findDesignNotes()
+ .at(1)
+ .isVisible(),
+ ).toBe(true);
+ });
+
+ it('renders a reply placeholder', () => {
+ expect(findReplyPlaceholder().isVisible()).toBe(true);
+ });
+
+ it('renders a checkbox with Unresolve thread text in reply form', () => {
+ findReplyPlaceholder().vm.$emit('onClick');
+ wrapper.setProps({ discussionWithOpenForm: discussion.id });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findResolveCheckbox().text()).toBe('Unresolve thread');
+ });
+ });
+ });
+ });
+
+ it('hides reply placeholder and opens form on placeholder click', () => {
+ createComponent();
+ findReplyPlaceholder().vm.$emit('onClick');
+ wrapper.setProps({ discussionWithOpenForm: discussion.id });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findReplyPlaceholder().exists()).toBe(false);
+ expect(findReplyForm().exists()).toBe(true);
+ });
+ });
+
+ it('calls mutation on submitting form and closes the form', () => {
+ createComponent(
+ { discussionWithOpenForm: discussion.id },
+ { discussionComment: 'test', isFormRendered: true },
+ );
+
+ findReplyForm().vm.$emit('submitForm');
+ expect(mutate).toHaveBeenCalledWith(mutationVariables);
+
+ return mutate()
+ .then(() => {
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ expect(findReplyForm().exists()).toBe(false);
+ });
+ });
+
+ it('clears the discussion comment on closing comment form', () => {
+ createComponent(
+ { discussionWithOpenForm: discussion.id },
+ { discussionComment: 'test', isFormRendered: true },
+ );
+
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ findReplyForm().vm.$emit('cancelForm');
+
+ expect(wrapper.vm.discussionComment).toBe('');
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ expect(findReplyForm().exists()).toBe(false);
+ });
+ });
+
+ it('applies correct class to design notes when discussion is highlighted', () => {
+ createComponent(
+ {},
+ {
+ activeDiscussion: {
+ id: notes[0].id,
+ source: 'pin',
+ },
+ },
+ );
+
+ expect(wrapper.findAll(DesignNote).wrappers.every(note => note.classes('gl-bg-blue-50'))).toBe(
+ true,
+ );
+ });
+
+ it('calls toggleResolveDiscussion mutation on resolve thread button click', () => {
+ createComponent();
+ findResolveButton().trigger('click');
+ expect(mutate).toHaveBeenCalledWith({
+ mutation: toggleResolveDiscussionMutation,
+ variables: {
+ id: discussion.id,
+ resolve: true,
+ },
+ });
+ return wrapper.vm.$nextTick(() => {
+ expect(findResolveLoadingIcon().exists()).toBe(true);
+ });
+ });
+
+ it('calls toggleResolveDiscussion mutation after adding a note if checkbox was checked', () => {
+ createComponent(
+ { discussionWithOpenForm: discussion.id },
+ { discussionComment: 'test', isFormRendered: true },
+ );
+ findResolveButton().trigger('click');
+ findReplyForm().vm.$emit('submitForm');
+
+ return mutate().then(() => {
+ expect(mutate).toHaveBeenCalledWith({
+ mutation: toggleResolveDiscussionMutation,
+ variables: {
+ id: discussion.id,
+ resolve: true,
+ },
+ });
+ });
+ });
+
+ it('emits openForm event on opening the form', () => {
+ createComponent();
+ findReplyPlaceholder().vm.$emit('onClick');
+
+ expect(wrapper.emitted('openForm')).toBeTruthy();
+ });
+});
diff --git a/spec/frontend/design_management_new/components/design_notes/design_note_spec.js b/spec/frontend/design_management_new/components/design_notes/design_note_spec.js
new file mode 100644
index 00000000000..b0e3e85b9c6
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_notes/design_note_spec.js
@@ -0,0 +1,170 @@
+import { shallowMount } from '@vue/test-utils';
+import { ApolloMutation } from 'vue-apollo';
+import DesignNote from '~/design_management_new/components/design_notes/design_note.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import DesignReplyForm from '~/design_management_new/components/design_notes/design_reply_form.vue';
+
+const scrollIntoViewMock = jest.fn();
+const note = {
+ id: 'gid://gitlab/DiffNote/123',
+ author: {
+ id: 'author-id',
+ },
+ body: 'test',
+ userPermissions: {
+ adminNote: false,
+ },
+};
+HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
+
+const $route = {
+ hash: '#note_123',
+};
+
+const mutate = jest.fn().mockResolvedValue({ data: { updateNote: {} } });
+
+describe('Design note component', () => {
+ let wrapper;
+
+ const findUserAvatar = () => wrapper.find(UserAvatarLink);
+ const findUserLink = () => wrapper.find('.js-user-link');
+ const findReplyForm = () => wrapper.find(DesignReplyForm);
+ const findEditButton = () => wrapper.find('.js-note-edit');
+ const findNoteContent = () => wrapper.find('.js-note-text');
+
+ function createComponent(props = {}, data = { isEditing: false }) {
+ wrapper = shallowMount(DesignNote, {
+ propsData: {
+ note: {},
+ ...props,
+ },
+ data() {
+ return {
+ ...data,
+ };
+ },
+ mocks: {
+ $route,
+ $apollo: {
+ mutate,
+ },
+ },
+ stubs: {
+ ApolloMutation,
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should match the snapshot', () => {
+ createComponent({
+ note,
+ });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('should render an author', () => {
+ createComponent({
+ note,
+ });
+
+ expect(findUserAvatar().exists()).toBe(true);
+ expect(findUserLink().exists()).toBe(true);
+ });
+
+ it('should render a time ago tooltip if note has createdAt property', () => {
+ createComponent({
+ note: {
+ ...note,
+ createdAt: '2019-07-26T15:02:20Z',
+ },
+ });
+
+ expect(wrapper.find(TimeAgoTooltip).exists()).toBe(true);
+ });
+
+ it('should trigger a scrollIntoView method', () => {
+ createComponent({
+ note,
+ });
+
+ expect(scrollIntoViewMock).toHaveBeenCalled();
+ });
+
+ it('should not render edit icon when user does not have a permission', () => {
+ createComponent({
+ note,
+ });
+
+ expect(findEditButton().exists()).toBe(false);
+ });
+
+ describe('when user has a permission to edit note', () => {
+ it('should open an edit form on edit button click', () => {
+ createComponent({
+ note: {
+ ...note,
+ userPermissions: {
+ adminNote: true,
+ },
+ },
+ });
+
+ findEditButton().trigger('click');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findReplyForm().exists()).toBe(true);
+ expect(findNoteContent().exists()).toBe(false);
+ });
+ });
+
+ describe('when edit form is rendered', () => {
+ beforeEach(() => {
+ createComponent(
+ {
+ note: {
+ ...note,
+ userPermissions: {
+ adminNote: true,
+ },
+ },
+ },
+ { isEditing: true },
+ );
+ });
+
+ it('should not render note content and should render reply form', () => {
+ expect(findNoteContent().exists()).toBe(false);
+ expect(findReplyForm().exists()).toBe(true);
+ });
+
+ it('hides the form on hideForm event', () => {
+ findReplyForm().vm.$emit('cancelForm');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findReplyForm().exists()).toBe(false);
+ expect(findNoteContent().exists()).toBe(true);
+ });
+ });
+
+ it('calls a mutation on submitForm event and hides a form', () => {
+ findReplyForm().vm.$emit('submitForm');
+ expect(mutate).toHaveBeenCalled();
+
+ return mutate()
+ .then(() => {
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ expect(findReplyForm().exists()).toBe(false);
+ expect(findNoteContent().exists()).toBe(true);
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/design_notes/design_reply_form_spec.js b/spec/frontend/design_management_new/components/design_notes/design_reply_form_spec.js
new file mode 100644
index 00000000000..9c1d6154516
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_notes/design_reply_form_spec.js
@@ -0,0 +1,184 @@
+import { mount } from '@vue/test-utils';
+import DesignReplyForm from '~/design_management_new/components/design_notes/design_reply_form.vue';
+
+const showModal = jest.fn();
+
+const GlModal = {
+ template: '<div><slot name="modal-title"></slot><slot></slot><slot name="modal-ok"></slot></div>',
+ methods: {
+ show: showModal,
+ },
+};
+
+describe('Design reply form component', () => {
+ let wrapper;
+
+ const findTextarea = () => wrapper.find('textarea');
+ const findSubmitButton = () => wrapper.find({ ref: 'submitButton' });
+ const findCancelButton = () => wrapper.find({ ref: 'cancelButton' });
+ const findModal = () => wrapper.find({ ref: 'cancelCommentModal' });
+
+ function createComponent(props = {}, mountOptions = {}) {
+ wrapper = mount(DesignReplyForm, {
+ propsData: {
+ value: '',
+ isSaving: false,
+ ...props,
+ },
+ stubs: { GlModal },
+ ...mountOptions,
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('textarea has focus after component mount', () => {
+ // We need to attach to document, so that `document.activeElement` is properly set in jsdom
+ createComponent({}, { attachToDocument: true });
+
+ expect(findTextarea().element).toEqual(document.activeElement);
+ });
+
+ it('renders button text as "Comment" when creating a comment', () => {
+ createComponent();
+
+ expect(findSubmitButton().html()).toMatchSnapshot();
+ });
+
+ it('renders button text as "Save comment" when creating a comment', () => {
+ createComponent({ isNewComment: false });
+
+ expect(findSubmitButton().html()).toMatchSnapshot();
+ });
+
+ describe('when form has no text', () => {
+ beforeEach(() => {
+ createComponent({
+ value: '',
+ });
+ });
+
+ it('submit button is disabled', () => {
+ expect(findSubmitButton().attributes().disabled).toBeTruthy();
+ });
+
+ it('does not emit submitForm event on textarea ctrl+enter keydown', () => {
+ findTextarea().trigger('keydown.enter', {
+ ctrlKey: true,
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('submitForm')).toBeFalsy();
+ });
+ });
+
+ it('does not emit submitForm event on textarea meta+enter keydown', () => {
+ findTextarea().trigger('keydown.enter', {
+ metaKey: true,
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('submitForm')).toBeFalsy();
+ });
+ });
+
+ it('emits cancelForm event on pressing escape button on textarea', () => {
+ findTextarea().trigger('keyup.esc');
+
+ expect(wrapper.emitted('cancelForm')).toBeTruthy();
+ });
+
+ it('emits cancelForm event on clicking Cancel button', () => {
+ findCancelButton().vm.$emit('click');
+
+ expect(wrapper.emitted('cancelForm')).toHaveLength(1);
+ });
+ });
+
+ describe('when form has text', () => {
+ beforeEach(() => {
+ createComponent({
+ value: 'test',
+ });
+ });
+
+ it('submit button is enabled', () => {
+ expect(findSubmitButton().attributes().disabled).toBeFalsy();
+ });
+
+ it('emits submitForm event on Comment button click', () => {
+ findSubmitButton().vm.$emit('click');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('submitForm')).toBeTruthy();
+ });
+ });
+
+ it('emits submitForm event on textarea ctrl+enter keydown', () => {
+ findTextarea().trigger('keydown.enter', {
+ ctrlKey: true,
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('submitForm')).toBeTruthy();
+ });
+ });
+
+ it('emits submitForm event on textarea meta+enter keydown', () => {
+ findTextarea().trigger('keydown.enter', {
+ metaKey: true,
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('submitForm')).toBeTruthy();
+ });
+ });
+
+ it('emits input event on changing textarea content', () => {
+ findTextarea().setValue('test2');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('input')).toBeTruthy();
+ });
+ });
+
+ it('emits cancelForm event on Escape key if text was not changed', () => {
+ findTextarea().trigger('keyup.esc');
+
+ expect(wrapper.emitted('cancelForm')).toBeTruthy();
+ });
+
+ it('opens confirmation modal on Escape key when text has changed', () => {
+ wrapper.setProps({ value: 'test2' });
+
+ return wrapper.vm.$nextTick().then(() => {
+ findTextarea().trigger('keyup.esc');
+ expect(showModal).toHaveBeenCalled();
+ });
+ });
+
+ it('emits cancelForm event on Cancel button click if text was not changed', () => {
+ findCancelButton().trigger('click');
+
+ expect(wrapper.emitted('cancelForm')).toBeTruthy();
+ });
+
+ it('opens confirmation modal on Cancel button click when text has changed', () => {
+ wrapper.setProps({ value: 'test2' });
+
+ return wrapper.vm.$nextTick().then(() => {
+ findCancelButton().trigger('click');
+ expect(showModal).toHaveBeenCalled();
+ });
+ });
+
+ it('emits cancelForm event on modal Ok button click', () => {
+ findTextarea().trigger('keyup.esc');
+ findModal().vm.$emit('ok');
+
+ expect(wrapper.emitted('cancelForm')).toBeTruthy();
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/design_notes/toggle_replies_widget_spec.js b/spec/frontend/design_management_new/components/design_notes/toggle_replies_widget_spec.js
new file mode 100644
index 00000000000..d3c89075a24
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_notes/toggle_replies_widget_spec.js
@@ -0,0 +1,98 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon, GlButton, GlLink } from '@gitlab/ui';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import ToggleRepliesWidget from '~/design_management_new/components/design_notes/toggle_replies_widget.vue';
+import notes from '../../mock_data/notes';
+
+describe('Toggle replies widget component', () => {
+ let wrapper;
+
+ const findToggleWrapper = () => wrapper.find('[data-testid="toggle-comments-wrapper"]');
+ const findIcon = () => wrapper.find(GlIcon);
+ const findButton = () => wrapper.find(GlButton);
+ const findAuthorLink = () => wrapper.find(GlLink);
+ const findTimeAgo = () => wrapper.find(TimeAgoTooltip);
+
+ function createComponent(props = {}) {
+ wrapper = shallowMount(ToggleRepliesWidget, {
+ propsData: {
+ collapsed: true,
+ replies: notes,
+ ...props,
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when replies are collapsed', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should not have expanded class', () => {
+ expect(findToggleWrapper().classes()).not.toContain('expanded');
+ });
+
+ it('should render chevron-right icon', () => {
+ expect(findIcon().props('name')).toBe('chevron-right');
+ });
+
+ it('should have replies length on button', () => {
+ expect(findButton().text()).toBe('2 replies');
+ });
+
+ it('should render a link to the last reply author', () => {
+ expect(findAuthorLink().exists()).toBe(true);
+ expect(findAuthorLink().text()).toBe(notes[1].author.name);
+ expect(findAuthorLink().attributes('href')).toBe(notes[1].author.webUrl);
+ });
+
+ it('should render correct time ago tooltip', () => {
+ expect(findTimeAgo().exists()).toBe(true);
+ expect(findTimeAgo().props('time')).toBe(notes[1].createdAt);
+ });
+ });
+
+ describe('when replies are expanded', () => {
+ beforeEach(() => {
+ createComponent({ collapsed: false });
+ });
+
+ it('should have expanded class', () => {
+ expect(findToggleWrapper().classes()).toContain('expanded');
+ });
+
+ it('should render chevron-down icon', () => {
+ expect(findIcon().props('name')).toBe('chevron-down');
+ });
+
+ it('should have Collapse replies text on button', () => {
+ expect(findButton().text()).toBe('Collapse replies');
+ });
+
+ it('should not have a link to the last reply author', () => {
+ expect(findAuthorLink().exists()).toBe(false);
+ });
+
+ it('should not render time ago tooltip', () => {
+ expect(findTimeAgo().exists()).toBe(false);
+ });
+ });
+
+ it('should emit toggle event on icon click', () => {
+ createComponent();
+ findIcon().vm.$emit('click', new MouseEvent('click'));
+
+ expect(wrapper.emitted('toggle')).toHaveLength(1);
+ });
+
+ it('should emit toggle event on button click', () => {
+ createComponent();
+ findButton().vm.$emit('click', new MouseEvent('click'));
+
+ expect(wrapper.emitted('toggle')).toHaveLength(1);
+ });
+});
diff --git a/spec/frontend/design_management_new/components/design_overlay_spec.js b/spec/frontend/design_management_new/components/design_overlay_spec.js
new file mode 100644
index 00000000000..4ca69c143a8
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_overlay_spec.js
@@ -0,0 +1,410 @@
+import { mount } from '@vue/test-utils';
+import DesignOverlay from '~/design_management_new/components/design_overlay.vue';
+import updateActiveDiscussion from '~/design_management_new/graphql/mutations/update_active_discussion.mutation.graphql';
+import notes from '../mock_data/notes';
+import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '~/design_management_new/constants';
+
+const mutate = jest.fn(() => Promise.resolve());
+
+describe('Design overlay component', () => {
+ let wrapper;
+
+ const mockDimensions = { width: 100, height: 100 };
+
+ const findOverlay = () => wrapper.find('.image-diff-overlay');
+ const findAllNotes = () => wrapper.findAll('.js-image-badge');
+ const findCommentBadge = () => wrapper.find('.comment-indicator');
+ const findFirstBadge = () => findAllNotes().at(0);
+ const findSecondBadge = () => findAllNotes().at(1);
+
+ const clickAndDragBadge = (elem, fromPoint, toPoint) => {
+ elem.trigger('mousedown', { clientX: fromPoint.x, clientY: fromPoint.y });
+ return wrapper.vm.$nextTick().then(() => {
+ elem.trigger('mousemove', { clientX: toPoint.x, clientY: toPoint.y });
+ return wrapper.vm.$nextTick();
+ });
+ };
+
+ function createComponent(props = {}, data = {}) {
+ wrapper = mount(DesignOverlay, {
+ propsData: {
+ dimensions: mockDimensions,
+ position: {
+ top: '0',
+ left: '0',
+ },
+ resolvedDiscussionsExpanded: false,
+ ...props,
+ },
+ data() {
+ return {
+ activeDiscussion: {
+ id: null,
+ source: null,
+ },
+ ...data,
+ };
+ },
+ mocks: {
+ $apollo: {
+ mutate,
+ },
+ },
+ });
+ }
+
+ it('should have correct inline style', () => {
+ createComponent();
+
+ expect(wrapper.find('.image-diff-overlay').attributes().style).toBe(
+ 'width: 100px; height: 100px; top: 0px; left: 0px;',
+ );
+ });
+
+ it('should emit `openCommentForm` when clicking on overlay', () => {
+ createComponent();
+ const newCoordinates = {
+ x: 10,
+ y: 10,
+ };
+
+ wrapper
+ .find('.image-diff-overlay-add-comment')
+ .trigger('mouseup', { offsetX: newCoordinates.x, offsetY: newCoordinates.y });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('openCommentForm')).toEqual([
+ [{ x: newCoordinates.x, y: newCoordinates.y }],
+ ]);
+ });
+ });
+
+ describe('with notes', () => {
+ it('should render only the first note', () => {
+ createComponent({
+ notes,
+ });
+ expect(findAllNotes()).toHaveLength(1);
+ });
+
+ describe('with resolved discussions toggle expanded', () => {
+ beforeEach(() => {
+ createComponent({
+ notes,
+ resolvedDiscussionsExpanded: true,
+ });
+ });
+
+ it('should render all notes', () => {
+ expect(findAllNotes()).toHaveLength(notes.length);
+ });
+
+ it('should have set the correct position for each note badge', () => {
+ expect(findFirstBadge().attributes().style).toBe('left: 10px; top: 15px;');
+ expect(findSecondBadge().attributes().style).toBe('left: 50px; top: 50px;');
+ });
+
+ it('should apply resolved class to the resolved note pin', () => {
+ expect(findSecondBadge().classes()).toContain('resolved');
+ });
+
+ it('when there is an active discussion, should apply inactive class to all pins besides the active one', () => {
+ wrapper.setData({
+ activeDiscussion: {
+ id: notes[0].id,
+ source: 'discussion',
+ },
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findSecondBadge().classes()).toContain('inactive');
+ });
+ });
+ });
+
+ it('should recalculate badges positions on window resize', () => {
+ createComponent({
+ notes,
+ dimensions: {
+ width: 400,
+ height: 400,
+ },
+ });
+
+ expect(findFirstBadge().attributes().style).toBe('left: 40px; top: 60px;');
+
+ wrapper.setProps({
+ dimensions: {
+ width: 200,
+ height: 200,
+ },
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findFirstBadge().attributes().style).toBe('left: 20px; top: 30px;');
+ });
+ });
+
+ it('should call an update active discussion mutation when clicking a note without moving it', () => {
+ const note = notes[0];
+ const { position } = note;
+ const mutationVariables = {
+ mutation: updateActiveDiscussion,
+ variables: {
+ id: note.id,
+ source: ACTIVE_DISCUSSION_SOURCE_TYPES.pin,
+ },
+ };
+
+ findFirstBadge().trigger('mousedown', { clientX: position.x, clientY: position.y });
+
+ return wrapper.vm.$nextTick().then(() => {
+ findFirstBadge().trigger('mouseup', { clientX: position.x, clientY: position.y });
+ expect(mutate).toHaveBeenCalledWith(mutationVariables);
+ });
+ });
+ });
+
+ describe('when moving notes', () => {
+ it('should update badge style when note is being moved', () => {
+ createComponent({
+ notes,
+ });
+
+ const { position } = notes[0];
+
+ return clickAndDragBadge(
+ findFirstBadge(),
+ { x: position.x, y: position.y },
+ { x: 20, y: 20 },
+ ).then(() => {
+ expect(findFirstBadge().attributes().style).toBe('left: 20px; top: 20px; cursor: move;');
+ });
+ });
+
+ it('should emit `moveNote` event when note-moving action ends', () => {
+ createComponent({ notes });
+ const note = notes[0];
+ const { position } = note;
+ const newCoordinates = { x: 20, y: 20 };
+
+ wrapper.setData({
+ movingNoteNewPosition: {
+ ...position,
+ ...newCoordinates,
+ },
+ movingNoteStartPosition: {
+ noteId: notes[0].id,
+ discussionId: notes[0].discussion.id,
+ ...position,
+ },
+ });
+
+ const badge = findFirstBadge();
+ return clickAndDragBadge(badge, { x: position.x, y: position.y }, newCoordinates)
+ .then(() => {
+ badge.trigger('mouseup');
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ expect(wrapper.emitted('moveNote')).toEqual([
+ [
+ {
+ noteId: notes[0].id,
+ discussionId: notes[0].discussion.id,
+ coordinates: newCoordinates,
+ },
+ ],
+ ]);
+ });
+ });
+
+ describe('without [adminNote] permission', () => {
+ const mockNoteNotAuthorised = {
+ ...notes[0],
+ userPermissions: {
+ adminNote: false,
+ },
+ };
+
+ const mockNoteCoordinates = {
+ x: mockNoteNotAuthorised.position.x,
+ y: mockNoteNotAuthorised.position.y,
+ };
+
+ it('should be unable to move a note', () => {
+ createComponent({
+ dimensions: mockDimensions,
+ notes: [mockNoteNotAuthorised],
+ });
+
+ const badge = findAllNotes().at(0);
+ return clickAndDragBadge(badge, { ...mockNoteCoordinates }, { x: 20, y: 20 }).then(() => {
+ // note position should not change after a click-and-drag attempt
+ expect(findFirstBadge().attributes().style).toContain(
+ `left: ${mockNoteCoordinates.x}px; top: ${mockNoteCoordinates.y}px;`,
+ );
+ });
+ });
+ });
+ });
+
+ describe('with a new form', () => {
+ it('should render a new comment badge', () => {
+ createComponent({
+ currentCommentForm: {
+ ...notes[0].position,
+ },
+ });
+
+ expect(findCommentBadge().exists()).toBe(true);
+ expect(findCommentBadge().attributes().style).toBe('left: 10px; top: 15px;');
+ });
+
+ describe('when moving the comment badge', () => {
+ it('should update badge style to reflect new position', () => {
+ const { position } = notes[0];
+
+ createComponent({
+ currentCommentForm: {
+ ...position,
+ },
+ });
+
+ return clickAndDragBadge(
+ findCommentBadge(),
+ { x: position.x, y: position.y },
+ { x: 20, y: 20 },
+ ).then(() => {
+ expect(findCommentBadge().attributes().style).toBe(
+ 'left: 20px; top: 20px; cursor: move;',
+ );
+ });
+ });
+
+ it('should update badge style when note-moving action ends', () => {
+ const { position } = notes[0];
+ createComponent({
+ currentCommentForm: {
+ ...position,
+ },
+ });
+
+ const commentBadge = findCommentBadge();
+ const toPoint = { x: 20, y: 20 };
+
+ return clickAndDragBadge(commentBadge, { x: position.x, y: position.y }, toPoint)
+ .then(() => {
+ commentBadge.trigger('mouseup');
+ // simulates the currentCommentForm being updated in index.vue component, and
+ // propagated back down to this prop
+ wrapper.setProps({
+ currentCommentForm: { height: position.height, width: position.width, ...toPoint },
+ });
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ expect(commentBadge.attributes().style).toBe('left: 20px; top: 20px;');
+ });
+ });
+
+ it.each`
+ element | getElementFunc | event
+ ${'overlay'} | ${findOverlay} | ${'mouseleave'}
+ ${'comment badge'} | ${findCommentBadge} | ${'mouseup'}
+ `(
+ 'should emit `openCommentForm` event when $event fired on $element element',
+ ({ getElementFunc, event }) => {
+ createComponent({
+ notes,
+ currentCommentForm: {
+ ...notes[0].position,
+ },
+ });
+
+ const newCoordinates = { x: 20, y: 20 };
+ wrapper.setData({
+ movingNoteStartPosition: {
+ ...notes[0].position,
+ },
+ movingNoteNewPosition: {
+ ...notes[0].position,
+ ...newCoordinates,
+ },
+ });
+
+ getElementFunc().trigger(event);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('openCommentForm')).toEqual([[newCoordinates]]);
+ });
+ },
+ );
+ });
+ });
+
+ describe('getMovingNotePositionDelta', () => {
+ it('should calculate delta correctly from state', () => {
+ createComponent();
+
+ wrapper.setData({
+ movingNoteStartPosition: {
+ clientX: 10,
+ clientY: 20,
+ },
+ });
+
+ const mockMouseEvent = {
+ clientX: 30,
+ clientY: 10,
+ };
+
+ expect(wrapper.vm.getMovingNotePositionDelta(mockMouseEvent)).toEqual({
+ deltaX: 20,
+ deltaY: -10,
+ });
+ });
+ });
+
+ describe('isPositionInOverlay', () => {
+ createComponent({ dimensions: mockDimensions });
+
+ it.each`
+ test | coordinates | expectedResult
+ ${'within overlay bounds'} | ${{ x: 50, y: 50 }} | ${true}
+ ${'outside overlay bounds'} | ${{ x: 101, y: 101 }} | ${false}
+ `('returns [$expectedResult] when position is $test', ({ coordinates, expectedResult }) => {
+ const position = { ...mockDimensions, ...coordinates };
+
+ expect(wrapper.vm.isPositionInOverlay(position)).toBe(expectedResult);
+ });
+ });
+
+ describe('getNoteRelativePosition', () => {
+ it('calculates position correctly', () => {
+ createComponent({ dimensions: mockDimensions });
+ const position = { x: 50, y: 50, width: 200, height: 200 };
+
+ expect(wrapper.vm.getNoteRelativePosition(position)).toEqual({ left: 25, top: 25 });
+ });
+ });
+
+ describe('canMoveNote', () => {
+ it.each`
+ adminNotePermission | canMoveNoteResult
+ ${true} | ${true}
+ ${false} | ${false}
+ ${undefined} | ${false}
+ `(
+ 'returns [$canMoveNoteResult] when [adminNote permission] is [$adminNotePermission]',
+ ({ adminNotePermission, canMoveNoteResult }) => {
+ createComponent();
+
+ const note = {
+ userPermissions: {
+ adminNote: adminNotePermission,
+ },
+ };
+ expect(wrapper.vm.canMoveNote(note)).toBe(canMoveNoteResult);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/design_management_new/components/design_presentation_spec.js b/spec/frontend/design_management_new/components/design_presentation_spec.js
new file mode 100644
index 00000000000..d043a762cd2
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_presentation_spec.js
@@ -0,0 +1,553 @@
+import { shallowMount } from '@vue/test-utils';
+import DesignPresentation from '~/design_management_new/components/design_presentation.vue';
+import DesignOverlay from '~/design_management_new/components/design_overlay.vue';
+
+const mockOverlayData = {
+ overlayDimensions: {
+ width: 100,
+ height: 100,
+ },
+ overlayPosition: {
+ top: '0',
+ left: '0',
+ },
+};
+
+describe('Design management design presentation component', () => {
+ let wrapper;
+
+ function createComponent(
+ {
+ image,
+ imageName,
+ discussions = [],
+ isAnnotating = false,
+ resolvedDiscussionsExpanded = false,
+ } = {},
+ data = {},
+ stubs = {},
+ ) {
+ wrapper = shallowMount(DesignPresentation, {
+ propsData: {
+ image,
+ imageName,
+ discussions,
+ isAnnotating,
+ resolvedDiscussionsExpanded,
+ },
+ stubs,
+ });
+
+ wrapper.setData(data);
+ wrapper.element.scrollTo = jest.fn();
+ }
+
+ const findOverlayCommentButton = () => wrapper.find('.image-diff-overlay-add-comment');
+
+ /**
+ * Spy on $refs and mock given values
+ * @param {Object} viewportDimensions {width, height}
+ * @param {Object} childDimensions {width, height}
+ * @param {Float} scrollTopPerc 0 < x < 1
+ * @param {Float} scrollLeftPerc 0 < x < 1
+ */
+ function mockRefDimensions(
+ ref,
+ viewportDimensions,
+ childDimensions,
+ scrollTopPerc,
+ scrollLeftPerc,
+ ) {
+ jest.spyOn(ref, 'scrollWidth', 'get').mockReturnValue(childDimensions.width);
+ jest.spyOn(ref, 'scrollHeight', 'get').mockReturnValue(childDimensions.height);
+ jest.spyOn(ref, 'offsetWidth', 'get').mockReturnValue(viewportDimensions.width);
+ jest.spyOn(ref, 'offsetHeight', 'get').mockReturnValue(viewportDimensions.height);
+ jest
+ .spyOn(ref, 'scrollLeft', 'get')
+ .mockReturnValue((childDimensions.width - viewportDimensions.width) * scrollLeftPerc);
+ jest
+ .spyOn(ref, 'scrollTop', 'get')
+ .mockReturnValue((childDimensions.height - viewportDimensions.height) * scrollTopPerc);
+ }
+
+ function clickDragExplore(startCoords, endCoords, { useTouchEvents, mouseup } = {}) {
+ const event = useTouchEvents
+ ? {
+ mousedown: 'touchstart',
+ mousemove: 'touchmove',
+ mouseup: 'touchend',
+ }
+ : {
+ mousedown: 'mousedown',
+ mousemove: 'mousemove',
+ mouseup: 'mouseup',
+ };
+
+ const addCommentOverlay = findOverlayCommentButton();
+
+ // triggering mouse events on this element best simulates
+ // reality, as it is the lowest-level node that needs to
+ // respond to mouse events
+ addCommentOverlay.trigger(event.mousedown, {
+ clientX: startCoords.clientX,
+ clientY: startCoords.clientY,
+ });
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ addCommentOverlay.trigger(event.mousemove, {
+ clientX: endCoords.clientX,
+ clientY: endCoords.clientY,
+ });
+
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ if (mouseup) {
+ addCommentOverlay.trigger(event.mouseup);
+ return wrapper.vm.$nextTick();
+ }
+
+ return undefined;
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders image and overlay when image provided', () => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ },
+ mockOverlayData,
+ );
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('renders empty state when no image provided', () => {
+ createComponent();
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('openCommentForm event emits correct data', () => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ },
+ mockOverlayData,
+ );
+
+ wrapper.vm.openCommentForm({ x: 1, y: 1 });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('openCommentForm')).toEqual([
+ [{ ...mockOverlayData.overlayDimensions, x: 1, y: 1 }],
+ ]);
+ });
+ });
+
+ describe('currentCommentForm', () => {
+ it('is null when isAnnotating is false', () => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ },
+ mockOverlayData,
+ );
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.currentCommentForm).toBeNull();
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('is null when isAnnotating is true but annotation position is falsey', () => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ isAnnotating: true,
+ },
+ mockOverlayData,
+ );
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.currentCommentForm).toBeNull();
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('is equal to current annotation position when isAnnotating is true', () => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ isAnnotating: true,
+ },
+ {
+ ...mockOverlayData,
+ currentAnnotationPosition: {
+ x: 1,
+ y: 1,
+ width: 100,
+ height: 100,
+ },
+ },
+ );
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.currentCommentForm).toEqual({
+ x: 1,
+ y: 1,
+ width: 100,
+ height: 100,
+ });
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+ });
+
+ describe('setOverlayPosition', () => {
+ beforeEach(() => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ },
+ mockOverlayData,
+ );
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('sets overlay position correctly when overlay is smaller than viewport', () => {
+ jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetWidth', 'get').mockReturnValue(200);
+ jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetHeight', 'get').mockReturnValue(200);
+
+ wrapper.vm.setOverlayPosition();
+ expect(wrapper.vm.overlayPosition).toEqual({
+ left: `calc(50% - ${mockOverlayData.overlayDimensions.width / 2}px)`,
+ top: `calc(50% - ${mockOverlayData.overlayDimensions.height / 2}px)`,
+ });
+ });
+
+ it('sets overlay position correctly when overlay width is larger than viewports', () => {
+ jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetWidth', 'get').mockReturnValue(50);
+ jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetHeight', 'get').mockReturnValue(200);
+
+ wrapper.vm.setOverlayPosition();
+ expect(wrapper.vm.overlayPosition).toEqual({
+ left: '0',
+ top: `calc(50% - ${mockOverlayData.overlayDimensions.height / 2}px)`,
+ });
+ });
+
+ it('sets overlay position correctly when overlay height is larger than viewports', () => {
+ jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetWidth', 'get').mockReturnValue(200);
+ jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetHeight', 'get').mockReturnValue(50);
+
+ wrapper.vm.setOverlayPosition();
+ expect(wrapper.vm.overlayPosition).toEqual({
+ left: `calc(50% - ${mockOverlayData.overlayDimensions.width / 2}px)`,
+ top: '0',
+ });
+ });
+ });
+
+ describe('getViewportCenter', () => {
+ beforeEach(() => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ },
+ mockOverlayData,
+ );
+ });
+
+ it('calculate center correctly with no scroll', () => {
+ mockRefDimensions(
+ wrapper.vm.$refs.presentationViewport,
+ { width: 10, height: 10 },
+ { width: 20, height: 20 },
+ 0,
+ 0,
+ );
+
+ expect(wrapper.vm.getViewportCenter()).toEqual({
+ x: 5,
+ y: 5,
+ });
+ });
+
+ it('calculate center correctly with some scroll', () => {
+ mockRefDimensions(
+ wrapper.vm.$refs.presentationViewport,
+ { width: 10, height: 10 },
+ { width: 20, height: 20 },
+ 0.5,
+ 0.5,
+ );
+
+ expect(wrapper.vm.getViewportCenter()).toEqual({
+ x: 10,
+ y: 10,
+ });
+ });
+
+ it('Returns default case if no overflow (scrollWidth==offsetWidth, etc.)', () => {
+ mockRefDimensions(
+ wrapper.vm.$refs.presentationViewport,
+ { width: 20, height: 20 },
+ { width: 20, height: 20 },
+ 0.5,
+ 0.5,
+ );
+
+ expect(wrapper.vm.getViewportCenter()).toEqual({
+ x: 10,
+ y: 10,
+ });
+ });
+ });
+
+ describe('scaleZoomFocalPoint', () => {
+ it('scales focal point correctly when zooming in', () => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ },
+ {
+ ...mockOverlayData,
+ zoomFocalPoint: {
+ x: 5,
+ y: 5,
+ width: 50,
+ height: 50,
+ },
+ },
+ );
+
+ wrapper.vm.scaleZoomFocalPoint();
+ expect(wrapper.vm.zoomFocalPoint).toEqual({
+ x: 10,
+ y: 10,
+ width: 100,
+ height: 100,
+ });
+ });
+
+ it('scales focal point correctly when zooming out', () => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ },
+ {
+ ...mockOverlayData,
+ zoomFocalPoint: {
+ x: 10,
+ y: 10,
+ width: 200,
+ height: 200,
+ },
+ },
+ );
+
+ wrapper.vm.scaleZoomFocalPoint();
+ expect(wrapper.vm.zoomFocalPoint).toEqual({
+ x: 5,
+ y: 5,
+ width: 100,
+ height: 100,
+ });
+ });
+ });
+
+ describe('onImageResize', () => {
+ it('sets zoom focal point on initial load', () => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ },
+ mockOverlayData,
+ );
+
+ wrapper.setMethods({
+ shiftZoomFocalPoint: jest.fn(),
+ scaleZoomFocalPoint: jest.fn(),
+ scrollToFocalPoint: jest.fn(),
+ });
+
+ wrapper.vm.onImageResize({ width: 10, height: 10 });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.shiftZoomFocalPoint).toHaveBeenCalled();
+ expect(wrapper.vm.initialLoad).toBe(false);
+ });
+ });
+
+ it('calls scaleZoomFocalPoint and scrollToFocalPoint after initial load', () => {
+ wrapper.vm.onImageResize({ width: 10, height: 10 });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.scaleZoomFocalPoint).toHaveBeenCalled();
+ expect(wrapper.vm.scrollToFocalPoint).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('onPresentationMousedown', () => {
+ it.each`
+ scenario | width | height
+ ${'width overflows'} | ${101} | ${100}
+ ${'height overflows'} | ${100} | ${101}
+ ${'width and height overflows'} | ${200} | ${200}
+ `('sets lastDragPosition when design $scenario', ({ width, height }) => {
+ createComponent();
+ mockRefDimensions(
+ wrapper.vm.$refs.presentationViewport,
+ { width: 100, height: 100 },
+ { width, height },
+ );
+
+ const newLastDragPosition = { x: 2, y: 2 };
+ wrapper.vm.onPresentationMousedown({
+ clientX: newLastDragPosition.x,
+ clientY: newLastDragPosition.y,
+ });
+
+ expect(wrapper.vm.lastDragPosition).toStrictEqual(newLastDragPosition);
+ });
+
+ it('does not set lastDragPosition if design does not overflow', () => {
+ const lastDragPosition = { x: 1, y: 1 };
+
+ createComponent({}, { lastDragPosition });
+ mockRefDimensions(
+ wrapper.vm.$refs.presentationViewport,
+ { width: 100, height: 100 },
+ { width: 50, height: 50 },
+ );
+
+ wrapper.vm.onPresentationMousedown({ clientX: 2, clientY: 2 });
+
+ // check lastDragPosition is unchanged
+ expect(wrapper.vm.lastDragPosition).toStrictEqual(lastDragPosition);
+ });
+ });
+
+ describe('getAnnotationPositon', () => {
+ it.each`
+ coordinates | overlayDimensions | position
+ ${{ x: 100, y: 100 }} | ${{ width: 50, height: 50 }} | ${{ x: 100, y: 100, width: 50, height: 50 }}
+ ${{ x: 100.2, y: 100.5 }} | ${{ width: 50.6, height: 50.0 }} | ${{ x: 100, y: 101, width: 51, height: 50 }}
+ `('returns correct annotation position', ({ coordinates, overlayDimensions, position }) => {
+ createComponent(undefined, {
+ overlayDimensions: {
+ width: overlayDimensions.width,
+ height: overlayDimensions.height,
+ },
+ });
+
+ expect(wrapper.vm.getAnnotationPositon(coordinates)).toStrictEqual(position);
+ });
+ });
+
+ describe('when design is overflowing', () => {
+ beforeEach(() => {
+ createComponent(
+ {
+ image: 'test.jpg',
+ imageName: 'test',
+ },
+ mockOverlayData,
+ {
+ 'design-overlay': DesignOverlay,
+ },
+ );
+
+ // mock a design that overflows
+ mockRefDimensions(
+ wrapper.vm.$refs.presentationViewport,
+ { width: 10, height: 10 },
+ { width: 20, height: 20 },
+ 0,
+ 0,
+ );
+ });
+
+ it('opens a comment form if design was not dragged', () => {
+ const addCommentOverlay = findOverlayCommentButton();
+ const startCoords = {
+ clientX: 1,
+ clientY: 1,
+ };
+
+ addCommentOverlay.trigger('mousedown', {
+ clientX: startCoords.clientX,
+ clientY: startCoords.clientY,
+ });
+
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ addCommentOverlay.trigger('mouseup');
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ expect(wrapper.emitted('openCommentForm')).toBeDefined();
+ });
+ });
+
+ describe('when clicking and dragging', () => {
+ it.each`
+ description | useTouchEvents
+ ${'with touch events'} | ${true}
+ ${'without touch events'} | ${false}
+ `('calls scrollTo with correct arguments $description', ({ useTouchEvents }) => {
+ return clickDragExplore(
+ { clientX: 0, clientY: 0 },
+ { clientX: 10, clientY: 10 },
+ { useTouchEvents },
+ ).then(() => {
+ expect(wrapper.element.scrollTo).toHaveBeenCalledTimes(1);
+ expect(wrapper.element.scrollTo).toHaveBeenCalledWith(-10, -10);
+ });
+ });
+
+ it('does not open a comment form when drag position exceeds buffer', () => {
+ return clickDragExplore(
+ { clientX: 0, clientY: 0 },
+ { clientX: 10, clientY: 10 },
+ { mouseup: true },
+ ).then(() => {
+ expect(wrapper.emitted('openCommentForm')).toBeFalsy();
+ });
+ });
+
+ it('opens a comment form when drag position is within buffer', () => {
+ return clickDragExplore(
+ { clientX: 0, clientY: 0 },
+ { clientX: 1, clientY: 0 },
+ { mouseup: true },
+ ).then(() => {
+ expect(wrapper.emitted('openCommentForm')).toBeDefined();
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/design_scaler_spec.js b/spec/frontend/design_management_new/components/design_scaler_spec.js
new file mode 100644
index 00000000000..5ff2554cd60
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_scaler_spec.js
@@ -0,0 +1,67 @@
+import { shallowMount } from '@vue/test-utils';
+import DesignScaler from '~/design_management_new/components/design_scaler.vue';
+
+describe('Design management design scaler component', () => {
+ let wrapper;
+
+ function createComponent(propsData, data = {}) {
+ wrapper = shallowMount(DesignScaler, {
+ propsData,
+ });
+ wrapper.setData(data);
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const getButton = type => {
+ const buttonTypeOrder = ['minus', 'reset', 'plus'];
+ const buttons = wrapper.findAll('button');
+ return buttons.at(buttonTypeOrder.indexOf(type));
+ };
+
+ it('emits @scale event when "plus" button clicked', () => {
+ createComponent();
+
+ getButton('plus').trigger('click');
+ expect(wrapper.emitted('scale')).toEqual([[1.2]]);
+ });
+
+ it('emits @scale event when "reset" button clicked (scale > 1)', () => {
+ createComponent({}, { scale: 1.6 });
+ return wrapper.vm.$nextTick().then(() => {
+ getButton('reset').trigger('click');
+ expect(wrapper.emitted('scale')).toEqual([[1]]);
+ });
+ });
+
+ it('emits @scale event when "minus" button clicked (scale > 1)', () => {
+ createComponent({}, { scale: 1.6 });
+
+ return wrapper.vm.$nextTick().then(() => {
+ getButton('minus').trigger('click');
+ expect(wrapper.emitted('scale')).toEqual([[1.4]]);
+ });
+ });
+
+ it('minus and reset buttons are disabled when scale === 1', () => {
+ createComponent();
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('minus and reset buttons are enabled when scale > 1', () => {
+ createComponent({}, { scale: 1.2 });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('plus button is disabled when scale === 2', () => {
+ createComponent({}, { scale: 2 });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/design_sidebar_spec.js b/spec/frontend/design_management_new/components/design_sidebar_spec.js
new file mode 100644
index 00000000000..f1d442a7b21
--- /dev/null
+++ b/spec/frontend/design_management_new/components/design_sidebar_spec.js
@@ -0,0 +1,236 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlCollapse, GlPopover } from '@gitlab/ui';
+import Cookies from 'js-cookie';
+import DesignSidebar from '~/design_management_new/components/design_sidebar.vue';
+import Participants from '~/sidebar/components/participants/participants.vue';
+import DesignDiscussion from '~/design_management_new/components/design_notes/design_discussion.vue';
+import design from '../mock_data/design';
+import updateActiveDiscussionMutation from '~/design_management_new/graphql/mutations/update_active_discussion.mutation.graphql';
+
+const updateActiveDiscussionMutationVariables = {
+ mutation: updateActiveDiscussionMutation,
+ variables: {
+ id: design.discussions.nodes[0].notes.nodes[0].id,
+ source: 'discussion',
+ },
+};
+
+const $route = {
+ params: {
+ id: '1',
+ },
+};
+
+const cookieKey = 'hide_design_resolved_comments_popover';
+
+const mutate = jest.fn().mockResolvedValue();
+
+describe('Design management design sidebar component', () => {
+ let wrapper;
+
+ const findDiscussions = () => wrapper.findAll(DesignDiscussion);
+ const findFirstDiscussion = () => findDiscussions().at(0);
+ const findUnresolvedDiscussions = () => wrapper.findAll('[data-testid="unresolved-discussion"]');
+ const findResolvedDiscussions = () => wrapper.findAll('[data-testid="resolved-discussion"]');
+ const findParticipants = () => wrapper.find(Participants);
+ const findCollapsible = () => wrapper.find(GlCollapse);
+ const findToggleResolvedCommentsButton = () => wrapper.find('[data-testid="resolved-comments"]');
+ const findPopover = () => wrapper.find(GlPopover);
+ const findNewDiscussionDisclaimer = () =>
+ wrapper.find('[data-testid="new-discussion-disclaimer"]');
+
+ function createComponent(props = {}) {
+ wrapper = shallowMount(DesignSidebar, {
+ propsData: {
+ design,
+ resolvedDiscussionsExpanded: false,
+ markdownPreviewPath: '',
+ ...props,
+ },
+ mocks: {
+ $route,
+ $apollo: {
+ mutate,
+ },
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders participants', () => {
+ createComponent();
+
+ expect(findParticipants().exists()).toBe(true);
+ });
+
+ it('passes the correct amount of participants to the Participants component', () => {
+ createComponent();
+
+ expect(findParticipants().props('participants')).toHaveLength(1);
+ });
+
+ describe('when has no discussions', () => {
+ beforeEach(() => {
+ createComponent({
+ design: {
+ ...design,
+ discussions: {
+ nodes: [],
+ },
+ },
+ });
+ });
+
+ it('does not render discussions', () => {
+ expect(findDiscussions().exists()).toBe(false);
+ });
+
+ it('renders a message about possibility to create a new discussion', () => {
+ expect(findNewDiscussionDisclaimer().exists()).toBe(true);
+ });
+ });
+
+ describe('when has discussions', () => {
+ beforeEach(() => {
+ Cookies.set(cookieKey, true);
+ createComponent();
+ });
+
+ it('renders correct amount of unresolved discussions', () => {
+ expect(findUnresolvedDiscussions()).toHaveLength(1);
+ });
+
+ it('renders correct amount of resolved discussions', () => {
+ expect(findResolvedDiscussions()).toHaveLength(1);
+ });
+
+ it('has resolved comments collapsible collapsed', () => {
+ expect(findCollapsible().attributes('visible')).toBeUndefined();
+ });
+
+ it('emits toggleResolveComments event on resolve comments button click', () => {
+ findToggleResolvedCommentsButton().vm.$emit('click');
+ expect(wrapper.emitted('toggleResolvedComments')).toHaveLength(1);
+ });
+
+ it('opens a collapsible when resolvedDiscussionsExpanded prop changes to true', () => {
+ expect(findCollapsible().attributes('visible')).toBeUndefined();
+ wrapper.setProps({
+ resolvedDiscussionsExpanded: true,
+ });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findCollapsible().attributes('visible')).toBe('true');
+ });
+ });
+
+ it('does not popover about resolved comments', () => {
+ expect(findPopover().exists()).toBe(false);
+ });
+
+ it('sends a mutation to set an active discussion when clicking on a discussion', () => {
+ findFirstDiscussion().trigger('click');
+
+ expect(mutate).toHaveBeenCalledWith(updateActiveDiscussionMutationVariables);
+ });
+
+ it('sends a mutation to reset an active discussion when clicking outside of discussion', () => {
+ wrapper.trigger('click');
+
+ expect(mutate).toHaveBeenCalledWith({
+ ...updateActiveDiscussionMutationVariables,
+ variables: { id: undefined, source: 'discussion' },
+ });
+ });
+
+ it('emits correct event on discussion create note error', () => {
+ findFirstDiscussion().vm.$emit('createNoteError', 'payload');
+ expect(wrapper.emitted('onDesignDiscussionError')).toEqual([['payload']]);
+ });
+
+ it('emits correct event on discussion update note error', () => {
+ findFirstDiscussion().vm.$emit('updateNoteError', 'payload');
+ expect(wrapper.emitted('updateNoteError')).toEqual([['payload']]);
+ });
+
+ it('emits correct event on discussion resolve error', () => {
+ findFirstDiscussion().vm.$emit('resolveDiscussionError', 'payload');
+ expect(wrapper.emitted('resolveDiscussionError')).toEqual([['payload']]);
+ });
+
+ it('changes prop correctly on opening discussion form', () => {
+ findFirstDiscussion().vm.$emit('openForm', 'some-id');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findFirstDiscussion().props('discussionWithOpenForm')).toBe('some-id');
+ });
+ });
+ });
+
+ describe('when all discussions are resolved', () => {
+ beforeEach(() => {
+ createComponent({
+ design: {
+ ...design,
+ discussions: {
+ nodes: [
+ {
+ id: 'discussion-id',
+ replyId: 'discussion-reply-id',
+ resolved: true,
+ notes: {
+ nodes: [
+ {
+ id: 'note-id',
+ body: '123',
+ author: {
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'link-to-author',
+ avatarUrl: 'link-to-avatar',
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ });
+ });
+
+ it('renders a message about possibility to create a new discussion', () => {
+ expect(findNewDiscussionDisclaimer().exists()).toBe(true);
+ });
+
+ it('does not render unresolved discussions', () => {
+ expect(findUnresolvedDiscussions()).toHaveLength(0);
+ });
+ });
+
+ describe('when showing resolved discussions for the first time', () => {
+ beforeEach(() => {
+ Cookies.set(cookieKey, false);
+ createComponent();
+ });
+
+ it('renders a popover if we show resolved comments collapsible for the first time', () => {
+ expect(findPopover().exists()).toBe(true);
+ });
+
+ it('dismisses a popover on the outside click', () => {
+ wrapper.trigger('click');
+ return wrapper.vm.$nextTick(() => {
+ expect(findPopover().exists()).toBe(false);
+ });
+ });
+
+ it(`sets a ${cookieKey} cookie on clicking outside the popover`, () => {
+ jest.spyOn(Cookies, 'set');
+ wrapper.trigger('click');
+ expect(Cookies.set).toHaveBeenCalledWith(cookieKey, 'true', { expires: 365 * 10 });
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/image_spec.js b/spec/frontend/design_management_new/components/image_spec.js
new file mode 100644
index 00000000000..c1a8a8767df
--- /dev/null
+++ b/spec/frontend/design_management_new/components/image_spec.js
@@ -0,0 +1,133 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
+import DesignImage from '~/design_management_new/components/image.vue';
+
+describe('Design management large image component', () => {
+ let wrapper;
+
+ function createComponent(propsData, data = {}) {
+ wrapper = shallowMount(DesignImage, {
+ propsData,
+ });
+ wrapper.setData(data);
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders loading state', () => {
+ createComponent({
+ isLoading: true,
+ });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders image', () => {
+ createComponent({
+ isLoading: false,
+ image: 'test.jpg',
+ name: 'test',
+ });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('sets correct classes and styles if imageStyle is set', () => {
+ createComponent(
+ {
+ isLoading: false,
+ image: 'test.jpg',
+ name: 'test',
+ },
+ {
+ imageStyle: {
+ width: '100px',
+ height: '100px',
+ },
+ },
+ );
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('renders media broken icon on error', () => {
+ createComponent({
+ isLoading: false,
+ image: 'test.jpg',
+ name: 'test',
+ });
+
+ const image = wrapper.find('img');
+ image.trigger('error');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(image.isVisible()).toBe(false);
+ expect(wrapper.find(GlIcon).element).toMatchSnapshot();
+ });
+ });
+
+ describe('zoom', () => {
+ const baseImageWidth = 100;
+ const baseImageHeight = 100;
+
+ beforeEach(() => {
+ createComponent(
+ {
+ isLoading: false,
+ image: 'test.jpg',
+ name: 'test',
+ },
+ {
+ imageStyle: {
+ width: `${baseImageWidth}px`,
+ height: `${baseImageHeight}px`,
+ },
+ baseImageSize: {
+ width: baseImageWidth,
+ height: baseImageHeight,
+ },
+ },
+ );
+
+ jest.spyOn(wrapper.vm.$refs.contentImg, 'offsetWidth', 'get').mockReturnValue(baseImageWidth);
+ jest
+ .spyOn(wrapper.vm.$refs.contentImg, 'offsetHeight', 'get')
+ .mockReturnValue(baseImageHeight);
+ });
+
+ it('emits @resize event on zoom', () => {
+ const zoomAmount = 2;
+ wrapper.vm.zoom(zoomAmount);
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('resize')).toEqual([
+ [{ width: baseImageWidth * zoomAmount, height: baseImageHeight * zoomAmount }],
+ ]);
+ });
+ });
+
+ it('emits @resize event with base image size when scale=1', () => {
+ wrapper.vm.zoom(1);
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('resize')).toEqual([
+ [{ width: baseImageWidth, height: baseImageHeight }],
+ ]);
+ });
+ });
+
+ it('sets image style when zoomed', () => {
+ const zoomAmount = 2;
+ wrapper.vm.zoom(zoomAmount);
+ expect(wrapper.vm.imageStyle).toEqual({
+ width: `${baseImageWidth * zoomAmount}px`,
+ height: `${baseImageHeight * zoomAmount}px`,
+ });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/list/__snapshots__/item_spec.js.snap b/spec/frontend/design_management_new/components/list/__snapshots__/item_spec.js.snap
new file mode 100644
index 00000000000..9cd427f6aae
--- /dev/null
+++ b/spec/frontend/design_management_new/components/list/__snapshots__/item_spec.js.snap
@@ -0,0 +1,472 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management list item component when item appears in view after image is loaded renders media broken icon when image onerror triggered 1`] = `
+<gl-icon-stub
+ class="text-secondary"
+ name="media-broken"
+ size="32"
+/>
+`;
+
+exports[`Design management list item component with no notes renders item with correct status icon for creation event 1`] = `
+<router-link-stub
+ class="card cursor-pointer text-plain js-design-list-item design-list-item"
+ to="[object Object]"
+>
+ <div
+ class="card-body p-0 d-flex-center overflow-hidden position-relative"
+ >
+ <div
+ class="design-event position-absolute"
+ >
+ <span
+ aria-label="Added in this version"
+ title="Added in this version"
+ >
+ <icon-stub
+ class="text-success-500"
+ name="file-addition-solid"
+ size="18"
+ />
+ </span>
+ </div>
+
+ <gl-intersection-observer-stub
+ options="[object Object]"
+ >
+ <!---->
+
+ <img
+ alt="test"
+ class="block mx-auto mw-100 mh-100 design-img"
+ data-qa-selector="design_image"
+ src=""
+ />
+ </gl-intersection-observer-stub>
+ </div>
+
+ <div
+ class="card-footer d-flex w-100"
+ >
+ <div
+ class="d-flex flex-column str-truncated-100"
+ >
+ <span
+ class="bold str-truncated-100"
+ data-qa-selector="design_file_name"
+ >
+ test
+ </span>
+
+ <span
+ class="str-truncated-100"
+ >
+
+ Updated
+ <timeago-stub
+ cssclass=""
+ time="01-01-2019"
+ tooltipplacement="bottom"
+ />
+ </span>
+ </div>
+
+ <!---->
+ </div>
+</router-link-stub>
+`;
+
+exports[`Design management list item component with no notes renders item with correct status icon for deletion event 1`] = `
+<router-link-stub
+ class="card cursor-pointer text-plain js-design-list-item design-list-item"
+ to="[object Object]"
+>
+ <div
+ class="card-body p-0 d-flex-center overflow-hidden position-relative"
+ >
+ <div
+ class="design-event position-absolute"
+ >
+ <span
+ aria-label="Deleted in this version"
+ title="Deleted in this version"
+ >
+ <icon-stub
+ class="text-danger-500"
+ name="file-deletion-solid"
+ size="18"
+ />
+ </span>
+ </div>
+
+ <gl-intersection-observer-stub
+ options="[object Object]"
+ >
+ <!---->
+
+ <img
+ alt="test"
+ class="block mx-auto mw-100 mh-100 design-img"
+ data-qa-selector="design_image"
+ src=""
+ />
+ </gl-intersection-observer-stub>
+ </div>
+
+ <div
+ class="card-footer d-flex w-100"
+ >
+ <div
+ class="d-flex flex-column str-truncated-100"
+ >
+ <span
+ class="bold str-truncated-100"
+ data-qa-selector="design_file_name"
+ >
+ test
+ </span>
+
+ <span
+ class="str-truncated-100"
+ >
+
+ Updated
+ <timeago-stub
+ cssclass=""
+ time="01-01-2019"
+ tooltipplacement="bottom"
+ />
+ </span>
+ </div>
+
+ <!---->
+ </div>
+</router-link-stub>
+`;
+
+exports[`Design management list item component with no notes renders item with correct status icon for modification event 1`] = `
+<router-link-stub
+ class="card cursor-pointer text-plain js-design-list-item design-list-item"
+ to="[object Object]"
+>
+ <div
+ class="card-body p-0 d-flex-center overflow-hidden position-relative"
+ >
+ <div
+ class="design-event position-absolute"
+ >
+ <span
+ aria-label="Modified in this version"
+ title="Modified in this version"
+ >
+ <icon-stub
+ class="text-primary-500"
+ name="file-modified-solid"
+ size="18"
+ />
+ </span>
+ </div>
+
+ <gl-intersection-observer-stub
+ options="[object Object]"
+ >
+ <!---->
+
+ <img
+ alt="test"
+ class="block mx-auto mw-100 mh-100 design-img"
+ data-qa-selector="design_image"
+ src=""
+ />
+ </gl-intersection-observer-stub>
+ </div>
+
+ <div
+ class="card-footer d-flex w-100"
+ >
+ <div
+ class="d-flex flex-column str-truncated-100"
+ >
+ <span
+ class="bold str-truncated-100"
+ data-qa-selector="design_file_name"
+ >
+ test
+ </span>
+
+ <span
+ class="str-truncated-100"
+ >
+
+ Updated
+ <timeago-stub
+ cssclass=""
+ time="01-01-2019"
+ tooltipplacement="bottom"
+ />
+ </span>
+ </div>
+
+ <!---->
+ </div>
+</router-link-stub>
+`;
+
+exports[`Design management list item component with no notes renders item with no status icon for none event 1`] = `
+<router-link-stub
+ class="card cursor-pointer text-plain js-design-list-item design-list-item"
+ to="[object Object]"
+>
+ <div
+ class="card-body p-0 d-flex-center overflow-hidden position-relative"
+ >
+ <!---->
+
+ <gl-intersection-observer-stub
+ options="[object Object]"
+ >
+ <!---->
+
+ <img
+ alt="test"
+ class="block mx-auto mw-100 mh-100 design-img"
+ data-qa-selector="design_image"
+ src=""
+ />
+ </gl-intersection-observer-stub>
+ </div>
+
+ <div
+ class="card-footer d-flex w-100"
+ >
+ <div
+ class="d-flex flex-column str-truncated-100"
+ >
+ <span
+ class="bold str-truncated-100"
+ data-qa-selector="design_file_name"
+ >
+ test
+ </span>
+
+ <span
+ class="str-truncated-100"
+ >
+
+ Updated
+ <timeago-stub
+ cssclass=""
+ time="01-01-2019"
+ tooltipplacement="bottom"
+ />
+ </span>
+ </div>
+
+ <!---->
+ </div>
+</router-link-stub>
+`;
+
+exports[`Design management list item component with no notes renders loading spinner when isUploading is true 1`] = `
+<router-link-stub
+ class="card cursor-pointer text-plain js-design-list-item design-list-item"
+ to="[object Object]"
+>
+ <div
+ class="card-body p-0 d-flex-center overflow-hidden position-relative"
+ >
+ <!---->
+
+ <gl-intersection-observer-stub
+ options="[object Object]"
+ >
+ <gl-loading-icon-stub
+ color="orange"
+ label="Loading"
+ size="md"
+ />
+
+ <img
+ alt="test"
+ class="block mx-auto mw-100 mh-100 design-img"
+ data-qa-selector="design_image"
+ src=""
+ style="display: none;"
+ />
+ </gl-intersection-observer-stub>
+ </div>
+
+ <div
+ class="card-footer d-flex w-100"
+ >
+ <div
+ class="d-flex flex-column str-truncated-100"
+ >
+ <span
+ class="bold str-truncated-100"
+ data-qa-selector="design_file_name"
+ >
+ test
+ </span>
+
+ <span
+ class="str-truncated-100"
+ >
+
+ Updated
+ <timeago-stub
+ cssclass=""
+ time="01-01-2019"
+ tooltipplacement="bottom"
+ />
+ </span>
+ </div>
+
+ <!---->
+ </div>
+</router-link-stub>
+`;
+
+exports[`Design management list item component with notes renders item with multiple comments 1`] = `
+<router-link-stub
+ class="card cursor-pointer text-plain js-design-list-item design-list-item"
+ to="[object Object]"
+>
+ <div
+ class="card-body p-0 d-flex-center overflow-hidden position-relative"
+ >
+ <!---->
+
+ <gl-intersection-observer-stub
+ options="[object Object]"
+ >
+ <!---->
+
+ <img
+ alt="test"
+ class="block mx-auto mw-100 mh-100 design-img"
+ data-qa-selector="design_image"
+ src=""
+ />
+ </gl-intersection-observer-stub>
+ </div>
+
+ <div
+ class="card-footer d-flex w-100"
+ >
+ <div
+ class="d-flex flex-column str-truncated-100"
+ >
+ <span
+ class="bold str-truncated-100"
+ data-qa-selector="design_file_name"
+ >
+ test
+ </span>
+
+ <span
+ class="str-truncated-100"
+ >
+
+ Updated
+ <timeago-stub
+ cssclass=""
+ time="01-01-2019"
+ tooltipplacement="bottom"
+ />
+ </span>
+ </div>
+
+ <div
+ class="ml-auto d-flex align-items-center text-secondary"
+ >
+ <icon-stub
+ class="ml-1"
+ name="comments"
+ size="16"
+ />
+
+ <span
+ aria-label="2 comments"
+ class="ml-1"
+ >
+
+ 2
+
+ </span>
+ </div>
+ </div>
+</router-link-stub>
+`;
+
+exports[`Design management list item component with notes renders item with single comment 1`] = `
+<router-link-stub
+ class="card cursor-pointer text-plain js-design-list-item design-list-item"
+ to="[object Object]"
+>
+ <div
+ class="card-body p-0 d-flex-center overflow-hidden position-relative"
+ >
+ <!---->
+
+ <gl-intersection-observer-stub
+ options="[object Object]"
+ >
+ <!---->
+
+ <img
+ alt="test"
+ class="block mx-auto mw-100 mh-100 design-img"
+ data-qa-selector="design_image"
+ src=""
+ />
+ </gl-intersection-observer-stub>
+ </div>
+
+ <div
+ class="card-footer d-flex w-100"
+ >
+ <div
+ class="d-flex flex-column str-truncated-100"
+ >
+ <span
+ class="bold str-truncated-100"
+ data-qa-selector="design_file_name"
+ >
+ test
+ </span>
+
+ <span
+ class="str-truncated-100"
+ >
+
+ Updated
+ <timeago-stub
+ cssclass=""
+ time="01-01-2019"
+ tooltipplacement="bottom"
+ />
+ </span>
+ </div>
+
+ <div
+ class="ml-auto d-flex align-items-center text-secondary"
+ >
+ <icon-stub
+ class="ml-1"
+ name="comments"
+ size="16"
+ />
+
+ <span
+ aria-label="1 comment"
+ class="ml-1"
+ >
+
+ 1
+
+ </span>
+ </div>
+ </div>
+</router-link-stub>
+`;
diff --git a/spec/frontend/design_management_new/components/list/item_spec.js b/spec/frontend/design_management_new/components/list/item_spec.js
new file mode 100644
index 00000000000..5e3e6832acb
--- /dev/null
+++ b/spec/frontend/design_management_new/components/list/item_spec.js
@@ -0,0 +1,168 @@
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlIcon, GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui';
+import VueRouter from 'vue-router';
+import Item from '~/design_management_new/components/list/item.vue';
+
+const localVue = createLocalVue();
+localVue.use(VueRouter);
+const router = new VueRouter();
+
+// Referenced from: doc/api/graphql/reference/gitlab_schema.graphql:DesignVersionEvent
+const DESIGN_VERSION_EVENT = {
+ CREATION: 'CREATION',
+ DELETION: 'DELETION',
+ MODIFICATION: 'MODIFICATION',
+ NO_CHANGE: 'NONE',
+};
+
+describe('Design management list item component', () => {
+ let wrapper;
+
+ function createComponent({
+ notesCount = 0,
+ event = DESIGN_VERSION_EVENT.NO_CHANGE,
+ isUploading = false,
+ imageLoading = false,
+ } = {}) {
+ wrapper = shallowMount(Item, {
+ localVue,
+ router,
+ propsData: {
+ id: 1,
+ filename: 'test',
+ image: 'http://via.placeholder.com/300',
+ isUploading,
+ event,
+ notesCount,
+ updatedAt: '01-01-2019',
+ },
+ data() {
+ return {
+ imageLoading,
+ };
+ },
+ stubs: ['router-link'],
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when item is not in view', () => {
+ it('image is not rendered', () => {
+ createComponent();
+
+ const image = wrapper.find('img');
+ expect(image.attributes('src')).toBe('');
+ });
+ });
+
+ describe('when item appears in view', () => {
+ let image;
+ let glIntersectionObserver;
+
+ beforeEach(() => {
+ createComponent();
+ image = wrapper.find('img');
+ glIntersectionObserver = wrapper.find(GlIntersectionObserver);
+
+ glIntersectionObserver.vm.$emit('appear');
+ return wrapper.vm.$nextTick();
+ });
+
+ describe('before image is loaded', () => {
+ it('renders loading spinner', () => {
+ expect(wrapper.find(GlLoadingIcon)).toExist();
+ });
+ });
+
+ describe('after image is loaded', () => {
+ beforeEach(() => {
+ image.trigger('load');
+ return wrapper.vm.$nextTick();
+ });
+
+ it('renders an image', () => {
+ expect(image.attributes('src')).toBe('http://via.placeholder.com/300');
+ expect(image.isVisible()).toBe(true);
+ });
+
+ it('renders media broken icon when image onerror triggered', () => {
+ image.trigger('error');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(image.isVisible()).toBe(false);
+ expect(wrapper.find(GlIcon).element).toMatchSnapshot();
+ });
+ });
+
+ describe('when imageV432x230 and image provided', () => {
+ it('renders imageV432x230 image', () => {
+ const mockSrc = 'mock-imageV432x230-url';
+ wrapper.setProps({ imageV432x230: mockSrc });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(image.attributes('src')).toBe(mockSrc);
+ });
+ });
+ });
+
+ describe('when image disappears from view and then reappears', () => {
+ beforeEach(() => {
+ glIntersectionObserver.vm.$emit('appear');
+ return wrapper.vm.$nextTick();
+ });
+
+ it('renders an image', () => {
+ expect(image.isVisible()).toBe(true);
+ });
+ });
+ });
+ });
+
+ describe('with notes', () => {
+ it('renders item with single comment', () => {
+ createComponent({ notesCount: 1 });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders item with multiple comments', () => {
+ createComponent({ notesCount: 2 });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ describe('with no notes', () => {
+ it('renders item with no status icon for none event', () => {
+ createComponent();
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders item with correct status icon for modification event', () => {
+ createComponent({ event: DESIGN_VERSION_EVENT.MODIFICATION });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders item with correct status icon for deletion event', () => {
+ createComponent({ event: DESIGN_VERSION_EVENT.DELETION });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders item with correct status icon for creation event', () => {
+ createComponent({ event: DESIGN_VERSION_EVENT.CREATION });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders loading spinner when isUploading is true', () => {
+ createComponent({ isUploading: true });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/toolbar/__snapshots__/index_spec.js.snap b/spec/frontend/design_management_new/components/toolbar/__snapshots__/index_spec.js.snap
new file mode 100644
index 00000000000..e55cff8de3d
--- /dev/null
+++ b/spec/frontend/design_management_new/components/toolbar/__snapshots__/index_spec.js.snap
@@ -0,0 +1,61 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management toolbar component renders design and updated data 1`] = `
+<header
+ class="d-flex p-2 bg-white align-items-center js-design-header"
+>
+ <a
+ aria-label="Go back to designs"
+ class="mr-3 text-plain d-flex justify-content-center align-items-center"
+ >
+ <icon-stub
+ name="close"
+ size="18"
+ />
+ </a>
+
+ <div
+ class="overflow-hidden d-flex align-items-center"
+ >
+ <h2
+ class="m-0 str-truncated-100 gl-font-base"
+ >
+ test.jpg
+ </h2>
+
+ <small
+ class="text-secondary"
+ >
+ Updated 1 hour ago by Test Name
+ </small>
+ </div>
+
+ <pagination-stub
+ class="ml-auto flex-shrink-0"
+ id="1"
+ />
+
+ <gl-deprecated-button-stub
+ class="mr-2"
+ href="/-/designs/306/7f747adcd4693afadbe968d7ba7d983349b9012d"
+ size="md"
+ variant="secondary"
+ >
+ <icon-stub
+ name="download"
+ size="18"
+ />
+ </gl-deprecated-button-stub>
+
+ <delete-button-stub
+ buttonclass=""
+ buttonvariant="danger"
+ hasselecteddesigns="true"
+ >
+ <icon-stub
+ name="remove"
+ size="18"
+ />
+ </delete-button-stub>
+</header>
+`;
diff --git a/spec/frontend/design_management_new/components/toolbar/__snapshots__/pagination_button_spec.js.snap b/spec/frontend/design_management_new/components/toolbar/__snapshots__/pagination_button_spec.js.snap
new file mode 100644
index 00000000000..08662a04f15
--- /dev/null
+++ b/spec/frontend/design_management_new/components/toolbar/__snapshots__/pagination_button_spec.js.snap
@@ -0,0 +1,28 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management pagination button component disables button when no design is passed 1`] = `
+<router-link-stub
+ aria-label="Test title"
+ class="btn btn-default disabled"
+ disabled="true"
+ to="[object Object]"
+>
+ <icon-stub
+ name="angle-right"
+ size="16"
+ />
+</router-link-stub>
+`;
+
+exports[`Design management pagination button component renders router-link 1`] = `
+<router-link-stub
+ aria-label="Test title"
+ class="btn btn-default"
+ to="[object Object]"
+>
+ <icon-stub
+ name="angle-right"
+ size="16"
+ />
+</router-link-stub>
+`;
diff --git a/spec/frontend/design_management_new/components/toolbar/__snapshots__/pagination_spec.js.snap b/spec/frontend/design_management_new/components/toolbar/__snapshots__/pagination_spec.js.snap
new file mode 100644
index 00000000000..0197b4bff79
--- /dev/null
+++ b/spec/frontend/design_management_new/components/toolbar/__snapshots__/pagination_spec.js.snap
@@ -0,0 +1,29 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management pagination component hides components when designs are empty 1`] = `<!---->`;
+
+exports[`Design management pagination component renders pagination buttons 1`] = `
+<div
+ class="d-flex align-items-center"
+>
+
+ 0 of 2
+
+ <div
+ class="btn-group ml-3 mr-3"
+ >
+ <pagination-button-stub
+ class="js-previous-design"
+ iconname="angle-left"
+ title="Go to previous design"
+ />
+
+ <pagination-button-stub
+ class="js-next-design"
+ design="[object Object]"
+ iconname="angle-right"
+ title="Go to next design"
+ />
+ </div>
+</div>
+`;
diff --git a/spec/frontend/design_management_new/components/toolbar/index_spec.js b/spec/frontend/design_management_new/components/toolbar/index_spec.js
new file mode 100644
index 00000000000..eb5ae15ed58
--- /dev/null
+++ b/spec/frontend/design_management_new/components/toolbar/index_spec.js
@@ -0,0 +1,123 @@
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import VueRouter from 'vue-router';
+import Toolbar from '~/design_management_new/components/toolbar/index.vue';
+import DeleteButton from '~/design_management_new/components/delete_button.vue';
+import { DESIGNS_ROUTE_NAME } from '~/design_management_new/router/constants';
+import { GlDeprecatedButton } from '@gitlab/ui';
+
+const localVue = createLocalVue();
+localVue.use(VueRouter);
+const router = new VueRouter();
+
+const RouterLinkStub = {
+ props: {
+ to: {
+ type: Object,
+ },
+ },
+ render(createElement) {
+ return createElement('a', {}, this.$slots.default);
+ },
+};
+
+describe('Design management toolbar component', () => {
+ let wrapper;
+
+ function createComponent(isLoading = false, createDesign = true, props) {
+ const updatedAt = new Date();
+ updatedAt.setHours(updatedAt.getHours() - 1);
+
+ wrapper = shallowMount(Toolbar, {
+ localVue,
+ router,
+ propsData: {
+ id: '1',
+ isLatestVersion: true,
+ isLoading,
+ isDeleting: false,
+ filename: 'test.jpg',
+ updatedAt: updatedAt.toString(),
+ updatedBy: {
+ name: 'Test Name',
+ },
+ image: '/-/designs/306/7f747adcd4693afadbe968d7ba7d983349b9012d',
+ ...props,
+ },
+ stubs: {
+ 'router-link': RouterLinkStub,
+ },
+ });
+
+ wrapper.setData({
+ permissions: {
+ createDesign,
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders design and updated data', () => {
+ createComponent();
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('links back to designs list', () => {
+ createComponent();
+
+ return wrapper.vm.$nextTick().then(() => {
+ const link = wrapper.find('a');
+
+ expect(link.props('to')).toEqual({
+ name: DESIGNS_ROUTE_NAME,
+ query: {
+ version: undefined,
+ },
+ });
+ });
+ });
+
+ it('renders delete button on latest designs version with logged in user', () => {
+ createComponent();
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.find(DeleteButton).exists()).toBe(true);
+ });
+ });
+
+ it('does not render delete button on non-latest version', () => {
+ createComponent(false, true, { isLatestVersion: false });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.find(DeleteButton).exists()).toBe(false);
+ });
+ });
+
+ it('does not render delete button when user is not logged in', () => {
+ createComponent(false, false);
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.find(DeleteButton).exists()).toBe(false);
+ });
+ });
+
+ it('emits `delete` event on deleteButton `deleteSelectedDesigns` event', () => {
+ createComponent();
+
+ return wrapper.vm.$nextTick().then(() => {
+ wrapper.find(DeleteButton).vm.$emit('deleteSelectedDesigns');
+ expect(wrapper.emitted().delete).toBeTruthy();
+ });
+ });
+
+ it('renders download button with correct link', () => {
+ expect(wrapper.find(GlDeprecatedButton).attributes('href')).toBe(
+ '/-/designs/306/7f747adcd4693afadbe968d7ba7d983349b9012d',
+ );
+ });
+});
diff --git a/spec/frontend/design_management_new/components/toolbar/pagination_button_spec.js b/spec/frontend/design_management_new/components/toolbar/pagination_button_spec.js
new file mode 100644
index 00000000000..5f33d65fc1f
--- /dev/null
+++ b/spec/frontend/design_management_new/components/toolbar/pagination_button_spec.js
@@ -0,0 +1,61 @@
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import VueRouter from 'vue-router';
+import PaginationButton from '~/design_management_new/components/toolbar/pagination_button.vue';
+import { DESIGN_ROUTE_NAME } from '~/design_management_new/router/constants';
+
+const localVue = createLocalVue();
+localVue.use(VueRouter);
+const router = new VueRouter();
+
+describe('Design management pagination button component', () => {
+ let wrapper;
+
+ function createComponent(design = null) {
+ wrapper = shallowMount(PaginationButton, {
+ localVue,
+ router,
+ propsData: {
+ design,
+ title: 'Test title',
+ iconName: 'angle-right',
+ },
+ stubs: ['router-link'],
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('disables button when no design is passed', () => {
+ createComponent();
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders router-link', () => {
+ createComponent({ id: '2' });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ describe('designLink', () => {
+ it('returns empty link when design is null', () => {
+ createComponent();
+
+ expect(wrapper.vm.designLink).toEqual({});
+ });
+
+ it('returns design link', () => {
+ createComponent({ id: '2', filename: 'test' });
+
+ wrapper.vm.$router.replace('/root/test-project/issues/1/designs/test?version=1');
+
+ expect(wrapper.vm.designLink).toEqual({
+ name: DESIGN_ROUTE_NAME,
+ params: { id: 'test' },
+ query: { version: '1' },
+ });
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/toolbar/pagination_spec.js b/spec/frontend/design_management_new/components/toolbar/pagination_spec.js
new file mode 100644
index 00000000000..45dce15e292
--- /dev/null
+++ b/spec/frontend/design_management_new/components/toolbar/pagination_spec.js
@@ -0,0 +1,79 @@
+/* global Mousetrap */
+import 'mousetrap';
+import { shallowMount } from '@vue/test-utils';
+import Pagination from '~/design_management_new/components/toolbar/pagination.vue';
+import { DESIGN_ROUTE_NAME } from '~/design_management_new/router/constants';
+
+const push = jest.fn();
+const $router = {
+ push,
+};
+
+const $route = {
+ path: '/designs/design-2',
+ query: {},
+};
+
+describe('Design management pagination component', () => {
+ let wrapper;
+
+ function createComponent() {
+ wrapper = shallowMount(Pagination, {
+ propsData: {
+ id: '2',
+ },
+ mocks: {
+ $router,
+ $route,
+ },
+ });
+ }
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('hides components when designs are empty', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders pagination buttons', () => {
+ wrapper.setData({
+ designs: [{ id: '1' }, { id: '2' }],
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ describe('keyboard buttons navigation', () => {
+ beforeEach(() => {
+ wrapper.setData({
+ designs: [{ filename: '1' }, { filename: '2' }, { filename: '3' }],
+ });
+ });
+
+ it('routes to previous design on Left button', () => {
+ Mousetrap.trigger('left');
+ expect(push).toHaveBeenCalledWith({
+ name: DESIGN_ROUTE_NAME,
+ params: { id: '1' },
+ query: {},
+ });
+ });
+
+ it('routes to next design on Right button', () => {
+ Mousetrap.trigger('right');
+ expect(push).toHaveBeenCalledWith({
+ name: DESIGN_ROUTE_NAME,
+ params: { id: '3' },
+ query: {},
+ });
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/upload/__snapshots__/button_spec.js.snap b/spec/frontend/design_management_new/components/upload/__snapshots__/button_spec.js.snap
new file mode 100644
index 00000000000..27c0ba589e6
--- /dev/null
+++ b/spec/frontend/design_management_new/components/upload/__snapshots__/button_spec.js.snap
@@ -0,0 +1,79 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management upload button component renders inverted upload design button 1`] = `
+<div
+ isinverted="true"
+>
+ <gl-deprecated-button-stub
+ size="md"
+ title="Adding a design with the same filename replaces the file in a new version."
+ variant="success"
+ >
+
+ Upload designs
+
+ <!---->
+ </gl-deprecated-button-stub>
+
+ <input
+ accept="image/*"
+ class="hide"
+ multiple="multiple"
+ name="design_file"
+ type="file"
+ />
+</div>
+`;
+
+exports[`Design management upload button component renders loading icon 1`] = `
+<div>
+ <gl-deprecated-button-stub
+ disabled="true"
+ size="md"
+ title="Adding a design with the same filename replaces the file in a new version."
+ variant="success"
+ >
+
+ Upload designs
+
+ <gl-loading-icon-stub
+ class="ml-1"
+ color="orange"
+ inline="true"
+ label="Loading"
+ size="sm"
+ />
+ </gl-deprecated-button-stub>
+
+ <input
+ accept="image/*"
+ class="hide"
+ multiple="multiple"
+ name="design_file"
+ type="file"
+ />
+</div>
+`;
+
+exports[`Design management upload button component renders upload design button 1`] = `
+<div>
+ <gl-deprecated-button-stub
+ size="md"
+ title="Adding a design with the same filename replaces the file in a new version."
+ variant="success"
+ >
+
+ Upload designs
+
+ <!---->
+ </gl-deprecated-button-stub>
+
+ <input
+ accept="image/*"
+ class="hide"
+ multiple="multiple"
+ name="design_file"
+ type="file"
+ />
+</div>
+`;
diff --git a/spec/frontend/design_management_new/components/upload/__snapshots__/design_dropzone_spec.js.snap b/spec/frontend/design_management_new/components/upload/__snapshots__/design_dropzone_spec.js.snap
new file mode 100644
index 00000000000..0737b9729a2
--- /dev/null
+++ b/spec/frontend/design_management_new/components/upload/__snapshots__/design_dropzone_spec.js.snap
@@ -0,0 +1,455 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management dropzone component when dragging renders correct template when drag event contains files 1`] = `
+<div
+ class="w-100 position-relative"
+>
+ <button
+ class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
+ >
+ <div
+ class="d-flex-center flex-column text-center"
+ >
+ <gl-icon-stub
+ class="mb-4"
+ name="doc-new"
+ size="48"
+ />
+
+ <p>
+ <gl-sprintf-stub
+ message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
+ />
+ </p>
+ </div>
+ </button>
+
+ <input
+ accept="image/*"
+ class="hide"
+ multiple="multiple"
+ name="design_file"
+ type="file"
+ />
+
+ <transition-stub
+ name="design-dropzone-fade"
+ >
+ <div
+ class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ style=""
+ >
+ <div
+ class="mw-50 text-center"
+ style="display: none;"
+ >
+ <h3>
+ Oh no!
+ </h3>
+
+ <span>
+ You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
+ </span>
+ </div>
+
+ <div
+ class="mw-50 text-center"
+ style=""
+ >
+ <h3>
+ Incoming!
+ </h3>
+
+ <span>
+ Drop your designs to start your upload.
+ </span>
+ </div>
+ </div>
+ </transition-stub>
+</div>
+`;
+
+exports[`Design management dropzone component when dragging renders correct template when drag event contains files and text 1`] = `
+<div
+ class="w-100 position-relative"
+>
+ <button
+ class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
+ >
+ <div
+ class="d-flex-center flex-column text-center"
+ >
+ <gl-icon-stub
+ class="mb-4"
+ name="doc-new"
+ size="48"
+ />
+
+ <p>
+ <gl-sprintf-stub
+ message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
+ />
+ </p>
+ </div>
+ </button>
+
+ <input
+ accept="image/*"
+ class="hide"
+ multiple="multiple"
+ name="design_file"
+ type="file"
+ />
+
+ <transition-stub
+ name="design-dropzone-fade"
+ >
+ <div
+ class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ style=""
+ >
+ <div
+ class="mw-50 text-center"
+ style="display: none;"
+ >
+ <h3>
+ Oh no!
+ </h3>
+
+ <span>
+ You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
+ </span>
+ </div>
+
+ <div
+ class="mw-50 text-center"
+ style=""
+ >
+ <h3>
+ Incoming!
+ </h3>
+
+ <span>
+ Drop your designs to start your upload.
+ </span>
+ </div>
+ </div>
+ </transition-stub>
+</div>
+`;
+
+exports[`Design management dropzone component when dragging renders correct template when drag event contains text 1`] = `
+<div
+ class="w-100 position-relative"
+>
+ <button
+ class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
+ >
+ <div
+ class="d-flex-center flex-column text-center"
+ >
+ <gl-icon-stub
+ class="mb-4"
+ name="doc-new"
+ size="48"
+ />
+
+ <p>
+ <gl-sprintf-stub
+ message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
+ />
+ </p>
+ </div>
+ </button>
+
+ <input
+ accept="image/*"
+ class="hide"
+ multiple="multiple"
+ name="design_file"
+ type="file"
+ />
+
+ <transition-stub
+ name="design-dropzone-fade"
+ >
+ <div
+ class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ style=""
+ >
+ <div
+ class="mw-50 text-center"
+ >
+ <h3>
+ Oh no!
+ </h3>
+
+ <span>
+ You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
+ </span>
+ </div>
+
+ <div
+ class="mw-50 text-center"
+ style="display: none;"
+ >
+ <h3>
+ Incoming!
+ </h3>
+
+ <span>
+ Drop your designs to start your upload.
+ </span>
+ </div>
+ </div>
+ </transition-stub>
+</div>
+`;
+
+exports[`Design management dropzone component when dragging renders correct template when drag event is empty 1`] = `
+<div
+ class="w-100 position-relative"
+>
+ <button
+ class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
+ >
+ <div
+ class="d-flex-center flex-column text-center"
+ >
+ <gl-icon-stub
+ class="mb-4"
+ name="doc-new"
+ size="48"
+ />
+
+ <p>
+ <gl-sprintf-stub
+ message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
+ />
+ </p>
+ </div>
+ </button>
+
+ <input
+ accept="image/*"
+ class="hide"
+ multiple="multiple"
+ name="design_file"
+ type="file"
+ />
+
+ <transition-stub
+ name="design-dropzone-fade"
+ >
+ <div
+ class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ style=""
+ >
+ <div
+ class="mw-50 text-center"
+ >
+ <h3>
+ Oh no!
+ </h3>
+
+ <span>
+ You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
+ </span>
+ </div>
+
+ <div
+ class="mw-50 text-center"
+ style="display: none;"
+ >
+ <h3>
+ Incoming!
+ </h3>
+
+ <span>
+ Drop your designs to start your upload.
+ </span>
+ </div>
+ </div>
+ </transition-stub>
+</div>
+`;
+
+exports[`Design management dropzone component when dragging renders correct template when dragging stops 1`] = `
+<div
+ class="w-100 position-relative"
+>
+ <button
+ class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
+ >
+ <div
+ class="d-flex-center flex-column text-center"
+ >
+ <gl-icon-stub
+ class="mb-4"
+ name="doc-new"
+ size="48"
+ />
+
+ <p>
+ <gl-sprintf-stub
+ message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
+ />
+ </p>
+ </div>
+ </button>
+
+ <input
+ accept="image/*"
+ class="hide"
+ multiple="multiple"
+ name="design_file"
+ type="file"
+ />
+
+ <transition-stub
+ name="design-dropzone-fade"
+ >
+ <div
+ class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ style="display: none;"
+ >
+ <div
+ class="mw-50 text-center"
+ >
+ <h3>
+ Oh no!
+ </h3>
+
+ <span>
+ You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
+ </span>
+ </div>
+
+ <div
+ class="mw-50 text-center"
+ style="display: none;"
+ >
+ <h3>
+ Incoming!
+ </h3>
+
+ <span>
+ Drop your designs to start your upload.
+ </span>
+ </div>
+ </div>
+ </transition-stub>
+</div>
+`;
+
+exports[`Design management dropzone component when no slot provided renders default dropzone card 1`] = `
+<div
+ class="w-100 position-relative"
+>
+ <button
+ class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
+ >
+ <div
+ class="d-flex-center flex-column text-center"
+ >
+ <gl-icon-stub
+ class="mb-4"
+ name="doc-new"
+ size="48"
+ />
+
+ <p>
+ <gl-sprintf-stub
+ message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
+ />
+ </p>
+ </div>
+ </button>
+
+ <input
+ accept="image/*"
+ class="hide"
+ multiple="multiple"
+ name="design_file"
+ type="file"
+ />
+
+ <transition-stub
+ name="design-dropzone-fade"
+ >
+ <div
+ class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ style="display: none;"
+ >
+ <div
+ class="mw-50 text-center"
+ >
+ <h3>
+ Oh no!
+ </h3>
+
+ <span>
+ You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
+ </span>
+ </div>
+
+ <div
+ class="mw-50 text-center"
+ style="display: none;"
+ >
+ <h3>
+ Incoming!
+ </h3>
+
+ <span>
+ Drop your designs to start your upload.
+ </span>
+ </div>
+ </div>
+ </transition-stub>
+</div>
+`;
+
+exports[`Design management dropzone component when slot provided renders dropzone with slot content 1`] = `
+<div
+ class="w-100 position-relative"
+>
+ <div>
+ dropzone slot
+ </div>
+
+ <transition-stub
+ name="design-dropzone-fade"
+ >
+ <div
+ class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ style="display: none;"
+ >
+ <div
+ class="mw-50 text-center"
+ >
+ <h3>
+ Oh no!
+ </h3>
+
+ <span>
+ You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
+ </span>
+ </div>
+
+ <div
+ class="mw-50 text-center"
+ style="display: none;"
+ >
+ <h3>
+ Incoming!
+ </h3>
+
+ <span>
+ Drop your designs to start your upload.
+ </span>
+ </div>
+ </div>
+ </transition-stub>
+</div>
+`;
diff --git a/spec/frontend/design_management_new/components/upload/__snapshots__/design_version_dropdown_spec.js.snap b/spec/frontend/design_management_new/components/upload/__snapshots__/design_version_dropdown_spec.js.snap
new file mode 100644
index 00000000000..00f1a40dfb2
--- /dev/null
+++ b/spec/frontend/design_management_new/components/upload/__snapshots__/design_version_dropdown_spec.js.snap
@@ -0,0 +1,111 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management design version dropdown component renders design version dropdown button 1`] = `
+<gl-dropdown-stub
+ class="design-version-dropdown"
+ issueiid=""
+ projectpath=""
+ text="Showing Latest Version"
+ variant="link"
+>
+ <gl-dropdown-item-stub>
+ <router-link-stub
+ class="d-flex js-version-link"
+ to="[object Object]"
+ >
+ <div
+ class="flex-grow-1 ml-2"
+ >
+ <div>
+ <strong>
+ Version 2
+
+ <span>
+ (latest)
+ </span>
+ </strong>
+ </div>
+ </div>
+
+ <i
+ class="fa fa-check pull-right"
+ />
+ </router-link-stub>
+ </gl-dropdown-item-stub>
+ <gl-dropdown-item-stub>
+ <router-link-stub
+ class="d-flex js-version-link"
+ to="[object Object]"
+ >
+ <div
+ class="flex-grow-1 ml-2"
+ >
+ <div>
+ <strong>
+ Version 1
+
+ <!---->
+ </strong>
+ </div>
+ </div>
+
+ <!---->
+ </router-link-stub>
+ </gl-dropdown-item-stub>
+</gl-dropdown-stub>
+`;
+
+exports[`Design management design version dropdown component renders design version list 1`] = `
+<gl-dropdown-stub
+ class="design-version-dropdown"
+ issueiid=""
+ projectpath=""
+ text="Showing Latest Version"
+ variant="link"
+>
+ <gl-dropdown-item-stub>
+ <router-link-stub
+ class="d-flex js-version-link"
+ to="[object Object]"
+ >
+ <div
+ class="flex-grow-1 ml-2"
+ >
+ <div>
+ <strong>
+ Version 2
+
+ <span>
+ (latest)
+ </span>
+ </strong>
+ </div>
+ </div>
+
+ <i
+ class="fa fa-check pull-right"
+ />
+ </router-link-stub>
+ </gl-dropdown-item-stub>
+ <gl-dropdown-item-stub>
+ <router-link-stub
+ class="d-flex js-version-link"
+ to="[object Object]"
+ >
+ <div
+ class="flex-grow-1 ml-2"
+ >
+ <div>
+ <strong>
+ Version 1
+
+ <!---->
+ </strong>
+ </div>
+ </div>
+
+ <!---->
+ </router-link-stub>
+ </gl-dropdown-item-stub>
+</gl-dropdown-stub>
+`;
diff --git a/spec/frontend/design_management_new/components/upload/button_spec.js b/spec/frontend/design_management_new/components/upload/button_spec.js
new file mode 100644
index 00000000000..7f751982491
--- /dev/null
+++ b/spec/frontend/design_management_new/components/upload/button_spec.js
@@ -0,0 +1,59 @@
+import { shallowMount } from '@vue/test-utils';
+import UploadButton from '~/design_management_new/components/upload/button.vue';
+
+describe('Design management upload button component', () => {
+ let wrapper;
+
+ function createComponent(isSaving = false, isInverted = false) {
+ wrapper = shallowMount(UploadButton, {
+ propsData: {
+ isSaving,
+ isInverted,
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders upload design button', () => {
+ createComponent();
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders inverted upload design button', () => {
+ createComponent(false, true);
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders loading icon', () => {
+ createComponent(true);
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ describe('onFileUploadChange', () => {
+ it('emits upload event', () => {
+ createComponent();
+
+ wrapper.vm.onFileUploadChange({ target: { files: 'test' } });
+
+ expect(wrapper.emitted().upload[0]).toEqual(['test']);
+ });
+ });
+
+ describe('openFileUpload', () => {
+ it('triggers click on input', () => {
+ createComponent();
+
+ const clickSpy = jest.spyOn(wrapper.find('input').element, 'click');
+
+ wrapper.vm.openFileUpload();
+
+ expect(clickSpy).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/upload/design_dropzone_spec.js b/spec/frontend/design_management_new/components/upload/design_dropzone_spec.js
new file mode 100644
index 00000000000..aab35bc1313
--- /dev/null
+++ b/spec/frontend/design_management_new/components/upload/design_dropzone_spec.js
@@ -0,0 +1,132 @@
+import { shallowMount } from '@vue/test-utils';
+import DesignDropzone from '~/design_management_new/components/upload/design_dropzone.vue';
+import createFlash from '~/flash';
+
+jest.mock('~/flash');
+
+describe('Design management dropzone component', () => {
+ let wrapper;
+
+ const mockDragEvent = ({ types = ['Files'], files = [] }) => {
+ return { dataTransfer: { types, files } };
+ };
+
+ const findDropzoneCard = () => wrapper.find('.design-dropzone-card');
+
+ function createComponent({ slots = {}, data = {} } = {}) {
+ wrapper = shallowMount(DesignDropzone, {
+ slots,
+ data() {
+ return data;
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when slot provided', () => {
+ it('renders dropzone with slot content', () => {
+ createComponent({
+ slots: {
+ default: ['<div>dropzone slot</div>'],
+ },
+ });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ describe('when no slot provided', () => {
+ it('renders default dropzone card', () => {
+ createComponent();
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('triggers click event on file input element when clicked', () => {
+ createComponent();
+ const clickSpy = jest.spyOn(wrapper.find('input').element, 'click');
+
+ findDropzoneCard().trigger('click');
+ expect(clickSpy).toHaveBeenCalled();
+ });
+ });
+
+ describe('when dragging', () => {
+ it.each`
+ description | eventPayload
+ ${'is empty'} | ${{}}
+ ${'contains text'} | ${mockDragEvent({ types: ['text'] })}
+ ${'contains files and text'} | ${mockDragEvent({ types: ['Files', 'text'] })}
+ ${'contains files'} | ${mockDragEvent({ types: ['Files'] })}
+ `('renders correct template when drag event $description', ({ eventPayload }) => {
+ createComponent();
+
+ wrapper.trigger('dragenter', eventPayload);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('renders correct template when dragging stops', () => {
+ createComponent();
+
+ wrapper.trigger('dragenter');
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ wrapper.trigger('dragleave');
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+ });
+
+ describe('when dropping', () => {
+ it('emits upload event', () => {
+ createComponent();
+ const mockFile = { name: 'test', type: 'image/jpg' };
+ const mockEvent = mockDragEvent({ files: [mockFile] });
+
+ wrapper.trigger('dragenter', mockEvent);
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ wrapper.trigger('drop', mockEvent);
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ expect(wrapper.emitted().change[0]).toEqual([[mockFile]]);
+ });
+ });
+ });
+
+ describe('ondrop', () => {
+ const mockData = { dragCounter: 1, isDragDataValid: true };
+
+ describe('when drag data is valid', () => {
+ it('emits upload event for valid files', () => {
+ createComponent({ data: mockData });
+
+ const mockFile = { type: 'image/jpg' };
+ const mockEvent = mockDragEvent({ files: [mockFile] });
+
+ wrapper.vm.ondrop(mockEvent);
+ expect(wrapper.emitted().change[0]).toEqual([[mockFile]]);
+ });
+
+ it('calls createFlash when files are invalid', () => {
+ createComponent({ data: mockData });
+
+ const mockEvent = mockDragEvent({ files: [{ type: 'audio/midi' }] });
+
+ wrapper.vm.ondrop(mockEvent);
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/upload/design_version_dropdown_spec.js b/spec/frontend/design_management_new/components/upload/design_version_dropdown_spec.js
new file mode 100644
index 00000000000..48c783423c1
--- /dev/null
+++ b/spec/frontend/design_management_new/components/upload/design_version_dropdown_spec.js
@@ -0,0 +1,114 @@
+import { shallowMount } from '@vue/test-utils';
+import DesignVersionDropdown from '~/design_management_new/components/upload/design_version_dropdown.vue';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import mockAllVersions from './mock_data/all_versions';
+
+const LATEST_VERSION_ID = 3;
+const PREVIOUS_VERSION_ID = 2;
+
+const designRouteFactory = versionId => ({
+ path: `/designs?version=${versionId}`,
+ query: {
+ version: `${versionId}`,
+ },
+});
+
+const MOCK_ROUTE = {
+ path: '/designs',
+ query: {},
+};
+
+describe('Design management design version dropdown component', () => {
+ let wrapper;
+
+ function createComponent({ maxVersions = -1, $route = MOCK_ROUTE } = {}) {
+ wrapper = shallowMount(DesignVersionDropdown, {
+ propsData: {
+ projectPath: '',
+ issueIid: '',
+ },
+ mocks: {
+ $route,
+ },
+ stubs: ['router-link'],
+ });
+
+ wrapper.setData({
+ allVersions: maxVersions > -1 ? mockAllVersions.slice(0, maxVersions) : mockAllVersions,
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findVersionLink = index => wrapper.findAll('.js-version-link').at(index);
+
+ it('renders design version dropdown button', () => {
+ createComponent();
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('renders design version list', () => {
+ createComponent();
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ describe('selected version name', () => {
+ it('has "latest" on most recent version item', () => {
+ createComponent();
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findVersionLink(0).text()).toContain('latest');
+ });
+ });
+ });
+
+ describe('versions list', () => {
+ it('displays latest version text by default', () => {
+ createComponent();
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.find(GlDropdown).attributes('text')).toBe('Showing Latest Version');
+ });
+ });
+
+ it('displays latest version text when only 1 version is present', () => {
+ createComponent({ maxVersions: 1 });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.find(GlDropdown).attributes('text')).toBe('Showing Latest Version');
+ });
+ });
+
+ it('displays version text when the current version is not the latest', () => {
+ createComponent({ $route: designRouteFactory(PREVIOUS_VERSION_ID) });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.find(GlDropdown).attributes('text')).toBe(`Showing Version #1`);
+ });
+ });
+
+ it('displays latest version text when the current version is the latest', () => {
+ createComponent({ $route: designRouteFactory(LATEST_VERSION_ID) });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.find(GlDropdown).attributes('text')).toBe('Showing Latest Version');
+ });
+ });
+
+ it('should have the same length as apollo query', () => {
+ createComponent();
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.findAll(GlDropdownItem)).toHaveLength(wrapper.vm.allVersions.length);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/components/upload/mock_data/all_versions.js b/spec/frontend/design_management_new/components/upload/mock_data/all_versions.js
new file mode 100644
index 00000000000..e76bbd261bd
--- /dev/null
+++ b/spec/frontend/design_management_new/components/upload/mock_data/all_versions.js
@@ -0,0 +1,14 @@
+export default [
+ {
+ node: {
+ id: 'gid://gitlab/DesignManagement::Version/3',
+ sha: '0945756378e0b1588b9dd40d5a6b99e8b7198f55',
+ },
+ },
+ {
+ node: {
+ id: 'gid://gitlab/DesignManagement::Version/2',
+ sha: '5b063fef0cd7213b312db65b30e24f057df21b20',
+ },
+ },
+];
diff --git a/spec/frontend/design_management_new/mock_data/all_versions.js b/spec/frontend/design_management_new/mock_data/all_versions.js
new file mode 100644
index 00000000000..c389fdb8747
--- /dev/null
+++ b/spec/frontend/design_management_new/mock_data/all_versions.js
@@ -0,0 +1,8 @@
+export default [
+ {
+ node: {
+ id: 'gid://gitlab/DesignManagement::Version/1',
+ sha: 'b389071a06c153509e11da1f582005b316667001',
+ },
+ },
+];
diff --git a/spec/frontend/design_management_new/mock_data/design.js b/spec/frontend/design_management_new/mock_data/design.js
new file mode 100644
index 00000000000..675198b9408
--- /dev/null
+++ b/spec/frontend/design_management_new/mock_data/design.js
@@ -0,0 +1,74 @@
+export default {
+ id: 'design-id',
+ filename: 'test.jpg',
+ fullPath: 'full-design-path',
+ image: 'test.jpg',
+ updatedAt: '01-01-2019',
+ updatedBy: {
+ name: 'test',
+ },
+ issue: {
+ title: 'My precious issue',
+ webPath: 'full-issue-path',
+ webUrl: 'full-issue-url',
+ participants: {
+ edges: [
+ {
+ node: {
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'link-to-author',
+ avatarUrl: 'link-to-avatar',
+ },
+ },
+ ],
+ },
+ },
+ discussions: {
+ nodes: [
+ {
+ id: 'discussion-id',
+ replyId: 'discussion-reply-id',
+ resolved: false,
+ notes: {
+ nodes: [
+ {
+ id: 'note-id',
+ body: '123',
+ author: {
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'link-to-author',
+ avatarUrl: 'link-to-avatar',
+ },
+ },
+ ],
+ },
+ },
+ {
+ id: 'discussion-resolved',
+ replyId: 'discussion-reply-resolved',
+ resolved: true,
+ notes: {
+ nodes: [
+ {
+ id: 'note-resolved',
+ body: '123',
+ author: {
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'link-to-author',
+ avatarUrl: 'link-to-avatar',
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ diffRefs: {
+ headSha: 'headSha',
+ baseSha: 'baseSha',
+ startSha: 'startSha',
+ },
+};
diff --git a/spec/frontend/design_management_new/mock_data/designs.js b/spec/frontend/design_management_new/mock_data/designs.js
new file mode 100644
index 00000000000..07f5c1b7457
--- /dev/null
+++ b/spec/frontend/design_management_new/mock_data/designs.js
@@ -0,0 +1,17 @@
+import design from './design';
+
+export default {
+ project: {
+ issue: {
+ designCollection: {
+ designs: {
+ edges: [
+ {
+ node: design,
+ },
+ ],
+ },
+ },
+ },
+ },
+};
diff --git a/spec/frontend/design_management_new/mock_data/no_designs.js b/spec/frontend/design_management_new/mock_data/no_designs.js
new file mode 100644
index 00000000000..9db0ffcade2
--- /dev/null
+++ b/spec/frontend/design_management_new/mock_data/no_designs.js
@@ -0,0 +1,11 @@
+export default {
+ project: {
+ issue: {
+ designCollection: {
+ designs: {
+ edges: [],
+ },
+ },
+ },
+ },
+};
diff --git a/spec/frontend/design_management_new/mock_data/notes.js b/spec/frontend/design_management_new/mock_data/notes.js
new file mode 100644
index 00000000000..80cb3944786
--- /dev/null
+++ b/spec/frontend/design_management_new/mock_data/notes.js
@@ -0,0 +1,46 @@
+export default [
+ {
+ id: 'note-id-1',
+ index: 1,
+ position: {
+ height: 100,
+ width: 100,
+ x: 10,
+ y: 15,
+ },
+ author: {
+ name: 'John',
+ webUrl: 'link-to-john-profile',
+ },
+ createdAt: '2020-05-08T07:10:45Z',
+ userPermissions: {
+ adminNote: true,
+ },
+ discussion: {
+ id: 'discussion-id-1',
+ },
+ resolved: false,
+ },
+ {
+ id: 'note-id-2',
+ index: 2,
+ position: {
+ height: 50,
+ width: 50,
+ x: 25,
+ y: 25,
+ },
+ author: {
+ name: 'Mary',
+ webUrl: 'link-to-mary-profile',
+ },
+ createdAt: '2020-05-08T07:10:45Z',
+ userPermissions: {
+ adminNote: true,
+ },
+ discussion: {
+ id: 'discussion-id-2',
+ },
+ resolved: true,
+ },
+];
diff --git a/spec/frontend/design_management_new/pages/__snapshots__/index_spec.js.snap b/spec/frontend/design_management_new/pages/__snapshots__/index_spec.js.snap
new file mode 100644
index 00000000000..3ba63fd14f0
--- /dev/null
+++ b/spec/frontend/design_management_new/pages/__snapshots__/index_spec.js.snap
@@ -0,0 +1,263 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management index page designs does not render toolbar when there is no permission 1`] = `
+<div>
+ <!---->
+
+ <div
+ class="mt-4"
+ >
+ <ol
+ class="list-unstyled row"
+ >
+ <li
+ class="col-md-6 col-lg-4 mb-3"
+ >
+ <design-dropzone-stub
+ class="design-list-item"
+ />
+ </li>
+
+ <li
+ class="col-md-6 col-lg-4 mb-3"
+ >
+ <design-dropzone-stub>
+ <design-stub
+ event="NONE"
+ filename="design-1-name"
+ id="design-1"
+ image="design-1-image"
+ notescount="0"
+ />
+ </design-dropzone-stub>
+
+ <!---->
+ </li>
+ <li
+ class="col-md-6 col-lg-4 mb-3"
+ >
+ <design-dropzone-stub>
+ <design-stub
+ event="NONE"
+ filename="design-2-name"
+ id="design-2"
+ image="design-2-image"
+ notescount="1"
+ />
+ </design-dropzone-stub>
+
+ <!---->
+ </li>
+ <li
+ class="col-md-6 col-lg-4 mb-3"
+ >
+ <design-dropzone-stub>
+ <design-stub
+ event="NONE"
+ filename="design-3-name"
+ id="design-3"
+ image="design-3-image"
+ notescount="0"
+ />
+ </design-dropzone-stub>
+
+ <!---->
+ </li>
+ </ol>
+ </div>
+
+ <router-view-stub
+ name="default"
+ />
+</div>
+`;
+
+exports[`Design management index page designs renders designs list and header with upload button 1`] = `
+<div>
+ <header
+ class="row-content-block border-top-0 p-2 d-flex"
+ >
+ <div
+ class="d-flex justify-content-between align-items-center w-100"
+ >
+ <design-version-dropdown-stub />
+
+ <div
+ class="qa-selector-toolbar d-flex"
+ >
+ <gl-deprecated-button-stub
+ class="mr-2 js-select-all"
+ size="md"
+ variant="link"
+ >
+ Select all
+ </gl-deprecated-button-stub>
+
+ <div>
+ <delete-button-stub
+ buttonclass="btn-danger btn-inverted mr-2"
+ buttonvariant=""
+ >
+
+ Delete selected
+
+ <!---->
+ </delete-button-stub>
+ </div>
+
+ <upload-button-stub />
+ </div>
+ </div>
+ </header>
+
+ <div
+ class="mt-4"
+ >
+ <ol
+ class="list-unstyled row"
+ >
+ <li
+ class="col-md-6 col-lg-4 mb-3"
+ >
+ <design-dropzone-stub
+ class="design-list-item"
+ />
+ </li>
+
+ <li
+ class="col-md-6 col-lg-4 mb-3"
+ >
+ <design-dropzone-stub>
+ <design-stub
+ event="NONE"
+ filename="design-1-name"
+ id="design-1"
+ image="design-1-image"
+ notescount="0"
+ />
+ </design-dropzone-stub>
+
+ <input
+ class="design-checkbox"
+ type="checkbox"
+ />
+ </li>
+ <li
+ class="col-md-6 col-lg-4 mb-3"
+ >
+ <design-dropzone-stub>
+ <design-stub
+ event="NONE"
+ filename="design-2-name"
+ id="design-2"
+ image="design-2-image"
+ notescount="1"
+ />
+ </design-dropzone-stub>
+
+ <input
+ class="design-checkbox"
+ type="checkbox"
+ />
+ </li>
+ <li
+ class="col-md-6 col-lg-4 mb-3"
+ >
+ <design-dropzone-stub>
+ <design-stub
+ event="NONE"
+ filename="design-3-name"
+ id="design-3"
+ image="design-3-image"
+ notescount="0"
+ />
+ </design-dropzone-stub>
+
+ <input
+ class="design-checkbox"
+ type="checkbox"
+ />
+ </li>
+ </ol>
+ </div>
+
+ <router-view-stub
+ name="default"
+ />
+</div>
+`;
+
+exports[`Design management index page designs renders error 1`] = `
+<div>
+ <!---->
+
+ <div
+ class="mt-4"
+ >
+ <gl-alert-stub
+ dismisslabel="Dismiss"
+ primarybuttonlink=""
+ primarybuttontext=""
+ secondarybuttonlink=""
+ secondarybuttontext=""
+ title=""
+ variant="danger"
+ >
+
+ An error occurred while loading designs. Please try again.
+
+ </gl-alert-stub>
+ </div>
+
+ <router-view-stub
+ name="default"
+ />
+</div>
+`;
+
+exports[`Design management index page designs renders loading icon 1`] = `
+<div>
+ <!---->
+
+ <div
+ class="mt-4"
+ >
+ <gl-loading-icon-stub
+ color="orange"
+ label="Loading"
+ size="md"
+ />
+ </div>
+
+ <router-view-stub
+ name="default"
+ />
+</div>
+`;
+
+exports[`Design management index page when has no designs renders empty text 1`] = `
+<div>
+ <!---->
+
+ <div
+ class="mt-4"
+ >
+ <ol
+ class="list-unstyled row"
+ >
+ <li
+ class="col-md-6 col-lg-4 mb-3"
+ >
+ <design-dropzone-stub
+ class="design-list-item"
+ />
+ </li>
+
+ </ol>
+ </div>
+
+ <router-view-stub
+ name="default"
+ />
+</div>
+`;
diff --git a/spec/frontend/design_management_new/pages/design/__snapshots__/index_spec.js.snap b/spec/frontend/design_management_new/pages/design/__snapshots__/index_spec.js.snap
new file mode 100644
index 00000000000..65c4811536e
--- /dev/null
+++ b/spec/frontend/design_management_new/pages/design/__snapshots__/index_spec.js.snap
@@ -0,0 +1,216 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Design management design index page renders design index 1`] = `
+<div
+ class="design-detail js-design-detail fixed-top w-100 position-bottom-0 d-flex justify-content-center flex-column flex-lg-row"
+>
+ <div
+ class="d-flex overflow-hidden flex-grow-1 flex-column position-relative"
+ >
+ <design-destroyer-stub
+ filenames="test.jpg"
+ iid="1"
+ projectpath=""
+ />
+
+ <!---->
+
+ <design-presentation-stub
+ discussions="[object Object],[object Object]"
+ image="test.jpg"
+ imagename="test.jpg"
+ scale="1"
+ />
+
+ <div
+ class="design-scaler-wrapper position-absolute mb-4 d-flex-center"
+ >
+ <design-scaler-stub />
+ </div>
+ </div>
+
+ <div
+ class="image-notes"
+ >
+ <h2
+ class="gl-font-weight-bold gl-mt-0"
+ >
+
+ My precious issue
+
+ </h2>
+
+ <a
+ class="gl-text-gray-600 gl-text-decoration-none gl-mb-6 gl-display-block"
+ href="full-issue-url"
+ >
+ ull-issue-path
+ </a>
+
+ <participants-stub
+ class="gl-mb-4"
+ numberoflessparticipants="7"
+ participants="[object Object]"
+ />
+
+ <!---->
+
+ <design-discussion-stub
+ data-testid="unresolved-discussion"
+ designid="test"
+ discussion="[object Object]"
+ discussionwithopenform=""
+ markdownpreviewpath="//preview_markdown?target_type=Issue"
+ noteableid="design-id"
+ />
+
+ <gl-button-stub
+ category="tertiary"
+ class="link-inherit-color gl-text-black-normal gl-text-decoration-none gl-font-weight-bold gl-mb-4"
+ data-testid="resolved-comments"
+ icon="chevron-right"
+ id="resolved-comments"
+ size="medium"
+ variant="link"
+ >
+ Resolved Comments (1)
+
+ </gl-button-stub>
+
+ <gl-popover-stub
+ container="popovercontainer"
+ cssclasses=""
+ placement="top"
+ show="true"
+ target="resolved-comments"
+ title="Resolved Comments"
+ >
+ <p>
+
+ Comments you resolve can be viewed and unresolved by going to the "Resolved Comments" section below
+
+ </p>
+
+ <a
+ href="#"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ Learn more about resolving comments
+ </a>
+ </gl-popover-stub>
+
+ <gl-collapse-stub
+ class="gl-mt-3"
+ >
+ <design-discussion-stub
+ data-testid="resolved-discussion"
+ designid="test"
+ discussion="[object Object]"
+ discussionwithopenform=""
+ markdownpreviewpath="//preview_markdown?target_type=Issue"
+ noteableid="design-id"
+ />
+ </gl-collapse-stub>
+
+ </div>
+</div>
+`;
+
+exports[`Design management design index page sets loading state 1`] = `
+<div
+ class="design-detail js-design-detail fixed-top w-100 position-bottom-0 d-flex justify-content-center flex-column flex-lg-row"
+>
+ <gl-loading-icon-stub
+ class="align-self-center"
+ color="orange"
+ label="Loading"
+ size="xl"
+ />
+</div>
+`;
+
+exports[`Design management design index page with error GlAlert is rendered in correct position with correct content 1`] = `
+<div
+ class="design-detail js-design-detail fixed-top w-100 position-bottom-0 d-flex justify-content-center flex-column flex-lg-row"
+>
+ <div
+ class="d-flex overflow-hidden flex-grow-1 flex-column position-relative"
+ >
+ <design-destroyer-stub
+ filenames="test.jpg"
+ iid="1"
+ projectpath=""
+ />
+
+ <div
+ class="p-3"
+ >
+ <gl-alert-stub
+ dismissible="true"
+ dismisslabel="Dismiss"
+ primarybuttonlink=""
+ primarybuttontext=""
+ secondarybuttonlink=""
+ secondarybuttontext=""
+ title=""
+ variant="danger"
+ >
+
+ woops
+
+ </gl-alert-stub>
+ </div>
+
+ <design-presentation-stub
+ discussions=""
+ image="test.jpg"
+ imagename="test.jpg"
+ scale="1"
+ />
+
+ <div
+ class="design-scaler-wrapper position-absolute mb-4 d-flex-center"
+ >
+ <design-scaler-stub />
+ </div>
+ </div>
+
+ <div
+ class="image-notes"
+ >
+ <h2
+ class="gl-font-weight-bold gl-mt-0"
+ >
+
+ My precious issue
+
+ </h2>
+
+ <a
+ class="gl-text-gray-600 gl-text-decoration-none gl-mb-6 gl-display-block"
+ href="full-issue-url"
+ >
+ ull-issue-path
+ </a>
+
+ <participants-stub
+ class="gl-mb-4"
+ numberoflessparticipants="7"
+ participants="[object Object]"
+ />
+
+ <h2
+ class="new-discussion-disclaimer gl-font-base gl-m-0 gl-mb-4"
+ data-testid="new-discussion-disclaimer"
+ >
+
+ Click the image where you'd like to start a new discussion
+
+ </h2>
+
+ <!---->
+
+ </div>
+</div>
+`;
diff --git a/spec/frontend/design_management_new/pages/design/index_spec.js b/spec/frontend/design_management_new/pages/design/index_spec.js
new file mode 100644
index 00000000000..cedfccfa342
--- /dev/null
+++ b/spec/frontend/design_management_new/pages/design/index_spec.js
@@ -0,0 +1,291 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import VueRouter from 'vue-router';
+import { GlAlert } from '@gitlab/ui';
+import { ApolloMutation } from 'vue-apollo';
+import createFlash from '~/flash';
+import DesignIndex from '~/design_management_new/pages/design/index.vue';
+import DesignSidebar from '~/design_management_new/components/design_sidebar.vue';
+import DesignPresentation from '~/design_management_new/components/design_presentation.vue';
+import createImageDiffNoteMutation from '~/design_management_new/graphql/mutations/create_image_diff_note.mutation.graphql';
+import design from '../../mock_data/design';
+import mockResponseWithDesigns from '../../mock_data/designs';
+import mockResponseNoDesigns from '../../mock_data/no_designs';
+import mockAllVersions from '../../mock_data/all_versions';
+import {
+ DESIGN_NOT_FOUND_ERROR,
+ DESIGN_VERSION_NOT_EXIST_ERROR,
+} from '~/design_management_new/utils/error_messages';
+import { DESIGNS_ROUTE_NAME } from '~/design_management_new/router/constants';
+import createRouter from '~/design_management_new/router';
+import * as utils from '~/design_management_new/utils/design_management_utils';
+import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '~/design_management_new/constants';
+
+jest.mock('~/flash');
+jest.mock('mousetrap', () => ({
+ bind: jest.fn(),
+ unbind: jest.fn(),
+}));
+
+const focusInput = jest.fn();
+
+const DesignReplyForm = {
+ template: '<div><textarea ref="textarea"></textarea></div>',
+ methods: {
+ focusInput,
+ },
+};
+
+const localVue = createLocalVue();
+localVue.use(VueRouter);
+
+describe('Design management design index page', () => {
+ let wrapper;
+ let router;
+
+ const newComment = 'new comment';
+ const annotationCoordinates = {
+ x: 10,
+ y: 10,
+ width: 100,
+ height: 100,
+ };
+ const createDiscussionMutationVariables = {
+ mutation: createImageDiffNoteMutation,
+ update: expect.anything(),
+ variables: {
+ input: {
+ body: newComment,
+ noteableId: design.id,
+ position: {
+ headSha: 'headSha',
+ baseSha: 'baseSha',
+ startSha: 'startSha',
+ paths: {
+ newPath: 'full-design-path',
+ },
+ ...annotationCoordinates,
+ },
+ },
+ },
+ };
+
+ const mutate = jest.fn().mockResolvedValue();
+
+ const findDiscussionForm = () => wrapper.find(DesignReplyForm);
+ const findSidebar = () => wrapper.find(DesignSidebar);
+ const findDesignPresentation = () => wrapper.find(DesignPresentation);
+
+ function createComponent(loading = false, data = {}) {
+ const $apollo = {
+ queries: {
+ design: {
+ loading,
+ },
+ },
+ mutate,
+ };
+
+ router = createRouter();
+
+ wrapper = shallowMount(DesignIndex, {
+ propsData: { id: '1' },
+ mocks: { $apollo },
+ stubs: {
+ ApolloMutation,
+ DesignSidebar,
+ DesignReplyForm,
+ },
+ data() {
+ return {
+ issueIid: '1',
+ activeDiscussion: {
+ id: null,
+ source: null,
+ },
+ ...data,
+ };
+ },
+ localVue,
+ router,
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when navigating', () => {
+ it('applies fullscreen layout', () => {
+ const mockEl = {
+ classList: {
+ add: jest.fn(),
+ remove: jest.fn(),
+ },
+ };
+ jest.spyOn(utils, 'getPageLayoutElement').mockReturnValue(mockEl);
+ createComponent(true);
+
+ wrapper.vm.$router.push('/designs/test');
+ expect(mockEl.classList.add).toHaveBeenCalledTimes(1);
+ expect(mockEl.classList.add).toHaveBeenCalledWith(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
+ });
+ });
+
+ it('sets loading state', () => {
+ createComponent(true);
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders design index', () => {
+ createComponent(false, { design });
+
+ expect(wrapper.element).toMatchSnapshot();
+ expect(wrapper.find(GlAlert).exists()).toBe(false);
+ });
+
+ it('passes correct props to sidebar component', () => {
+ createComponent(false, { design });
+
+ expect(findSidebar().props()).toEqual({
+ design,
+ markdownPreviewPath: '//preview_markdown?target_type=Issue',
+ resolvedDiscussionsExpanded: false,
+ });
+ });
+
+ it('opens a new discussion form', () => {
+ createComponent(false, {
+ design: {
+ ...design,
+ discussions: {
+ nodes: [],
+ },
+ },
+ });
+
+ findDesignPresentation().vm.$emit('openCommentForm', { x: 0, y: 0 });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findDiscussionForm().exists()).toBe(true);
+ });
+ });
+
+ it('keeps new discussion form focused', () => {
+ createComponent(false, {
+ design: {
+ ...design,
+ discussions: {
+ nodes: [],
+ },
+ },
+ annotationCoordinates,
+ });
+
+ findDesignPresentation().vm.$emit('openCommentForm', { x: 10, y: 10 });
+
+ expect(focusInput).toHaveBeenCalled();
+ });
+
+ it('sends a mutation on submitting form and closes form', () => {
+ createComponent(false, {
+ design: {
+ ...design,
+ discussions: {
+ nodes: [],
+ },
+ },
+ annotationCoordinates,
+ comment: newComment,
+ });
+
+ findDiscussionForm().vm.$emit('submitForm');
+ expect(mutate).toHaveBeenCalledWith(createDiscussionMutationVariables);
+
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ return mutate({ variables: createDiscussionMutationVariables });
+ })
+ .then(() => {
+ expect(findDiscussionForm().exists()).toBe(false);
+ });
+ });
+
+ it('closes the form and clears the comment on canceling form', () => {
+ createComponent(false, {
+ design: {
+ ...design,
+ discussions: {
+ nodes: [],
+ },
+ },
+ annotationCoordinates,
+ comment: newComment,
+ });
+
+ findDiscussionForm().vm.$emit('cancelForm');
+
+ expect(wrapper.vm.comment).toBe('');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findDiscussionForm().exists()).toBe(false);
+ });
+ });
+
+ describe('with error', () => {
+ beforeEach(() => {
+ createComponent(false, {
+ design: {
+ ...design,
+ discussions: {
+ nodes: [],
+ },
+ },
+ errorMessage: 'woops',
+ });
+ });
+
+ it('GlAlert is rendered in correct position with correct content', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ describe('onDesignQueryResult', () => {
+ describe('with no designs', () => {
+ it('redirects to /designs', () => {
+ createComponent(true);
+ router.push = jest.fn();
+
+ wrapper.vm.onDesignQueryResult({ data: mockResponseNoDesigns, loading: false });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith(DESIGN_NOT_FOUND_ERROR);
+ expect(router.push).toHaveBeenCalledTimes(1);
+ expect(router.push).toHaveBeenCalledWith({ name: DESIGNS_ROUTE_NAME });
+ });
+ });
+ });
+
+ describe('when no design exists for given version', () => {
+ it('redirects to /designs', () => {
+ createComponent(true);
+ wrapper.setData({
+ allVersions: mockAllVersions,
+ });
+
+ // attempt to query for a version of the design that doesn't exist
+ router.push({ query: { version: '999' } });
+ router.push = jest.fn();
+
+ wrapper.vm.onDesignQueryResult({ data: mockResponseWithDesigns, loading: false });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith(DESIGN_VERSION_NOT_EXIST_ERROR);
+ expect(router.push).toHaveBeenCalledTimes(1);
+ expect(router.push).toHaveBeenCalledWith({ name: DESIGNS_ROUTE_NAME });
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/pages/index_spec.js b/spec/frontend/design_management_new/pages/index_spec.js
new file mode 100644
index 00000000000..bab9b501bf1
--- /dev/null
+++ b/spec/frontend/design_management_new/pages/index_spec.js
@@ -0,0 +1,543 @@
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { ApolloMutation } from 'vue-apollo';
+import VueRouter from 'vue-router';
+import { GlEmptyState } from '@gitlab/ui';
+import Index from '~/design_management_new/pages/index.vue';
+import uploadDesignQuery from '~/design_management_new/graphql/mutations/upload_design.mutation.graphql';
+import DesignDestroyer from '~/design_management_new/components/design_destroyer.vue';
+import DesignDropzone from '~/design_management_new/components/upload/design_dropzone.vue';
+import DeleteButton from '~/design_management_new/components/delete_button.vue';
+import { DESIGNS_ROUTE_NAME } from '~/design_management_new/router/constants';
+import {
+ EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE,
+ EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE,
+} from '~/design_management_new/utils/error_messages';
+import createFlash from '~/flash';
+import createRouter from '~/design_management_new/router';
+import * as utils from '~/design_management_new/utils/design_management_utils';
+import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '~/design_management_new/constants';
+
+jest.mock('~/flash.js');
+const mockPageEl = {
+ classList: {
+ remove: jest.fn(),
+ },
+};
+jest.spyOn(utils, 'getPageLayoutElement').mockReturnValue(mockPageEl);
+
+const localVue = createLocalVue();
+const router = createRouter();
+localVue.use(VueRouter);
+
+const mockDesigns = [
+ {
+ id: 'design-1',
+ image: 'design-1-image',
+ filename: 'design-1-name',
+ event: 'NONE',
+ notesCount: 0,
+ },
+ {
+ id: 'design-2',
+ image: 'design-2-image',
+ filename: 'design-2-name',
+ event: 'NONE',
+ notesCount: 1,
+ },
+ {
+ id: 'design-3',
+ image: 'design-3-image',
+ filename: 'design-3-name',
+ event: 'NONE',
+ notesCount: 0,
+ },
+];
+
+const mockVersion = {
+ node: {
+ id: 'gid://gitlab/DesignManagement::Version/1',
+ },
+};
+
+describe('Design management index page', () => {
+ let mutate;
+ let wrapper;
+
+ const findDesignCheckboxes = () => wrapper.findAll('.design-checkbox');
+ const findSelectAllButton = () => wrapper.find('.js-select-all');
+ const findToolbar = () => wrapper.find('.qa-selector-toolbar');
+ const findDeleteButton = () => wrapper.find(DeleteButton);
+ const findDropzone = () => wrapper.findAll(DesignDropzone).at(0);
+ const findFirstDropzoneWithDesign = () => wrapper.findAll(DesignDropzone).at(1);
+
+ function createComponent({
+ loading = false,
+ designs = [],
+ allVersions = [],
+ createDesign = true,
+ stubs = {},
+ mockMutate = jest.fn().mockResolvedValue(),
+ } = {}) {
+ mutate = mockMutate;
+ const $apollo = {
+ queries: {
+ designs: {
+ loading,
+ },
+ permissions: {
+ loading,
+ },
+ },
+ mutate,
+ };
+
+ wrapper = shallowMount(Index, {
+ mocks: { $apollo },
+ localVue,
+ router,
+ stubs: { DesignDestroyer, ApolloMutation, ...stubs },
+ attachToDocument: true,
+ });
+
+ wrapper.setData({
+ designs,
+ allVersions,
+ issueIid: '1',
+ permissions: {
+ createDesign,
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('designs', () => {
+ it('renders loading icon', () => {
+ createComponent({ loading: true });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('renders error', () => {
+ createComponent();
+
+ wrapper.setData({ error: true });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('renders a toolbar with buttons when there are designs', () => {
+ createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findToolbar().exists()).toBe(true);
+ });
+ });
+
+ it('renders designs list and header with upload button', () => {
+ createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ it('does not render toolbar when there is no permission', () => {
+ createComponent({ designs: mockDesigns, allVersions: [mockVersion], createDesign: false });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+ });
+
+ describe('when has no designs', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders empty text', () =>
+ wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.element).toMatchSnapshot();
+ }));
+
+ it('does not render a toolbar with buttons', () =>
+ wrapper.vm.$nextTick().then(() => {
+ expect(findToolbar().exists()).toBe(false);
+ }));
+ });
+
+ describe('uploading designs', () => {
+ it('calls mutation on upload', () => {
+ createComponent({ stubs: { GlEmptyState } });
+
+ const mutationVariables = {
+ update: expect.anything(),
+ context: {
+ hasUpload: true,
+ },
+ mutation: uploadDesignQuery,
+ variables: {
+ files: [{ name: 'test' }],
+ projectPath: '',
+ iid: '1',
+ },
+ optimisticResponse: {
+ __typename: 'Mutation',
+ designManagementUpload: {
+ __typename: 'DesignManagementUploadPayload',
+ designs: [
+ {
+ __typename: 'Design',
+ id: expect.anything(),
+ image: '',
+ imageV432x230: '',
+ filename: 'test',
+ fullPath: '',
+ event: 'NONE',
+ notesCount: 0,
+ diffRefs: {
+ __typename: 'DiffRefs',
+ baseSha: '',
+ startSha: '',
+ headSha: '',
+ },
+ discussions: {
+ __typename: 'DesignDiscussion',
+ nodes: [],
+ },
+ versions: {
+ __typename: 'DesignVersionConnection',
+ edges: {
+ __typename: 'DesignVersionEdge',
+ node: {
+ __typename: 'DesignVersion',
+ id: expect.anything(),
+ sha: expect.anything(),
+ },
+ },
+ },
+ },
+ ],
+ skippedDesigns: [],
+ errors: [],
+ },
+ },
+ };
+
+ return wrapper.vm.$nextTick().then(() => {
+ findDropzone().vm.$emit('change', [{ name: 'test' }]);
+ expect(mutate).toHaveBeenCalledWith(mutationVariables);
+ expect(wrapper.vm.filesToBeSaved).toEqual([{ name: 'test' }]);
+ expect(wrapper.vm.isSaving).toBeTruthy();
+ });
+ });
+
+ it('sets isSaving', () => {
+ createComponent();
+
+ const uploadDesign = wrapper.vm.onUploadDesign([
+ {
+ name: 'test',
+ },
+ ]);
+
+ expect(wrapper.vm.isSaving).toBe(true);
+
+ return uploadDesign.then(() => {
+ expect(wrapper.vm.isSaving).toBe(false);
+ });
+ });
+
+ it('updates state appropriately after upload complete', () => {
+ createComponent({ stubs: { GlEmptyState } });
+ wrapper.setData({ filesToBeSaved: [{ name: 'test' }] });
+
+ wrapper.vm.onUploadDesignDone();
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.filesToBeSaved).toEqual([]);
+ expect(wrapper.vm.isSaving).toBeFalsy();
+ expect(wrapper.vm.isLatestVersion).toBe(true);
+ });
+ });
+
+ it('updates state appropriately after upload error', () => {
+ createComponent({ stubs: { GlEmptyState } });
+ wrapper.setData({ filesToBeSaved: [{ name: 'test' }] });
+
+ wrapper.vm.onUploadDesignError();
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.filesToBeSaved).toEqual([]);
+ expect(wrapper.vm.isSaving).toBeFalsy();
+ expect(createFlash).toHaveBeenCalled();
+
+ createFlash.mockReset();
+ });
+ });
+
+ it('does not call mutation if createDesign is false', () => {
+ createComponent({ createDesign: false });
+
+ wrapper.vm.onUploadDesign([]);
+
+ expect(mutate).not.toHaveBeenCalled();
+ });
+
+ describe('upload count limit', () => {
+ const MAXIMUM_FILE_UPLOAD_LIMIT = 10;
+
+ afterEach(() => {
+ createFlash.mockReset();
+ });
+
+ it('does not warn when the max files are uploaded', () => {
+ createComponent();
+
+ wrapper.vm.onUploadDesign(new Array(MAXIMUM_FILE_UPLOAD_LIMIT).fill(mockDesigns[0]));
+
+ expect(createFlash).not.toHaveBeenCalled();
+ });
+
+ it('warns when too many files are uploaded', () => {
+ createComponent();
+
+ wrapper.vm.onUploadDesign(new Array(MAXIMUM_FILE_UPLOAD_LIMIT + 1).fill(mockDesigns[0]));
+
+ expect(createFlash).toHaveBeenCalled();
+ });
+ });
+
+ it('flashes warning if designs are skipped', () => {
+ createComponent({
+ mockMutate: () =>
+ Promise.resolve({
+ data: { designManagementUpload: { skippedDesigns: [{ filename: 'test.jpg' }] } },
+ }),
+ });
+
+ const uploadDesign = wrapper.vm.onUploadDesign([
+ {
+ name: 'test',
+ },
+ ]);
+
+ return uploadDesign.then(() => {
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith(
+ 'Upload skipped. test.jpg did not change.',
+ 'warning',
+ );
+ });
+ });
+
+ describe('dragging onto an existing design', () => {
+ beforeEach(() => {
+ createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
+ });
+
+ it('calls onUploadDesign with valid upload', () => {
+ wrapper.setMethods({
+ onUploadDesign: jest.fn(),
+ });
+
+ const mockUploadPayload = [
+ {
+ name: mockDesigns[0].filename,
+ },
+ ];
+
+ const designDropzone = findFirstDropzoneWithDesign();
+ designDropzone.vm.$emit('change', mockUploadPayload);
+
+ expect(wrapper.vm.onUploadDesign).toHaveBeenCalledTimes(1);
+ expect(wrapper.vm.onUploadDesign).toHaveBeenCalledWith(mockUploadPayload);
+ });
+
+ it.each`
+ description | eventPayload | message
+ ${'> 1 file'} | ${[{ name: 'test' }, { name: 'test-2' }]} | ${EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE}
+ ${'different filename'} | ${[{ name: 'wrong-name' }]} | ${EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE}
+ `('calls createFlash when upload has $description', ({ eventPayload, message }) => {
+ const designDropzone = findFirstDropzoneWithDesign();
+ designDropzone.vm.$emit('change', eventPayload);
+
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith(message);
+ });
+ });
+ });
+
+ describe('on latest version when has designs', () => {
+ beforeEach(() => {
+ createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
+ });
+
+ it('renders design checkboxes', () => {
+ expect(findDesignCheckboxes()).toHaveLength(mockDesigns.length);
+ });
+
+ it('renders toolbar buttons', () => {
+ expect(findToolbar().exists()).toBe(true);
+ expect(findToolbar().classes()).toContain('d-flex');
+ expect(findToolbar().classes()).not.toContain('d-none');
+ });
+
+ it('adds two designs to selected designs when their checkboxes are checked', () => {
+ findDesignCheckboxes()
+ .at(0)
+ .trigger('click');
+
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ findDesignCheckboxes()
+ .at(1)
+ .trigger('click');
+
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ expect(findDeleteButton().exists()).toBe(true);
+ expect(findSelectAllButton().text()).toBe('Deselect all');
+ findDeleteButton().vm.$emit('deleteSelectedDesigns');
+ const [{ variables }] = mutate.mock.calls[0];
+ expect(variables.filenames).toStrictEqual([
+ mockDesigns[0].filename,
+ mockDesigns[1].filename,
+ ]);
+ });
+ });
+
+ it('adds all designs to selected designs when Select All button is clicked', () => {
+ findSelectAllButton().vm.$emit('click');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findDeleteButton().props().hasSelectedDesigns).toBe(true);
+ expect(findSelectAllButton().text()).toBe('Deselect all');
+ expect(wrapper.vm.selectedDesigns).toEqual(mockDesigns.map(design => design.filename));
+ });
+ });
+
+ it('removes all designs from selected designs when at least one design was selected', () => {
+ findDesignCheckboxes()
+ .at(0)
+ .trigger('click');
+
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ findSelectAllButton().vm.$emit('click');
+ })
+ .then(() => {
+ expect(findDeleteButton().props().hasSelectedDesigns).toBe(false);
+ expect(findSelectAllButton().text()).toBe('Select all');
+ expect(wrapper.vm.selectedDesigns).toEqual([]);
+ });
+ });
+ });
+
+ it('on latest version when has no designs does not render toolbar buttons', () => {
+ createComponent({ designs: [], allVersions: [mockVersion] });
+ expect(findToolbar().exists()).toBe(false);
+ });
+
+ describe('on non-latest version', () => {
+ beforeEach(() => {
+ createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
+
+ router.replace({
+ name: DESIGNS_ROUTE_NAME,
+ query: {
+ version: '2',
+ },
+ });
+ });
+
+ it('does not render design checkboxes', () => {
+ expect(findDesignCheckboxes()).toHaveLength(0);
+ });
+
+ it('does not render Delete selected button', () => {
+ expect(findDeleteButton().exists()).toBe(false);
+ });
+
+ it('does not render Select All button', () => {
+ expect(findSelectAllButton().exists()).toBe(false);
+ });
+ });
+
+ describe('pasting a design', () => {
+ let event;
+ beforeEach(() => {
+ createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
+
+ wrapper.setMethods({
+ onUploadDesign: jest.fn(),
+ });
+
+ event = new Event('paste');
+
+ router.replace({
+ name: DESIGNS_ROUTE_NAME,
+ query: {
+ version: '2',
+ },
+ });
+ });
+
+ it('calls onUploadDesign with valid paste', () => {
+ event.clipboardData = {
+ files: [{ name: 'image.png', type: 'image/png' }],
+ getData: () => 'test.png',
+ };
+
+ document.dispatchEvent(event);
+
+ expect(wrapper.vm.onUploadDesign).toHaveBeenCalledTimes(1);
+ expect(wrapper.vm.onUploadDesign).toHaveBeenCalledWith([
+ new File([{ name: 'image.png' }], 'test.png'),
+ ]);
+ });
+
+ it('renames a design if it has an image.png filename', () => {
+ event.clipboardData = {
+ files: [{ name: 'image.png', type: 'image/png' }],
+ getData: () => 'image.png',
+ };
+
+ document.dispatchEvent(event);
+
+ expect(wrapper.vm.onUploadDesign).toHaveBeenCalledTimes(1);
+ expect(wrapper.vm.onUploadDesign).toHaveBeenCalledWith([
+ new File([{ name: 'image.png' }], `design_${Date.now()}.png`),
+ ]);
+ });
+
+ it('does not call onUploadDesign with invalid paste', () => {
+ event.clipboardData = {
+ items: [{ type: 'text/plain' }, { type: 'text' }],
+ files: [],
+ };
+
+ document.dispatchEvent(event);
+
+ expect(wrapper.vm.onUploadDesign).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when navigating', () => {
+ it('ensures fullscreen layout is not applied', () => {
+ createComponent(true);
+
+ wrapper.vm.$router.push('/designs');
+ expect(mockPageEl.classList.remove).toHaveBeenCalledTimes(1);
+ expect(mockPageEl.classList.remove).toHaveBeenCalledWith(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/router_spec.js b/spec/frontend/design_management_new/router_spec.js
new file mode 100644
index 00000000000..972af86195f
--- /dev/null
+++ b/spec/frontend/design_management_new/router_spec.js
@@ -0,0 +1,82 @@
+import { mount, createLocalVue } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import VueRouter from 'vue-router';
+import App from '~/design_management_new/components/app.vue';
+import Designs from '~/design_management_new/pages/index.vue';
+import DesignDetail from '~/design_management_new/pages/design/index.vue';
+import createRouter from '~/design_management_new/router';
+import {
+ ROOT_ROUTE_NAME,
+ DESIGNS_ROUTE_NAME,
+ DESIGN_ROUTE_NAME,
+} from '~/design_management_new/router/constants';
+import '~/commons/bootstrap';
+
+function factory(routeArg) {
+ const localVue = createLocalVue();
+ localVue.use(VueRouter);
+
+ window.gon = { sprite_icons: '' };
+
+ const router = createRouter('/');
+ if (routeArg !== undefined) {
+ router.push(routeArg);
+ }
+
+ return mount(App, {
+ localVue,
+ router,
+ mocks: {
+ $apollo: {
+ queries: {
+ designs: { loading: true },
+ design: { loading: true },
+ permissions: { loading: true },
+ },
+ mutate: jest.fn(),
+ },
+ },
+ });
+}
+
+jest.mock('mousetrap', () => ({
+ bind: jest.fn(),
+ unbind: jest.fn(),
+}));
+
+describe('Design management router', () => {
+ afterEach(() => {
+ window.location.hash = '';
+ });
+
+ describe.each([['/'], [{ name: ROOT_ROUTE_NAME }]])('root route', routeArg => {
+ it('pushes home component', () => {
+ const wrapper = factory(routeArg);
+
+ expect(wrapper.find(Designs).exists()).toBe(true);
+ });
+ });
+
+ describe.each([['/designs'], [{ name: DESIGNS_ROUTE_NAME }]])('designs route', routeArg => {
+ it('pushes designs root component', () => {
+ const wrapper = factory(routeArg);
+
+ expect(wrapper.find(Designs).exists()).toBe(true);
+ });
+ });
+
+ describe.each([['/designs/1'], [{ name: DESIGN_ROUTE_NAME, params: { id: '1' } }]])(
+ 'designs detail route',
+ routeArg => {
+ it('pushes designs detail component', () => {
+ const wrapper = factory(routeArg);
+
+ return nextTick().then(() => {
+ const detail = wrapper.find(DesignDetail);
+ expect(detail.exists()).toBe(true);
+ expect(detail.props('id')).toEqual('1');
+ });
+ });
+ },
+ );
+});
diff --git a/spec/frontend/design_management_new/utils/cache_update_spec.js b/spec/frontend/design_management_new/utils/cache_update_spec.js
new file mode 100644
index 00000000000..611716d5aa7
--- /dev/null
+++ b/spec/frontend/design_management_new/utils/cache_update_spec.js
@@ -0,0 +1,44 @@
+import { InMemoryCache } from 'apollo-cache-inmemory';
+import {
+ updateStoreAfterDesignsDelete,
+ updateStoreAfterAddDiscussionComment,
+ updateStoreAfterAddImageDiffNote,
+ updateStoreAfterUploadDesign,
+ updateStoreAfterUpdateImageDiffNote,
+} from '~/design_management_new/utils/cache_update';
+import {
+ designDeletionError,
+ ADD_DISCUSSION_COMMENT_ERROR,
+ ADD_IMAGE_DIFF_NOTE_ERROR,
+ UPDATE_IMAGE_DIFF_NOTE_ERROR,
+} from '~/design_management_new/utils/error_messages';
+import design from '../mock_data/design';
+import createFlash from '~/flash';
+
+jest.mock('~/flash.js');
+
+describe('Design Management cache update', () => {
+ const mockErrors = ['code red!'];
+
+ let mockStore;
+
+ beforeEach(() => {
+ mockStore = new InMemoryCache();
+ });
+
+ describe('error handling', () => {
+ it.each`
+ fnName | subject | errorMessage | extraArgs
+ ${'updateStoreAfterDesignsDelete'} | ${updateStoreAfterDesignsDelete} | ${designDeletionError({ singular: true })} | ${[[design]]}
+ ${'updateStoreAfterAddDiscussionComment'} | ${updateStoreAfterAddDiscussionComment} | ${ADD_DISCUSSION_COMMENT_ERROR} | ${[]}
+ ${'updateStoreAfterAddImageDiffNote'} | ${updateStoreAfterAddImageDiffNote} | ${ADD_IMAGE_DIFF_NOTE_ERROR} | ${[]}
+ ${'updateStoreAfterUploadDesign'} | ${updateStoreAfterUploadDesign} | ${mockErrors[0]} | ${[]}
+ ${'updateStoreAfterUpdateImageDiffNote'} | ${updateStoreAfterUpdateImageDiffNote} | ${UPDATE_IMAGE_DIFF_NOTE_ERROR} | ${[]}
+ `('$fnName handles errors in response', ({ subject, extraArgs, errorMessage }) => {
+ expect(createFlash).not.toHaveBeenCalled();
+ expect(() => subject(mockStore, { errors: mockErrors }, {}, ...extraArgs)).toThrow();
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith(errorMessage);
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/utils/design_management_utils_spec.js b/spec/frontend/design_management_new/utils/design_management_utils_spec.js
new file mode 100644
index 00000000000..8bc33e214be
--- /dev/null
+++ b/spec/frontend/design_management_new/utils/design_management_utils_spec.js
@@ -0,0 +1,176 @@
+import {
+ extractCurrentDiscussion,
+ extractDiscussions,
+ findVersionId,
+ designUploadOptimisticResponse,
+ updateImageDiffNoteOptimisticResponse,
+ isValidDesignFile,
+ extractDesign,
+} from '~/design_management_new/utils/design_management_utils';
+import mockResponseNoDesigns from '../mock_data/no_designs';
+import mockResponseWithDesigns from '../mock_data/designs';
+import mockDesign from '../mock_data/design';
+
+jest.mock('lodash/uniqueId', () => () => 1);
+
+describe('extractCurrentDiscussion', () => {
+ let discussions;
+
+ beforeEach(() => {
+ discussions = {
+ nodes: [
+ { id: 101, payload: 'w' },
+ { id: 102, payload: 'x' },
+ { id: 103, payload: 'y' },
+ { id: 104, payload: 'z' },
+ ],
+ };
+ });
+
+ it('finds the relevant discussion if it exists', () => {
+ const id = 103;
+ expect(extractCurrentDiscussion(discussions, id)).toEqual({ id, payload: 'y' });
+ });
+
+ it('returns null if the relevant discussion does not exist', () => {
+ expect(extractCurrentDiscussion(discussions, 0)).not.toBeDefined();
+ });
+});
+
+describe('extractDiscussions', () => {
+ let discussions;
+
+ beforeEach(() => {
+ discussions = {
+ nodes: [
+ { id: 1, notes: { nodes: ['a'] } },
+ { id: 2, notes: { nodes: ['b'] } },
+ { id: 3, notes: { nodes: ['c'] } },
+ { id: 4, notes: { nodes: ['d'] } },
+ ],
+ };
+ });
+
+ it('discards the edges.node artifacts of GraphQL', () => {
+ expect(extractDiscussions(discussions)).toEqual([
+ { id: 1, notes: ['a'], index: 1 },
+ { id: 2, notes: ['b'], index: 2 },
+ { id: 3, notes: ['c'], index: 3 },
+ { id: 4, notes: ['d'], index: 4 },
+ ]);
+ });
+});
+
+describe('version parser', () => {
+ it('correctly extracts version ID from a valid version string', () => {
+ const testVersionId = '123';
+ const testVersionString = `gid://gitlab/DesignManagement::Version/${testVersionId}`;
+
+ expect(findVersionId(testVersionString)).toEqual(testVersionId);
+ });
+
+ it('fails to extract version ID from an invalid version string', () => {
+ const testInvalidVersionString = `gid://gitlab/DesignManagement::Version`;
+
+ expect(findVersionId(testInvalidVersionString)).toBeUndefined();
+ });
+});
+
+describe('optimistic responses', () => {
+ it('correctly generated for designManagementUpload', () => {
+ const expectedResponse = {
+ __typename: 'Mutation',
+ designManagementUpload: {
+ __typename: 'DesignManagementUploadPayload',
+ designs: [
+ {
+ __typename: 'Design',
+ id: -1,
+ image: '',
+ imageV432x230: '',
+ filename: 'test',
+ fullPath: '',
+ notesCount: 0,
+ event: 'NONE',
+ diffRefs: { __typename: 'DiffRefs', baseSha: '', startSha: '', headSha: '' },
+ discussions: { __typename: 'DesignDiscussion', nodes: [] },
+ versions: {
+ __typename: 'DesignVersionConnection',
+ edges: {
+ __typename: 'DesignVersionEdge',
+ node: { __typename: 'DesignVersion', id: -1, sha: -1 },
+ },
+ },
+ },
+ ],
+ errors: [],
+ skippedDesigns: [],
+ },
+ };
+ expect(designUploadOptimisticResponse([{ name: 'test' }])).toEqual(expectedResponse);
+ });
+
+ it('correctly generated for updateImageDiffNoteOptimisticResponse', () => {
+ const mockNote = {
+ id: 'test-note-id',
+ };
+
+ const mockPosition = {
+ x: 10,
+ y: 10,
+ width: 10,
+ height: 10,
+ };
+
+ const expectedResponse = {
+ __typename: 'Mutation',
+ updateImageDiffNote: {
+ __typename: 'UpdateImageDiffNotePayload',
+ note: {
+ ...mockNote,
+ position: mockPosition,
+ },
+ errors: [],
+ },
+ };
+ expect(updateImageDiffNoteOptimisticResponse(mockNote, { position: mockPosition })).toEqual(
+ expectedResponse,
+ );
+ });
+});
+
+describe('isValidDesignFile', () => {
+ // test every filetype that Design Management supports
+ // https://docs.gitlab.com/ee/user/project/issues/design_management.html#limitations
+ it.each`
+ mimetype | isValid
+ ${'image/svg'} | ${true}
+ ${'image/png'} | ${true}
+ ${'image/jpg'} | ${true}
+ ${'image/jpeg'} | ${true}
+ ${'image/gif'} | ${true}
+ ${'image/bmp'} | ${true}
+ ${'image/tiff'} | ${true}
+ ${'image/ico'} | ${true}
+ ${'image/svg'} | ${true}
+ ${'video/mpeg'} | ${false}
+ ${'audio/midi'} | ${false}
+ ${'application/octet-stream'} | ${false}
+ `('returns $isValid for file type $mimetype', ({ mimetype, isValid }) => {
+ expect(isValidDesignFile({ type: mimetype })).toBe(isValid);
+ });
+});
+
+describe('extractDesign', () => {
+ describe('with no designs', () => {
+ it('returns undefined', () => {
+ expect(extractDesign(mockResponseNoDesigns)).toBeUndefined();
+ });
+ });
+
+ describe('with designs', () => {
+ it('returns the first design available', () => {
+ expect(extractDesign(mockResponseWithDesigns)).toEqual(mockDesign);
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/utils/error_messages_spec.js b/spec/frontend/design_management_new/utils/error_messages_spec.js
new file mode 100644
index 00000000000..eb5dc0fad20
--- /dev/null
+++ b/spec/frontend/design_management_new/utils/error_messages_spec.js
@@ -0,0 +1,62 @@
+import {
+ designDeletionError,
+ designUploadSkippedWarning,
+} from '~/design_management_new/utils/error_messages';
+
+const mockFilenames = n =>
+ Array(n)
+ .fill(0)
+ .map((_, i) => ({ filename: `${i + 1}.jpg` }));
+
+describe('Error message', () => {
+ describe('designDeletionError', () => {
+ const singularMsg = 'Could not delete a design. Please try again.';
+ const pluralMsg = 'Could not delete designs. Please try again.';
+
+ describe('when [singular=true]', () => {
+ it.each([[undefined], [true]])('uses singular grammar', singularOption => {
+ expect(designDeletionError({ singular: singularOption })).toEqual(singularMsg);
+ });
+ });
+
+ describe('when [singular=false]', () => {
+ it('uses plural grammar', () => {
+ expect(designDeletionError({ singular: false })).toEqual(pluralMsg);
+ });
+ });
+ });
+
+ describe.each([
+ [[], [], null],
+ [mockFilenames(1), mockFilenames(1), 'Upload skipped. 1.jpg did not change.'],
+ [
+ mockFilenames(2),
+ mockFilenames(2),
+ 'Upload skipped. The designs you tried uploading did not change.',
+ ],
+ [
+ mockFilenames(2),
+ mockFilenames(1),
+ 'Upload skipped. Some of the designs you tried uploading did not change: 1.jpg.',
+ ],
+ [
+ mockFilenames(6),
+ mockFilenames(5),
+ 'Upload skipped. Some of the designs you tried uploading did not change: 1.jpg, 2.jpg, 3.jpg, 4.jpg, 5.jpg.',
+ ],
+ [
+ mockFilenames(7),
+ mockFilenames(6),
+ 'Upload skipped. Some of the designs you tried uploading did not change: 1.jpg, 2.jpg, 3.jpg, 4.jpg, 5.jpg, and 1 more.',
+ ],
+ [
+ mockFilenames(8),
+ mockFilenames(7),
+ 'Upload skipped. Some of the designs you tried uploading did not change: 1.jpg, 2.jpg, 3.jpg, 4.jpg, 5.jpg, and 2 more.',
+ ],
+ ])('designUploadSkippedWarning', (uploadedFiles, skippedFiles, expected) => {
+ test('returns expected warning message', () => {
+ expect(designUploadSkippedWarning(uploadedFiles, skippedFiles)).toBe(expected);
+ });
+ });
+});
diff --git a/spec/frontend/design_management_new/utils/tracking_spec.js b/spec/frontend/design_management_new/utils/tracking_spec.js
new file mode 100644
index 00000000000..073cc0df255
--- /dev/null
+++ b/spec/frontend/design_management_new/utils/tracking_spec.js
@@ -0,0 +1,53 @@
+import { mockTracking } from 'helpers/tracking_helper';
+import { trackDesignDetailView } from '~/design_management_new/utils/tracking';
+
+function getTrackingSpy(key) {
+ return mockTracking(key, undefined, jest.spyOn);
+}
+
+describe('Tracking Events', () => {
+ describe('trackDesignDetailView', () => {
+ const eventKey = 'projects:issues:design';
+ const eventName = 'design_viewed';
+
+ it('trackDesignDetailView fires a tracking event when called', () => {
+ const trackingSpy = getTrackingSpy(eventKey);
+
+ trackDesignDetailView();
+
+ expect(trackingSpy).toHaveBeenCalledWith(
+ eventKey,
+ eventName,
+ expect.objectContaining({
+ label: eventName,
+ value: {
+ 'internal-object-refrerer': '',
+ 'design-collection-owner': '',
+ 'design-version-number': 1,
+ 'design-is-current-version': false,
+ },
+ }),
+ );
+ });
+
+ it('trackDesignDetailView allows to customize the value payload', () => {
+ const trackingSpy = getTrackingSpy(eventKey);
+
+ trackDesignDetailView('from-a-test', 'test', 100, true);
+
+ expect(trackingSpy).toHaveBeenCalledWith(
+ eventKey,
+ eventName,
+ expect.objectContaining({
+ label: eventName,
+ value: {
+ 'internal-object-refrerer': 'from-a-test',
+ 'design-collection-owner': 'test',
+ 'design-version-number': 100,
+ 'design-is-current-version': true,
+ },
+ }),
+ );
+ });
+ });
+});
diff --git a/spec/graphql/mutations/issues/update_spec.rb b/spec/graphql/mutations/issues/update_spec.rb
index 8c3d01918fd..9a847476e2e 100644
--- a/spec/graphql/mutations/issues/update_spec.rb
+++ b/spec/graphql/mutations/issues/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::Issues::Update do
+RSpec.describe Mutations::Issues::Update do
let(:issue) { create(:issue) }
let(:user) { create(:user) }
let(:expected_attributes) do
diff --git a/spec/graphql/mutations/merge_requests/create_spec.rb b/spec/graphql/mutations/merge_requests/create_spec.rb
index 88acd3ed5b6..ae31790f1f9 100644
--- a/spec/graphql/mutations/merge_requests/create_spec.rb
+++ b/spec/graphql/mutations/merge_requests/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::MergeRequests::Create do
+RSpec.describe Mutations::MergeRequests::Create do
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
let_it_be(:project) { create(:project, :public, :repository) }
diff --git a/spec/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/graphql/mutations/merge_requests/set_assignees_spec.rb
index d88c5db05c9..0e7abb849c4 100644
--- a/spec/graphql/mutations/merge_requests/set_assignees_spec.rb
+++ b/spec/graphql/mutations/merge_requests/set_assignees_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::MergeRequests::SetAssignees do
+RSpec.describe Mutations::MergeRequests::SetAssignees do
let(:merge_request) { create(:merge_request) }
let(:user) { create(:user) }
diff --git a/spec/graphql/mutations/merge_requests/set_labels_spec.rb b/spec/graphql/mutations/merge_requests/set_labels_spec.rb
index 0fd2c20a5c8..62a7f650f84 100644
--- a/spec/graphql/mutations/merge_requests/set_labels_spec.rb
+++ b/spec/graphql/mutations/merge_requests/set_labels_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::MergeRequests::SetLabels do
+RSpec.describe Mutations::MergeRequests::SetLabels do
let(:merge_request) { create(:merge_request) }
let(:user) { create(:user) }
diff --git a/spec/graphql/mutations/merge_requests/set_locked_spec.rb b/spec/graphql/mutations/merge_requests/set_locked_spec.rb
index d5219c781fd..aca7df5445f 100644
--- a/spec/graphql/mutations/merge_requests/set_locked_spec.rb
+++ b/spec/graphql/mutations/merge_requests/set_locked_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::MergeRequests::SetLocked do
+RSpec.describe Mutations::MergeRequests::SetLocked do
let(:merge_request) { create(:merge_request) }
let(:user) { create(:user) }
diff --git a/spec/graphql/mutations/merge_requests/set_milestone_spec.rb b/spec/graphql/mutations/merge_requests/set_milestone_spec.rb
index d77ec4de4d0..1c0d655ee83 100644
--- a/spec/graphql/mutations/merge_requests/set_milestone_spec.rb
+++ b/spec/graphql/mutations/merge_requests/set_milestone_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::MergeRequests::SetMilestone do
+RSpec.describe Mutations::MergeRequests::SetMilestone do
let(:merge_request) { create(:merge_request) }
let(:user) { create(:user) }
diff --git a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
index cf569a74aa9..20cfed9dd3d 100644
--- a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
+++ b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::MergeRequests::SetSubscription do
+RSpec.describe Mutations::MergeRequests::SetSubscription do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:user) { create(:user) }
diff --git a/spec/graphql/mutations/merge_requests/set_wip_spec.rb b/spec/graphql/mutations/merge_requests/set_wip_spec.rb
index 7255d0fe7d7..b6cb49724fa 100644
--- a/spec/graphql/mutations/merge_requests/set_wip_spec.rb
+++ b/spec/graphql/mutations/merge_requests/set_wip_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::MergeRequests::SetWip do
+RSpec.describe Mutations::MergeRequests::SetWip do
let(:merge_request) { create(:merge_request) }
let(:user) { create(:user) }
diff --git a/spec/graphql/mutations/todos/mark_all_done_spec.rb b/spec/graphql/mutations/todos/mark_all_done_spec.rb
index 4af00307969..ed2291c0c35 100644
--- a/spec/graphql/mutations/todos/mark_all_done_spec.rb
+++ b/spec/graphql/mutations/todos/mark_all_done_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::Todos::MarkAllDone do
+RSpec.describe Mutations::Todos::MarkAllDone do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/graphql/mutations/todos/mark_done_spec.rb b/spec/graphql/mutations/todos/mark_done_spec.rb
index 44065f83f74..51ad3e1a5d7 100644
--- a/spec/graphql/mutations/todos/mark_done_spec.rb
+++ b/spec/graphql/mutations/todos/mark_done_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::Todos::MarkDone do
+RSpec.describe Mutations::Todos::MarkDone do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/graphql/mutations/todos/restore_many_spec.rb b/spec/graphql/mutations/todos/restore_many_spec.rb
index 8f4a8985f9e..7f9f478085d 100644
--- a/spec/graphql/mutations/todos/restore_many_spec.rb
+++ b/spec/graphql/mutations/todos/restore_many_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::Todos::RestoreMany do
+RSpec.describe Mutations::Todos::RestoreMany do
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
diff --git a/spec/graphql/mutations/todos/restore_spec.rb b/spec/graphql/mutations/todos/restore_spec.rb
index 949ab6a164b..9043d7a44a8 100644
--- a/spec/graphql/mutations/todos/restore_spec.rb
+++ b/spec/graphql/mutations/todos/restore_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Mutations::Todos::Restore do
+RSpec.describe Mutations::Todos::Restore do
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
diff --git a/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb b/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
index 6c12f765e69..0c1ba5aab2c 100644
--- a/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
+++ b/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::AlertManagement::AlertResolver do
+RSpec.describe Resolvers::AlertManagement::AlertResolver do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/graphql/resolvers/alert_management/alert_status_counts_resolver_spec.rb b/spec/graphql/resolvers/alert_management/alert_status_counts_resolver_spec.rb
index 8eb28c8c945..b72e692f2e8 100644
--- a/spec/graphql/resolvers/alert_management/alert_status_counts_resolver_spec.rb
+++ b/spec/graphql/resolvers/alert_management/alert_status_counts_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::AlertManagement::AlertStatusCountsResolver do
+RSpec.describe Resolvers::AlertManagement::AlertStatusCountsResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/base_resolver_spec.rb b/spec/graphql/resolvers/base_resolver_spec.rb
index 6c384349577..40dc2370052 100644
--- a/spec/graphql/resolvers/base_resolver_spec.rb
+++ b/spec/graphql/resolvers/base_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::BaseResolver do
+RSpec.describe Resolvers::BaseResolver do
include GraphqlHelpers
let(:resolver) do
diff --git a/spec/graphql/resolvers/board_lists_resolver_spec.rb b/spec/graphql/resolvers/board_lists_resolver_spec.rb
index 5f6c440a8ed..f662e9a0f62 100644
--- a/spec/graphql/resolvers/board_lists_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_lists_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::BoardListsResolver do
+RSpec.describe Resolvers::BoardListsResolver do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/graphql/resolvers/boards_resolver_spec.rb b/spec/graphql/resolvers/boards_resolver_spec.rb
index 02d6f808118..f121e8a4083 100644
--- a/spec/graphql/resolvers/boards_resolver_spec.rb
+++ b/spec/graphql/resolvers/boards_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::BoardsResolver do
+RSpec.describe Resolvers::BoardsResolver do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/graphql/resolvers/branch_commit_resolver_spec.rb b/spec/graphql/resolvers/branch_commit_resolver_spec.rb
index 22e1de8f375..78d4959c3f9 100644
--- a/spec/graphql/resolvers/branch_commit_resolver_spec.rb
+++ b/spec/graphql/resolvers/branch_commit_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::BranchCommitResolver do
+RSpec.describe Resolvers::BranchCommitResolver do
include GraphqlHelpers
subject(:commit) { resolve(described_class, obj: branch) }
diff --git a/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb b/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb
index 93da877d714..20a0cb842a4 100644
--- a/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb
+++ b/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::CommitPipelinesResolver do
+RSpec.describe Resolvers::CommitPipelinesResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb b/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb
index 03ff1e11d85..3dffda75e08 100644
--- a/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb
+++ b/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ResolvesPipelines do
+RSpec.describe ResolvesPipelines do
include GraphqlHelpers
subject(:resolver) do
diff --git a/spec/graphql/resolvers/concerns/resolves_project_spec.rb b/spec/graphql/resolvers/concerns/resolves_project_spec.rb
index f29f54483d6..1748d8a81a3 100644
--- a/spec/graphql/resolvers/concerns/resolves_project_spec.rb
+++ b/spec/graphql/resolvers/concerns/resolves_project_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ResolvesProject do
+RSpec.describe ResolvesProject do
include GraphqlHelpers
let(:implementing_class) do
diff --git a/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb
index a5054ae3ebf..4bdef49499c 100644
--- a/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::DesignManagement::DesignAtVersionResolver do
+RSpec.describe Resolvers::DesignManagement::DesignAtVersionResolver do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/graphql/resolvers/design_management/design_resolver_spec.rb b/spec/graphql/resolvers/design_management/design_resolver_spec.rb
index 857acc3d371..02d7f94612c 100644
--- a/spec/graphql/resolvers/design_management/design_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/design_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::DesignManagement::DesignResolver do
+RSpec.describe Resolvers::DesignManagement::DesignResolver do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/graphql/resolvers/design_management/designs_resolver_spec.rb b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb
index 28fc9e2151d..cfa37d34fd9 100644
--- a/spec/graphql/resolvers/design_management/designs_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::DesignManagement::DesignsResolver do
+RSpec.describe Resolvers::DesignManagement::DesignsResolver do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb
index cc9c0436885..850b9f8cc87 100644
--- a/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::DesignManagement::Version::DesignAtVersionResolver do
+RSpec.describe Resolvers::DesignManagement::Version::DesignAtVersionResolver do
include GraphqlHelpers
include_context 'four designs in three versions'
diff --git a/spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb
index 123b26862d0..c038216ce0b 100644
--- a/spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::DesignManagement::Version::DesignsAtVersionResolver do
+RSpec.describe Resolvers::DesignManagement::Version::DesignsAtVersionResolver do
include GraphqlHelpers
include_context 'four designs in three versions'
diff --git a/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb b/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb
index ef50598d241..8ad928e9854 100644
--- a/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::DesignManagement::VersionInCollectionResolver do
+RSpec.describe Resolvers::DesignManagement::VersionInCollectionResolver do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/graphql/resolvers/design_management/version_resolver_spec.rb b/spec/graphql/resolvers/design_management/version_resolver_spec.rb
index e7c09351204..af1e6a73d09 100644
--- a/spec/graphql/resolvers/design_management/version_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/version_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::DesignManagement::VersionResolver do
+RSpec.describe Resolvers::DesignManagement::VersionResolver do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/graphql/resolvers/design_management/versions_resolver_spec.rb b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
index d5bab025e45..5bc1c555e9a 100644
--- a/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::DesignManagement::VersionsResolver do
+RSpec.describe Resolvers::DesignManagement::VersionsResolver do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/graphql/resolvers/echo_resolver_spec.rb b/spec/graphql/resolvers/echo_resolver_spec.rb
index 466501a4227..2182ac221f6 100644
--- a/spec/graphql/resolvers/echo_resolver_spec.rb
+++ b/spec/graphql/resolvers/echo_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::EchoResolver do
+RSpec.describe Resolvers::EchoResolver do
include GraphqlHelpers
let(:current_user) { create(:user) }
diff --git a/spec/graphql/resolvers/environments_resolver_spec.rb b/spec/graphql/resolvers/environments_resolver_spec.rb
index 75fd7aff39c..6c999e5d0e7 100644
--- a/spec/graphql/resolvers/environments_resolver_spec.rb
+++ b/spec/graphql/resolvers/environments_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::EnvironmentsResolver do
+RSpec.describe Resolvers::EnvironmentsResolver do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb b/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb
index 8b2e33cdfda..7e531910184 100644
--- a/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb
+++ b/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do
+RSpec.describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb b/spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb
index 3bb8a5c389d..02e0420be2a 100644
--- a/spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb
+++ b/spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::ErrorTracking::SentryErrorCollectionResolver do
+RSpec.describe Resolvers::ErrorTracking::SentryErrorCollectionResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb b/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb
index 93f89d077d7..554873a6e21 100644
--- a/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb
+++ b/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::ErrorTracking::SentryErrorsResolver do
+RSpec.describe Resolvers::ErrorTracking::SentryErrorsResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/graphql/resolvers/group_resolver_spec.rb b/spec/graphql/resolvers/group_resolver_spec.rb
index 70b1102d363..a03e7854177 100644
--- a/spec/graphql/resolvers/group_resolver_spec.rb
+++ b/spec/graphql/resolvers/group_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::GroupResolver do
+RSpec.describe Resolvers::GroupResolver do
include GraphqlHelpers
let_it_be(:group1) { create(:group) }
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index b7cc9bc6d71..c01840b94d5 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::IssuesResolver do
+RSpec.describe Resolvers::IssuesResolver do
include GraphqlHelpers
let(:current_user) { create(:user) }
diff --git a/spec/graphql/resolvers/last_commit_resolver_spec.rb b/spec/graphql/resolvers/last_commit_resolver_spec.rb
index 15b09b77a10..c891445c1ff 100644
--- a/spec/graphql/resolvers/last_commit_resolver_spec.rb
+++ b/spec/graphql/resolvers/last_commit_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::LastCommitResolver do
+RSpec.describe Resolvers::LastCommitResolver do
include GraphqlHelpers
let(:repository) { create(:project, :repository).repository }
diff --git a/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb b/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb
index b894dce3e17..2fe3e86ec14 100644
--- a/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::MergeRequestPipelinesResolver do
+RSpec.describe Resolvers::MergeRequestPipelinesResolver do
include GraphqlHelpers
let_it_be(:merge_request) { create(:merge_request) }
diff --git a/spec/graphql/resolvers/merge_requests_resolver_spec.rb b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
index 6ff7e1ecac6..ddf19acd8aa 100644
--- a/spec/graphql/resolvers/merge_requests_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::MergeRequestsResolver do
+RSpec.describe Resolvers::MergeRequestsResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/graphql/resolvers/metadata_resolver_spec.rb b/spec/graphql/resolvers/metadata_resolver_spec.rb
index afff9eabb97..20556941de4 100644
--- a/spec/graphql/resolvers/metadata_resolver_spec.rb
+++ b/spec/graphql/resolvers/metadata_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::MetadataResolver do
+RSpec.describe Resolvers::MetadataResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/metrics/dashboard_resolver_spec.rb b/spec/graphql/resolvers/metrics/dashboard_resolver_spec.rb
index 6a8eb8a65af..4112e3d4fe6 100644
--- a/spec/graphql/resolvers/metrics/dashboard_resolver_spec.rb
+++ b/spec/graphql/resolvers/metrics/dashboard_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::Metrics::DashboardResolver do
+RSpec.describe Resolvers::Metrics::DashboardResolver do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb b/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb
index c06fbef53b6..f90869c52bc 100644
--- a/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb
+++ b/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::Metrics::Dashboards::AnnotationResolver do
+RSpec.describe Resolvers::Metrics::Dashboards::AnnotationResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/milestone_resolver_spec.rb b/spec/graphql/resolvers/milestone_resolver_spec.rb
index 8e2c67fdc03..36dd5ef03e2 100644
--- a/spec/graphql/resolvers/milestone_resolver_spec.rb
+++ b/spec/graphql/resolvers/milestone_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::MilestoneResolver do
+RSpec.describe Resolvers::MilestoneResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/namespace_projects_resolver_spec.rb b/spec/graphql/resolvers/namespace_projects_resolver_spec.rb
index 639cc69650b..699269b47e0 100644
--- a/spec/graphql/resolvers/namespace_projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/namespace_projects_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::NamespaceProjectsResolver do
+RSpec.describe Resolvers::NamespaceProjectsResolver do
include GraphqlHelpers
let(:current_user) { create(:user) }
diff --git a/spec/graphql/resolvers/project_pipelines_resolver_spec.rb b/spec/graphql/resolvers/project_pipelines_resolver_spec.rb
index 2a14796fdfa..b2e8fed2441 100644
--- a/spec/graphql/resolvers/project_pipelines_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_pipelines_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::ProjectPipelinesResolver do
+RSpec.describe Resolvers::ProjectPipelinesResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/graphql/resolvers/project_resolver_spec.rb b/spec/graphql/resolvers/project_resolver_spec.rb
index e9e38353156..72a01b1c574 100644
--- a/spec/graphql/resolvers/project_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::ProjectResolver do
+RSpec.describe Resolvers::ProjectResolver do
include GraphqlHelpers
let_it_be(:project1) { create(:project) }
diff --git a/spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb b/spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb
index 416a90a841f..854e763fbdd 100644
--- a/spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::Projects::GrafanaIntegrationResolver do
+RSpec.describe Resolvers::Projects::GrafanaIntegrationResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb
index 9811075a613..0775c1c31d1 100644
--- a/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::Projects::JiraImportsResolver do
+RSpec.describe Resolvers::Projects::JiraImportsResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
index 156e10e4270..4038bcb3e5d 100644
--- a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::Projects::JiraProjectsResolver do
+RSpec.describe Resolvers::Projects::JiraProjectsResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/projects/services_resolver_spec.rb b/spec/graphql/resolvers/projects/services_resolver_spec.rb
index 00045442ea0..8b6eff9e8b6 100644
--- a/spec/graphql/resolvers/projects/services_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/services_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::Projects::ServicesResolver do
+RSpec.describe Resolvers::Projects::ServicesResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/projects/snippets_resolver_spec.rb b/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
index 6d301b1c742..b4a5eb8ddb0 100644
--- a/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::Projects::SnippetsResolver do
+RSpec.describe Resolvers::Projects::SnippetsResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/projects_resolver_spec.rb b/spec/graphql/resolvers/projects_resolver_spec.rb
index 73ff99a2520..db7c9225c84 100644
--- a/spec/graphql/resolvers/projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::ProjectsResolver do
+RSpec.describe Resolvers::ProjectsResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/release_resolver_spec.rb b/spec/graphql/resolvers/release_resolver_spec.rb
index 71aa4bbb439..666d54fbc3c 100644
--- a/spec/graphql/resolvers/release_resolver_spec.rb
+++ b/spec/graphql/resolvers/release_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::ReleaseResolver do
+RSpec.describe Resolvers::ReleaseResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private) }
diff --git a/spec/graphql/resolvers/releases_resolver_spec.rb b/spec/graphql/resolvers/releases_resolver_spec.rb
index 9de539b417a..ee8b33fc748 100644
--- a/spec/graphql/resolvers/releases_resolver_spec.rb
+++ b/spec/graphql/resolvers/releases_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::ReleasesResolver do
+RSpec.describe Resolvers::ReleasesResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private) }
diff --git a/spec/graphql/resolvers/snippets_resolver_spec.rb b/spec/graphql/resolvers/snippets_resolver_spec.rb
index 89c350020f0..180be8e8624 100644
--- a/spec/graphql/resolvers/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/snippets_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::SnippetsResolver do
+RSpec.describe Resolvers::SnippetsResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/todo_resolver_spec.rb b/spec/graphql/resolvers/todo_resolver_spec.rb
index 5a09ec40e64..f4b98e61003 100644
--- a/spec/graphql/resolvers/todo_resolver_spec.rb
+++ b/spec/graphql/resolvers/todo_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::TodoResolver do
+RSpec.describe Resolvers::TodoResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/tree_resolver_spec.rb b/spec/graphql/resolvers/tree_resolver_spec.rb
index 0ea4e6eeaad..7818c25fe47 100644
--- a/spec/graphql/resolvers/tree_resolver_spec.rb
+++ b/spec/graphql/resolvers/tree_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::TreeResolver do
+RSpec.describe Resolvers::TreeResolver do
include GraphqlHelpers
let(:repository) { create(:project, :repository).repository }
diff --git a/spec/graphql/resolvers/user_resolver_spec.rb b/spec/graphql/resolvers/user_resolver_spec.rb
index 45a8816bf26..3ee9f63d832 100644
--- a/spec/graphql/resolvers/user_resolver_spec.rb
+++ b/spec/graphql/resolvers/user_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::UserResolver do
+RSpec.describe Resolvers::UserResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/resolvers/users/snippets_resolver_spec.rb b/spec/graphql/resolvers/users/snippets_resolver_spec.rb
index 6412d77e02b..497b6b11b46 100644
--- a/spec/graphql/resolvers/users/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/users/snippets_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Resolvers::Users::SnippetsResolver do
+RSpec.describe Resolvers::Users::SnippetsResolver do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/types/alert_management/alert_status_count_type_spec.rb b/spec/graphql/types/alert_management/alert_status_count_type_spec.rb
index 1c56028425e..6372d5dd915 100644
--- a/spec/graphql/types/alert_management/alert_status_count_type_spec.rb
+++ b/spec/graphql/types/alert_management/alert_status_count_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['AlertManagementAlertStatusCountsType'] do
+RSpec.describe GitlabSchema.types['AlertManagementAlertStatusCountsType'] do
specify { expect(described_class.graphql_name).to eq('AlertManagementAlertStatusCountsType') }
it 'exposes the expected fields' do
diff --git a/spec/graphql/types/alert_management/alert_type_spec.rb b/spec/graphql/types/alert_management/alert_type_spec.rb
index 5acbf8ebb7a..1ccce1f2319 100644
--- a/spec/graphql/types/alert_management/alert_type_spec.rb
+++ b/spec/graphql/types/alert_management/alert_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['AlertManagementAlert'] do
+RSpec.describe GitlabSchema.types['AlertManagementAlert'] do
specify { expect(described_class.graphql_name).to eq('AlertManagementAlert') }
specify { expect(described_class).to require_graphql_authorizations(:read_alert_management_alert) }
diff --git a/spec/graphql/types/alert_management/severity_enum_spec.rb b/spec/graphql/types/alert_management/severity_enum_spec.rb
index ca5aa826fe5..6c3c962b71d 100644
--- a/spec/graphql/types/alert_management/severity_enum_spec.rb
+++ b/spec/graphql/types/alert_management/severity_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['AlertManagementSeverity'] do
+RSpec.describe GitlabSchema.types['AlertManagementSeverity'] do
specify { expect(described_class.graphql_name).to eq('AlertManagementSeverity') }
it 'exposes all the severity values' do
diff --git a/spec/graphql/types/alert_management/status_enum_spec.rb b/spec/graphql/types/alert_management/status_enum_spec.rb
index 240d8863c97..ac7a8eb53f6 100644
--- a/spec/graphql/types/alert_management/status_enum_spec.rb
+++ b/spec/graphql/types/alert_management/status_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['AlertManagementStatus'] do
+RSpec.describe GitlabSchema.types['AlertManagementStatus'] do
specify { expect(described_class.graphql_name).to eq('AlertManagementStatus') }
describe 'statuses' do
diff --git a/spec/graphql/types/award_emojis/award_emoji_type_spec.rb b/spec/graphql/types/award_emojis/award_emoji_type_spec.rb
index 4e06329506d..3c43c5f8e42 100644
--- a/spec/graphql/types/award_emojis/award_emoji_type_spec.rb
+++ b/spec/graphql/types/award_emojis/award_emoji_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['AwardEmoji'] do
+RSpec.describe GitlabSchema.types['AwardEmoji'] do
specify { expect(described_class.graphql_name).to eq('AwardEmoji') }
specify { expect(described_class).to require_graphql_authorizations(:read_emoji) }
diff --git a/spec/graphql/types/base_enum_spec.rb b/spec/graphql/types/base_enum_spec.rb
index 3eadb492cf5..0d0f6346f2d 100644
--- a/spec/graphql/types/base_enum_spec.rb
+++ b/spec/graphql/types/base_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::BaseEnum do
+RSpec.describe Types::BaseEnum do
describe '#enum' do
let(:enum) do
Class.new(described_class) do
diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb
index 3ec33c75803..73bb54e7ad0 100644
--- a/spec/graphql/types/base_field_spec.rb
+++ b/spec/graphql/types/base_field_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::BaseField do
+RSpec.describe Types::BaseField do
context 'when considering complexity' do
let(:resolver) do
Class.new(described_class) do
diff --git a/spec/graphql/types/blob_viewers/type_enum_spec.rb b/spec/graphql/types/blob_viewers/type_enum_spec.rb
index 09664382af9..57f052a4fd8 100644
--- a/spec/graphql/types/blob_viewers/type_enum_spec.rb
+++ b/spec/graphql/types/blob_viewers/type_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::BlobViewers::TypeEnum do
+RSpec.describe Types::BlobViewers::TypeEnum do
specify { expect(described_class.graphql_name).to eq('BlobViewersType') }
it 'exposes all tree entry types' do
diff --git a/spec/graphql/types/board_list_type_spec.rb b/spec/graphql/types/board_list_type_spec.rb
index 69597fc9617..046d1e92bfa 100644
--- a/spec/graphql/types/board_list_type_spec.rb
+++ b/spec/graphql/types/board_list_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['BoardList'] do
+RSpec.describe GitlabSchema.types['BoardList'] do
specify { expect(described_class.graphql_name).to eq('BoardList') }
it 'has specific fields' do
diff --git a/spec/graphql/types/board_type_spec.rb b/spec/graphql/types/board_type_spec.rb
index 5d87a1757b5..b02b342390d 100644
--- a/spec/graphql/types/board_type_spec.rb
+++ b/spec/graphql/types/board_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Board'] do
+RSpec.describe GitlabSchema.types['Board'] do
specify { expect(described_class.graphql_name).to eq('Board') }
specify { expect(described_class).to require_graphql_authorizations(:read_board) }
diff --git a/spec/graphql/types/branch_type_spec.rb b/spec/graphql/types/branch_type_spec.rb
index f58b514116d..a5838739a80 100644
--- a/spec/graphql/types/branch_type_spec.rb
+++ b/spec/graphql/types/branch_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Branch'] do
+RSpec.describe GitlabSchema.types['Branch'] do
it { expect(described_class.graphql_name).to eq('Branch') }
it { expect(described_class).to have_graphql_fields(:name, :commit) }
diff --git a/spec/graphql/types/ci/detailed_status_type_spec.rb b/spec/graphql/types/ci/detailed_status_type_spec.rb
index c62c8f23728..67199848df0 100644
--- a/spec/graphql/types/ci/detailed_status_type_spec.rb
+++ b/spec/graphql/types/ci/detailed_status_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::Ci::DetailedStatusType do
+RSpec.describe Types::Ci::DetailedStatusType do
specify { expect(described_class.graphql_name).to eq('DetailedStatus') }
it "has all fields" do
diff --git a/spec/graphql/types/ci/pipeline_type_spec.rb b/spec/graphql/types/ci/pipeline_type_spec.rb
index d56cff12105..f13f1c9afb2 100644
--- a/spec/graphql/types/ci/pipeline_type_spec.rb
+++ b/spec/graphql/types/ci/pipeline_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::Ci::PipelineType do
+RSpec.describe Types::Ci::PipelineType do
specify { expect(described_class.graphql_name).to eq('Pipeline') }
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Ci::Pipeline) }
diff --git a/spec/graphql/types/commit_action_mode_enum_spec.rb b/spec/graphql/types/commit_action_mode_enum_spec.rb
index 9e1a27ea254..cedd466e292 100644
--- a/spec/graphql/types/commit_action_mode_enum_spec.rb
+++ b/spec/graphql/types/commit_action_mode_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['CommitActionMode'] do
+RSpec.describe GitlabSchema.types['CommitActionMode'] do
it { expect(described_class.graphql_name).to eq('CommitActionMode') }
it 'exposes all the existing commit actions' do
diff --git a/spec/graphql/types/commit_encoding_enum_spec.rb b/spec/graphql/types/commit_encoding_enum_spec.rb
index 30686a0c712..7acfb73c06d 100644
--- a/spec/graphql/types/commit_encoding_enum_spec.rb
+++ b/spec/graphql/types/commit_encoding_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['CommitEncoding'] do
+RSpec.describe GitlabSchema.types['CommitEncoding'] do
it { expect(described_class.graphql_name).to eq('CommitEncoding') }
it 'exposes all the existing encoding option' do
diff --git a/spec/graphql/types/commit_type_spec.rb b/spec/graphql/types/commit_type_spec.rb
index 88b450e3924..75984786972 100644
--- a/spec/graphql/types/commit_type_spec.rb
+++ b/spec/graphql/types/commit_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Commit'] do
+RSpec.describe GitlabSchema.types['Commit'] do
specify { expect(described_class.graphql_name).to eq('Commit') }
specify { expect(described_class).to require_graphql_authorizations(:download_code) }
diff --git a/spec/graphql/types/container_expiration_policy_cadence_enum_spec.rb b/spec/graphql/types/container_expiration_policy_cadence_enum_spec.rb
index 08c777cd365..9bd1fe3ea76 100644
--- a/spec/graphql/types/container_expiration_policy_cadence_enum_spec.rb
+++ b/spec/graphql/types/container_expiration_policy_cadence_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['ContainerExpirationPolicyCadenceEnum'] do
+RSpec.describe GitlabSchema.types['ContainerExpirationPolicyCadenceEnum'] do
let_it_be(:expected_values) { %w[EVERY_DAY EVERY_WEEK EVERY_TWO_WEEKS EVERY_MONTH EVERY_THREE_MONTHS] }
it_behaves_like 'exposing container expiration policy option', :cadence
diff --git a/spec/graphql/types/container_expiration_policy_keep_enum_spec.rb b/spec/graphql/types/container_expiration_policy_keep_enum_spec.rb
index 1a5b4bdd3bb..35385545fe3 100644
--- a/spec/graphql/types/container_expiration_policy_keep_enum_spec.rb
+++ b/spec/graphql/types/container_expiration_policy_keep_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['ContainerExpirationPolicyKeepEnum'] do
+RSpec.describe GitlabSchema.types['ContainerExpirationPolicyKeepEnum'] do
let_it_be(:expected_values) { %w[ONE_TAG FIVE_TAGS TEN_TAGS TWENTY_FIVE_TAGS FIFTY_TAGS ONE_HUNDRED_TAGS] }
it_behaves_like 'exposing container expiration policy option', :keep_n
diff --git a/spec/graphql/types/container_expiration_policy_older_than_enum_spec.rb b/spec/graphql/types/container_expiration_policy_older_than_enum_spec.rb
index 47f0ca22522..72ab605f2e6 100644
--- a/spec/graphql/types/container_expiration_policy_older_than_enum_spec.rb
+++ b/spec/graphql/types/container_expiration_policy_older_than_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['ContainerExpirationPolicyOlderThanEnum'] do
+RSpec.describe GitlabSchema.types['ContainerExpirationPolicyOlderThanEnum'] do
let_it_be(:expected_values) { %w[SEVEN_DAYS FOURTEEN_DAYS THIRTY_DAYS NINETY_DAYS] }
it_behaves_like 'exposing container expiration policy option', :older_than
diff --git a/spec/graphql/types/container_expiration_policy_type_spec.rb b/spec/graphql/types/container_expiration_policy_type_spec.rb
index 3e0c686eee2..9e9ddaf1cb0 100644
--- a/spec/graphql/types/container_expiration_policy_type_spec.rb
+++ b/spec/graphql/types/container_expiration_policy_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['ContainerExpirationPolicy'] do
+RSpec.describe GitlabSchema.types['ContainerExpirationPolicy'] do
specify { expect(described_class.graphql_name).to eq('ContainerExpirationPolicy') }
specify { expect(described_class.description).to eq('A tag expiration policy designed to keep only the images that matter most') }
diff --git a/spec/graphql/types/design_management/design_at_version_type_spec.rb b/spec/graphql/types/design_management/design_at_version_type_spec.rb
index 1453d73d59c..5a6292c924a 100644
--- a/spec/graphql/types/design_management/design_at_version_type_spec.rb
+++ b/spec/graphql/types/design_management/design_at_version_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['DesignAtVersion'] do
+RSpec.describe GitlabSchema.types['DesignAtVersion'] do
it_behaves_like 'a GraphQL type with design fields' do
let(:extra_design_fields) { %i[version design] }
let_it_be(:design) { create(:design, :with_versions) }
diff --git a/spec/graphql/types/design_management/design_collection_type_spec.rb b/spec/graphql/types/design_management/design_collection_type_spec.rb
index 65150f0971d..6b1d3a87c2d 100644
--- a/spec/graphql/types/design_management/design_collection_type_spec.rb
+++ b/spec/graphql/types/design_management/design_collection_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['DesignCollection'] do
+RSpec.describe GitlabSchema.types['DesignCollection'] do
it { expect(described_class).to require_graphql_authorizations(:read_design) }
it 'has the expected fields' do
diff --git a/spec/graphql/types/design_management/design_type_spec.rb b/spec/graphql/types/design_management/design_type_spec.rb
index 75b4cd66d5e..7a38b397965 100644
--- a/spec/graphql/types/design_management/design_type_spec.rb
+++ b/spec/graphql/types/design_management/design_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Design'] do
+RSpec.describe GitlabSchema.types['Design'] do
it_behaves_like 'a GraphQL type with design fields' do
let(:extra_design_fields) { %i[notes discussions versions] }
let_it_be(:design) { create(:design, :with_versions) }
diff --git a/spec/graphql/types/design_management/design_version_event_enum_spec.rb b/spec/graphql/types/design_management/design_version_event_enum_spec.rb
index a65f1bb5990..06576336231 100644
--- a/spec/graphql/types/design_management/design_version_event_enum_spec.rb
+++ b/spec/graphql/types/design_management/design_version_event_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['DesignVersionEvent'] do
+RSpec.describe GitlabSchema.types['DesignVersionEvent'] do
it { expect(described_class.graphql_name).to eq('DesignVersionEvent') }
it 'exposes the correct event states' do
diff --git a/spec/graphql/types/design_management/version_type_spec.rb b/spec/graphql/types/design_management/version_type_spec.rb
index 3317c4c6571..017cc1775a1 100644
--- a/spec/graphql/types/design_management/version_type_spec.rb
+++ b/spec/graphql/types/design_management/version_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['DesignVersion'] do
+RSpec.describe GitlabSchema.types['DesignVersion'] do
it { expect(described_class).to require_graphql_authorizations(:read_design) }
it 'has the expected fields' do
diff --git a/spec/graphql/types/design_management_type_spec.rb b/spec/graphql/types/design_management_type_spec.rb
index a6204f20f23..e9162feec74 100644
--- a/spec/graphql/types/design_management_type_spec.rb
+++ b/spec/graphql/types/design_management_type_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe GitlabSchema.types['DesignManagement'] do
+RSpec.describe GitlabSchema.types['DesignManagement'] do
it { expect(described_class).to have_graphql_fields(:version, :design_at_version) }
end
diff --git a/spec/graphql/types/diff_refs_type_spec.rb b/spec/graphql/types/diff_refs_type_spec.rb
index 3165e642452..894191c55ba 100644
--- a/spec/graphql/types/diff_refs_type_spec.rb
+++ b/spec/graphql/types/diff_refs_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['DiffRefs'] do
+RSpec.describe GitlabSchema.types['DiffRefs'] do
specify { expect(described_class.graphql_name).to eq('DiffRefs') }
specify { expect(described_class).to have_graphql_fields(:head_sha, :base_sha, :start_sha).only }
diff --git a/spec/graphql/types/environment_type_spec.rb b/spec/graphql/types/environment_type_spec.rb
index 0e5cbac05df..f7522cb3e2c 100644
--- a/spec/graphql/types/environment_type_spec.rb
+++ b/spec/graphql/types/environment_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Environment'] do
+RSpec.describe GitlabSchema.types['Environment'] do
specify { expect(described_class.graphql_name).to eq('Environment') }
it 'has the expected fields' do
diff --git a/spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb b/spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb
index 0a094e9e188..66cc4d6374c 100644
--- a/spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb
+++ b/spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['SentryDetailedError'] do
+RSpec.describe GitlabSchema.types['SentryDetailedError'] do
specify { expect(described_class.graphql_name).to eq('SentryDetailedError') }
specify { expect(described_class).to require_graphql_authorizations(:read_sentry_issue) }
diff --git a/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb
index 793da2db960..3a8ff7a73be 100644
--- a/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb
+++ b/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['SentryErrorCollection'] do
+RSpec.describe GitlabSchema.types['SentryErrorCollection'] do
specify { expect(described_class.graphql_name).to eq('SentryErrorCollection') }
specify { expect(described_class).to require_graphql_authorizations(:read_sentry_issue) }
diff --git a/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb
index b65398fccc9..54d0d8edbc6 100644
--- a/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb
+++ b/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['SentryErrorStackTraceEntry'] do
+RSpec.describe GitlabSchema.types['SentryErrorStackTraceEntry'] do
specify { expect(described_class.graphql_name).to eq('SentryErrorStackTraceEntry') }
it 'exposes the expected fields' do
diff --git a/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb
index 2cec8865764..07ddbd83d0a 100644
--- a/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb
+++ b/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['SentryErrorStackTrace'] do
+RSpec.describe GitlabSchema.types['SentryErrorStackTrace'] do
specify { expect(described_class.graphql_name).to eq('SentryErrorStackTrace') }
specify { expect(described_class).to require_graphql_authorizations(:read_sentry_issue) }
diff --git a/spec/graphql/types/error_tracking/sentry_error_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_type_spec.rb
index f8cc801e35e..6cbcc8888c6 100644
--- a/spec/graphql/types/error_tracking/sentry_error_type_spec.rb
+++ b/spec/graphql/types/error_tracking/sentry_error_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['SentryError'] do
+RSpec.describe GitlabSchema.types['SentryError'] do
specify { expect(described_class.graphql_name).to eq('SentryError') }
it 'exposes the expected fields' do
diff --git a/spec/graphql/types/grafana_integration_type_spec.rb b/spec/graphql/types/grafana_integration_type_spec.rb
index 429b5bdffe6..b4658db08d7 100644
--- a/spec/graphql/types/grafana_integration_type_spec.rb
+++ b/spec/graphql/types/grafana_integration_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['GrafanaIntegration'] do
+RSpec.describe GitlabSchema.types['GrafanaIntegration'] do
let(:expected_fields) do
%i[
id
diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb
index c56cd40ef12..fb79e9bb85b 100644
--- a/spec/graphql/types/group_type_spec.rb
+++ b/spec/graphql/types/group_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Group'] do
+RSpec.describe GitlabSchema.types['Group'] do
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Group) }
specify { expect(described_class.graphql_name).to eq('Group') }
diff --git a/spec/graphql/types/issuable_sort_enum_spec.rb b/spec/graphql/types/issuable_sort_enum_spec.rb
index 35c42d8194c..e5237256a2b 100644
--- a/spec/graphql/types/issuable_sort_enum_spec.rb
+++ b/spec/graphql/types/issuable_sort_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::IssuableSortEnum do
+RSpec.describe Types::IssuableSortEnum do
specify { expect(described_class.graphql_name).to eq('IssuableSort') }
it 'exposes all the existing issuable sort values' do
diff --git a/spec/graphql/types/issuable_state_enum_spec.rb b/spec/graphql/types/issuable_state_enum_spec.rb
index f974ed5f5fb..a63b8cddb14 100644
--- a/spec/graphql/types/issuable_state_enum_spec.rb
+++ b/spec/graphql/types/issuable_state_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['IssuableState'] do
+RSpec.describe GitlabSchema.types['IssuableState'] do
specify { expect(described_class.graphql_name).to eq('IssuableState') }
it_behaves_like 'issuable state'
diff --git a/spec/graphql/types/issue_sort_enum_spec.rb b/spec/graphql/types/issue_sort_enum_spec.rb
index c496b897cdb..9313d3aee84 100644
--- a/spec/graphql/types/issue_sort_enum_spec.rb
+++ b/spec/graphql/types/issue_sort_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['IssueSort'] do
+RSpec.describe GitlabSchema.types['IssueSort'] do
specify { expect(described_class.graphql_name).to eq('IssueSort') }
it_behaves_like 'common sort values'
diff --git a/spec/graphql/types/issue_state_enum_spec.rb b/spec/graphql/types/issue_state_enum_spec.rb
index a18c5f5d317..a9dd287e196 100644
--- a/spec/graphql/types/issue_state_enum_spec.rb
+++ b/spec/graphql/types/issue_state_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['IssueState'] do
+RSpec.describe GitlabSchema.types['IssueState'] do
specify { expect(described_class.graphql_name).to eq('IssueState') }
it_behaves_like 'issuable state'
diff --git a/spec/graphql/types/issue_type_spec.rb b/spec/graphql/types/issue_type_spec.rb
index a8f7edcfe8e..8096cd001c0 100644
--- a/spec/graphql/types/issue_type_spec.rb
+++ b/spec/graphql/types/issue_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Issue'] do
+RSpec.describe GitlabSchema.types['Issue'] do
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Issue) }
specify { expect(described_class.graphql_name).to eq('Issue') }
diff --git a/spec/graphql/types/jira_import_type_spec.rb b/spec/graphql/types/jira_import_type_spec.rb
index fa1152aec41..b44525d3304 100644
--- a/spec/graphql/types/jira_import_type_spec.rb
+++ b/spec/graphql/types/jira_import_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['JiraImport'] do
+RSpec.describe GitlabSchema.types['JiraImport'] do
specify { expect(described_class.graphql_name).to eq('JiraImport') }
it 'has the expected fields' do
diff --git a/spec/graphql/types/label_type_spec.rb b/spec/graphql/types/label_type_spec.rb
index 026c63906ef..6a999a2e925 100644
--- a/spec/graphql/types/label_type_spec.rb
+++ b/spec/graphql/types/label_type_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-describe GitlabSchema.types['Label'] do
+RSpec.describe GitlabSchema.types['Label'] do
it 'has the correct fields' do
expected_fields = [:id, :description, :description_html, :title, :color, :text_color]
diff --git a/spec/graphql/types/merge_request_state_enum_spec.rb b/spec/graphql/types/merge_request_state_enum_spec.rb
index 2abc7b298b1..6fc5803a5d0 100644
--- a/spec/graphql/types/merge_request_state_enum_spec.rb
+++ b/spec/graphql/types/merge_request_state_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['MergeRequestState'] do
+RSpec.describe GitlabSchema.types['MergeRequestState'] do
specify { expect(described_class.graphql_name).to eq('MergeRequestState') }
it_behaves_like 'issuable state'
diff --git a/spec/graphql/types/merge_request_type_spec.rb b/spec/graphql/types/merge_request_type_spec.rb
index 0f48264c99f..6c3817392cd 100644
--- a/spec/graphql/types/merge_request_type_spec.rb
+++ b/spec/graphql/types/merge_request_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['MergeRequest'] do
+RSpec.describe GitlabSchema.types['MergeRequest'] do
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::MergeRequest) }
specify { expect(described_class).to require_graphql_authorizations(:read_merge_request) }
diff --git a/spec/graphql/types/metadata_type_spec.rb b/spec/graphql/types/metadata_type_spec.rb
index 75369ec9c3c..a1efb0a03d5 100644
--- a/spec/graphql/types/metadata_type_spec.rb
+++ b/spec/graphql/types/metadata_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Metadata'] do
+RSpec.describe GitlabSchema.types['Metadata'] do
specify { expect(described_class.graphql_name).to eq('Metadata') }
specify { expect(described_class).to require_graphql_authorizations(:read_instance_metadata) }
end
diff --git a/spec/graphql/types/metrics/dashboard_type_spec.rb b/spec/graphql/types/metrics/dashboard_type_spec.rb
index 0dbd0d8b38d..30dccc7c0be 100644
--- a/spec/graphql/types/metrics/dashboard_type_spec.rb
+++ b/spec/graphql/types/metrics/dashboard_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['MetricsDashboard'] do
+RSpec.describe GitlabSchema.types['MetricsDashboard'] do
specify { expect(described_class.graphql_name).to eq('MetricsDashboard') }
it 'has the expected fields' do
diff --git a/spec/graphql/types/metrics/dashboards/annotation_type_spec.rb b/spec/graphql/types/metrics/dashboards/annotation_type_spec.rb
index dbb8b04dbd7..12c5eec937c 100644
--- a/spec/graphql/types/metrics/dashboards/annotation_type_spec.rb
+++ b/spec/graphql/types/metrics/dashboards/annotation_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['MetricsDashboardAnnotation'] do
+RSpec.describe GitlabSchema.types['MetricsDashboardAnnotation'] do
specify { expect(described_class.graphql_name).to eq('MetricsDashboardAnnotation') }
it 'has the expected fields' do
diff --git a/spec/graphql/types/milestone_type_spec.rb b/spec/graphql/types/milestone_type_spec.rb
index 4c3d9f50a64..8952d9265d5 100644
--- a/spec/graphql/types/milestone_type_spec.rb
+++ b/spec/graphql/types/milestone_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Milestone'] do
+RSpec.describe GitlabSchema.types['Milestone'] do
specify { expect(described_class.graphql_name).to eq('Milestone') }
specify { expect(described_class).to require_graphql_authorizations(:read_milestone) }
diff --git a/spec/graphql/types/mutation_type_spec.rb b/spec/graphql/types/mutation_type_spec.rb
index 9d15648043e..41993327577 100644
--- a/spec/graphql/types/mutation_type_spec.rb
+++ b/spec/graphql/types/mutation_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::MutationType do
+RSpec.describe Types::MutationType do
it 'is expected to have the MergeRequestSetWip' do
expect(described_class).to have_graphql_mutation(Mutations::MergeRequests::SetWip)
end
diff --git a/spec/graphql/types/namespace_type_spec.rb b/spec/graphql/types/namespace_type_spec.rb
index 0080dc3b5cc..88952874bd3 100644
--- a/spec/graphql/types/namespace_type_spec.rb
+++ b/spec/graphql/types/namespace_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Namespace'] do
+RSpec.describe GitlabSchema.types['Namespace'] do
specify { expect(described_class.graphql_name).to eq('Namespace') }
it 'has the expected fields' do
diff --git a/spec/graphql/types/notes/diff_position_type_spec.rb b/spec/graphql/types/notes/diff_position_type_spec.rb
index 87f3810d55c..1515c2f66d7 100644
--- a/spec/graphql/types/notes/diff_position_type_spec.rb
+++ b/spec/graphql/types/notes/diff_position_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['DiffPosition'] do
+RSpec.describe GitlabSchema.types['DiffPosition'] do
it 'exposes the expected fields' do
expected_fields = %i[
diff_refs
diff --git a/spec/graphql/types/notes/discussion_type_spec.rb b/spec/graphql/types/notes/discussion_type_spec.rb
index 177000b01b2..37ed861d069 100644
--- a/spec/graphql/types/notes/discussion_type_spec.rb
+++ b/spec/graphql/types/notes/discussion_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Discussion'] do
+RSpec.describe GitlabSchema.types['Discussion'] do
it 'exposes the expected fields' do
expected_fields = %i[
created_at
diff --git a/spec/graphql/types/notes/note_type_spec.rb b/spec/graphql/types/notes/note_type_spec.rb
index d6cd0800234..4f2452683e2 100644
--- a/spec/graphql/types/notes/note_type_spec.rb
+++ b/spec/graphql/types/notes/note_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Note'] do
+RSpec.describe GitlabSchema.types['Note'] do
it 'exposes the expected fields' do
expected_fields = %i[
author
diff --git a/spec/graphql/types/notes/noteable_type_spec.rb b/spec/graphql/types/notes/noteable_type_spec.rb
index 88d8eae56d1..fad24c6fed4 100644
--- a/spec/graphql/types/notes/noteable_type_spec.rb
+++ b/spec/graphql/types/notes/noteable_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::Notes::NoteableType do
+RSpec.describe Types::Notes::NoteableType do
it 'exposes the expected fields' do
expected_fields = %i[
discussions
diff --git a/spec/graphql/types/permission_types/base_permission_type_spec.rb b/spec/graphql/types/permission_types/base_permission_type_spec.rb
index 4c6d5fd369a..2ce02f1520c 100644
--- a/spec/graphql/types/permission_types/base_permission_type_spec.rb
+++ b/spec/graphql/types/permission_types/base_permission_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::PermissionTypes::BasePermissionType do
+RSpec.describe Types::PermissionTypes::BasePermissionType do
let(:permitable) { double('permittable') }
let(:current_user) { build(:user) }
let(:context) { { current_user: current_user } }
diff --git a/spec/graphql/types/permission_types/issue_spec.rb b/spec/graphql/types/permission_types/issue_spec.rb
index a7a3dd00f11..58c5808cbcc 100644
--- a/spec/graphql/types/permission_types/issue_spec.rb
+++ b/spec/graphql/types/permission_types/issue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::PermissionTypes::Issue do
+RSpec.describe Types::PermissionTypes::Issue do
it do
expected_permissions = [
:read_issue, :admin_issue, :update_issue, :reopen_issue,
diff --git a/spec/graphql/types/permission_types/merge_request_spec.rb b/spec/graphql/types/permission_types/merge_request_spec.rb
index e0f8bdd4712..73a178540a6 100644
--- a/spec/graphql/types/permission_types/merge_request_spec.rb
+++ b/spec/graphql/types/permission_types/merge_request_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::PermissionTypes::MergeRequest do
+RSpec.describe Types::PermissionTypes::MergeRequest do
it do
expected_permissions = [
:read_merge_request, :admin_merge_request, :update_merge_request,
diff --git a/spec/graphql/types/permission_types/merge_request_type_spec.rb b/spec/graphql/types/permission_types/merge_request_type_spec.rb
index 7e9752cdc46..7dd1d3bca06 100644
--- a/spec/graphql/types/permission_types/merge_request_type_spec.rb
+++ b/spec/graphql/types/permission_types/merge_request_type_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Types::MergeRequestType do
+RSpec.describe Types::MergeRequestType do
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::MergeRequest) }
end
diff --git a/spec/graphql/types/permission_types/note_spec.rb b/spec/graphql/types/permission_types/note_spec.rb
index a2becb6892b..9769c7b3aa3 100644
--- a/spec/graphql/types/permission_types/note_spec.rb
+++ b/spec/graphql/types/permission_types/note_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['NotePermissions'] do
+RSpec.describe GitlabSchema.types['NotePermissions'] do
it 'has the expected fields' do
expected_permissions = [
:read_note, :create_note, :admin_note, :resolve_note, :award_emoji
diff --git a/spec/graphql/types/permission_types/project_spec.rb b/spec/graphql/types/permission_types/project_spec.rb
index 2789464d29c..c6853a0eadc 100644
--- a/spec/graphql/types/permission_types/project_spec.rb
+++ b/spec/graphql/types/permission_types/project_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::PermissionTypes::Project do
+RSpec.describe Types::PermissionTypes::Project do
it do
expected_permissions = [
:change_namespace, :change_visibility_level, :rename_project, :remove_project, :archive_project,
diff --git a/spec/graphql/types/permission_types/snippet_spec.rb b/spec/graphql/types/permission_types/snippet_spec.rb
index 66e9fa6dfdb..e2caa1c52c2 100644
--- a/spec/graphql/types/permission_types/snippet_spec.rb
+++ b/spec/graphql/types/permission_types/snippet_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::PermissionTypes::Snippet do
+RSpec.describe Types::PermissionTypes::Snippet do
it 'returns the snippets permissions' do
expected_permissions = [
:create_note, :award_emoji, :read_snippet, :update_snippet, :admin_snippet, :report_snippet
diff --git a/spec/graphql/types/permission_types/user_spec.rb b/spec/graphql/types/permission_types/user_spec.rb
index 1e8201db568..6f0d380f763 100644
--- a/spec/graphql/types/permission_types/user_spec.rb
+++ b/spec/graphql/types/permission_types/user_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::PermissionTypes::User do
+RSpec.describe Types::PermissionTypes::User do
it 'returns user permissions' do
expected_permissions = [
:create_snippet
diff --git a/spec/graphql/types/project_statistics_type_spec.rb b/spec/graphql/types/project_statistics_type_spec.rb
index fbea780494b..e1c2089c088 100644
--- a/spec/graphql/types/project_statistics_type_spec.rb
+++ b/spec/graphql/types/project_statistics_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['ProjectStatistics'] do
+RSpec.describe GitlabSchema.types['ProjectStatistics'] do
it "has all the required fields" do
expect(described_class).to have_graphql_fields(:storage_size, :repository_size, :lfs_objects_size,
:build_artifacts_size, :packages_size, :commit_count,
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 8ee9aa9cf3a..a3fe512934a 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Project'] do
+RSpec.describe GitlabSchema.types['Project'] do
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Project) }
specify { expect(described_class.graphql_name).to eq('Project') }
diff --git a/spec/graphql/types/projects/base_service_type_spec.rb b/spec/graphql/types/projects/base_service_type_spec.rb
index 4fcb9fe1a73..423cea860d7 100644
--- a/spec/graphql/types/projects/base_service_type_spec.rb
+++ b/spec/graphql/types/projects/base_service_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['BaseService'] do
+RSpec.describe GitlabSchema.types['BaseService'] do
specify { expect(described_class.graphql_name).to eq('BaseService') }
it 'has basic expected fields' do
diff --git a/spec/graphql/types/projects/jira_project_type_spec.rb b/spec/graphql/types/projects/jira_project_type_spec.rb
index cbb01117717..60b4c5c5276 100644
--- a/spec/graphql/types/projects/jira_project_type_spec.rb
+++ b/spec/graphql/types/projects/jira_project_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['JiraProject'] do
+RSpec.describe GitlabSchema.types['JiraProject'] do
it { expect(described_class.graphql_name).to eq('JiraProject') }
it 'has basic expected fields' do
diff --git a/spec/graphql/types/projects/jira_service_type_spec.rb b/spec/graphql/types/projects/jira_service_type_spec.rb
index fad0c91caab..9db580ac963 100644
--- a/spec/graphql/types/projects/jira_service_type_spec.rb
+++ b/spec/graphql/types/projects/jira_service_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['JiraService'] do
+RSpec.describe GitlabSchema.types['JiraService'] do
specify { expect(described_class.graphql_name).to eq('JiraService') }
it 'has basic expected fields' do
diff --git a/spec/graphql/types/projects/service_type_spec.rb b/spec/graphql/types/projects/service_type_spec.rb
index f6758d17d18..f110322ac89 100644
--- a/spec/graphql/types/projects/service_type_spec.rb
+++ b/spec/graphql/types/projects/service_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::Projects::ServiceType do
+RSpec.describe Types::Projects::ServiceType do
specify { expect(described_class).to have_graphql_fields(:type, :active) }
describe ".resolve_type" do
diff --git a/spec/graphql/types/projects/services_enum_spec.rb b/spec/graphql/types/projects/services_enum_spec.rb
index 91e398e8d81..dac1213daf3 100644
--- a/spec/graphql/types/projects/services_enum_spec.rb
+++ b/spec/graphql/types/projects/services_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['ServiceType'] do
+RSpec.describe GitlabSchema.types['ServiceType'] do
specify { expect(described_class.graphql_name).to eq('ServiceType') }
it 'exposes all the existing project services' do
diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb
index 1194391c26a..081f99a8307 100644
--- a/spec/graphql/types/query_type_spec.rb
+++ b/spec/graphql/types/query_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Query'] do
+RSpec.describe GitlabSchema.types['Query'] do
it 'is called Query' do
expect(described_class.graphql_name).to eq('Query')
end
diff --git a/spec/graphql/types/release_assets_type_spec.rb b/spec/graphql/types/release_assets_type_spec.rb
index 655098c4684..0166f87bf47 100644
--- a/spec/graphql/types/release_assets_type_spec.rb
+++ b/spec/graphql/types/release_assets_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['ReleaseAssets'] do
+RSpec.describe GitlabSchema.types['ReleaseAssets'] do
it { expect(described_class).to require_graphql_authorizations(:read_release) }
it 'has the expected fields' do
diff --git a/spec/graphql/types/release_links_type_spec.rb b/spec/graphql/types/release_links_type_spec.rb
index 1076cf37e0e..d505f0a4b5c 100644
--- a/spec/graphql/types/release_links_type_spec.rb
+++ b/spec/graphql/types/release_links_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['ReleaseLinks'] do
+RSpec.describe GitlabSchema.types['ReleaseLinks'] do
it { expect(described_class).to require_graphql_authorizations(:download_code) }
it 'has the expected fields' do
diff --git a/spec/graphql/types/release_source_type_spec.rb b/spec/graphql/types/release_source_type_spec.rb
index 929c6339479..69a1ca30dbc 100644
--- a/spec/graphql/types/release_source_type_spec.rb
+++ b/spec/graphql/types/release_source_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['ReleaseSource'] do
+RSpec.describe GitlabSchema.types['ReleaseSource'] do
it { expect(described_class).to require_graphql_authorizations(:download_code) }
it 'has the expected fields' do
diff --git a/spec/graphql/types/release_type_spec.rb b/spec/graphql/types/release_type_spec.rb
index 1001235702c..0c05a68c5a6 100644
--- a/spec/graphql/types/release_type_spec.rb
+++ b/spec/graphql/types/release_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Release'] do
+RSpec.describe GitlabSchema.types['Release'] do
it { expect(described_class).to require_graphql_authorizations(:read_release) }
it 'has the expected fields' do
diff --git a/spec/graphql/types/repository_type_spec.rb b/spec/graphql/types/repository_type_spec.rb
index fb52839c712..27780476421 100644
--- a/spec/graphql/types/repository_type_spec.rb
+++ b/spec/graphql/types/repository_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Repository'] do
+RSpec.describe GitlabSchema.types['Repository'] do
specify { expect(described_class.graphql_name).to eq('Repository') }
specify { expect(described_class).to require_graphql_authorizations(:download_code) }
diff --git a/spec/graphql/types/resolvable_interface_spec.rb b/spec/graphql/types/resolvable_interface_spec.rb
index 231287f9969..25370f8d527 100644
--- a/spec/graphql/types/resolvable_interface_spec.rb
+++ b/spec/graphql/types/resolvable_interface_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::ResolvableInterface do
+RSpec.describe Types::ResolvableInterface do
it 'exposes the expected fields' do
expected_fields = %i[
resolvable
diff --git a/spec/graphql/types/root_storage_statistics_type_spec.rb b/spec/graphql/types/root_storage_statistics_type_spec.rb
index ebaa5a18623..19e6f79ae74 100644
--- a/spec/graphql/types/root_storage_statistics_type_spec.rb
+++ b/spec/graphql/types/root_storage_statistics_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['RootStorageStatistics'] do
+RSpec.describe GitlabSchema.types['RootStorageStatistics'] do
specify { expect(described_class.graphql_name).to eq('RootStorageStatistics') }
it 'has all the required fields' do
diff --git a/spec/graphql/types/snippet_type_spec.rb b/spec/graphql/types/snippet_type_spec.rb
index f24419ce9cc..0341ca2c733 100644
--- a/spec/graphql/types/snippet_type_spec.rb
+++ b/spec/graphql/types/snippet_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Snippet'] do
+RSpec.describe GitlabSchema.types['Snippet'] do
let_it_be(:user) { create(:user) }
it 'has the correct fields' do
diff --git a/spec/graphql/types/snippets/blob_type_spec.rb b/spec/graphql/types/snippets/blob_type_spec.rb
index fb8c6896732..bfac08f40d3 100644
--- a/spec/graphql/types/snippets/blob_type_spec.rb
+++ b/spec/graphql/types/snippets/blob_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['SnippetBlob'] do
+RSpec.describe GitlabSchema.types['SnippetBlob'] do
it 'has the correct fields' do
expected_fields = [:rich_data, :plain_data,
:raw_path, :size, :binary, :name, :path,
diff --git a/spec/graphql/types/snippets/blob_viewer_type_spec.rb b/spec/graphql/types/snippets/blob_viewer_type_spec.rb
index 841e22451db..8210eb9a95c 100644
--- a/spec/graphql/types/snippets/blob_viewer_type_spec.rb
+++ b/spec/graphql/types/snippets/blob_viewer_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['SnippetBlobViewer'] do
+RSpec.describe GitlabSchema.types['SnippetBlobViewer'] do
let_it_be(:snippet) { create(:personal_snippet, :repository) }
let_it_be(:blob) { snippet.repository.blob_at('HEAD', 'files/images/6049019_460s.jpg') }
diff --git a/spec/graphql/types/time_type_spec.rb b/spec/graphql/types/time_type_spec.rb
index 3c6e191e2fb..68d346766c2 100644
--- a/spec/graphql/types/time_type_spec.rb
+++ b/spec/graphql/types/time_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Time'] do
+RSpec.describe GitlabSchema.types['Time'] do
let(:iso) { "2018-06-04T15:23:50+02:00" }
let(:time) { Time.parse(iso) }
diff --git a/spec/graphql/types/todo_type_spec.rb b/spec/graphql/types/todo_type_spec.rb
index 87a5405f0e2..15b6195ec5c 100644
--- a/spec/graphql/types/todo_type_spec.rb
+++ b/spec/graphql/types/todo_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['Todo'] do
+RSpec.describe GitlabSchema.types['Todo'] do
it 'has the correct fields' do
expected_fields = [:id, :project, :group, :author, :action, :target_type, :body, :state, :created_at]
diff --git a/spec/graphql/types/tree/blob_type_spec.rb b/spec/graphql/types/tree/blob_type_spec.rb
index 547a03b5edf..2c9089de3dd 100644
--- a/spec/graphql/types/tree/blob_type_spec.rb
+++ b/spec/graphql/types/tree/blob_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::Tree::BlobType do
+RSpec.describe Types::Tree::BlobType do
specify { expect(described_class.graphql_name).to eq('Blob') }
specify { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url, :lfs_oid) }
diff --git a/spec/graphql/types/tree/submodule_type_spec.rb b/spec/graphql/types/tree/submodule_type_spec.rb
index b5cfe8eb812..ba2b06f1907 100644
--- a/spec/graphql/types/tree/submodule_type_spec.rb
+++ b/spec/graphql/types/tree/submodule_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::Tree::SubmoduleType do
+RSpec.describe Types::Tree::SubmoduleType do
specify { expect(described_class.graphql_name).to eq('Submodule') }
specify { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url, :tree_url) }
diff --git a/spec/graphql/types/tree/tree_entry_type_spec.rb b/spec/graphql/types/tree/tree_entry_type_spec.rb
index 14826d06645..0e5caf66854 100644
--- a/spec/graphql/types/tree/tree_entry_type_spec.rb
+++ b/spec/graphql/types/tree/tree_entry_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::Tree::TreeEntryType do
+RSpec.describe Types::Tree::TreeEntryType do
specify { expect(described_class.graphql_name).to eq('TreeEntry') }
specify { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url) }
diff --git a/spec/graphql/types/tree/tree_type_spec.rb b/spec/graphql/types/tree/tree_type_spec.rb
index 93faebd3602..362ecdfca91 100644
--- a/spec/graphql/types/tree/tree_type_spec.rb
+++ b/spec/graphql/types/tree/tree_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::Tree::TreeType do
+RSpec.describe Types::Tree::TreeType do
specify { expect(described_class.graphql_name).to eq('Tree') }
specify { expect(described_class).to have_graphql_fields(:trees, :submodules, :blobs, :last_commit) }
diff --git a/spec/graphql/types/tree/type_enum_spec.rb b/spec/graphql/types/tree/type_enum_spec.rb
index dcacd6073f9..f751bcf2a13 100644
--- a/spec/graphql/types/tree/type_enum_spec.rb
+++ b/spec/graphql/types/tree/type_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Types::Tree::TypeEnum do
+RSpec.describe Types::Tree::TypeEnum do
specify { expect(described_class.graphql_name).to eq('EntryType') }
it 'exposes all tree entry types' do
diff --git a/spec/graphql/types/user_type_spec.rb b/spec/graphql/types/user_type_spec.rb
index 7b34588b0ff..6cc3f7bcaa1 100644
--- a/spec/graphql/types/user_type_spec.rb
+++ b/spec/graphql/types/user_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabSchema.types['User'] do
+RSpec.describe GitlabSchema.types['User'] do
specify { expect(described_class.graphql_name).to eq('User') }
specify { expect(described_class).to require_graphql_authorizations(:read_user) }
diff --git a/spec/haml_lint/linter/no_plain_nodes_spec.rb b/spec/haml_lint/linter/no_plain_nodes_spec.rb
index dc647467db6..08f7e6131cc 100644
--- a/spec/haml_lint/linter/no_plain_nodes_spec.rb
+++ b/spec/haml_lint/linter/no_plain_nodes_spec.rb
@@ -5,7 +5,7 @@ require 'haml_lint'
require 'haml_lint/spec'
require Rails.root.join('haml_lint/linter/no_plain_nodes')
-describe HamlLint::Linter::NoPlainNodes do
+RSpec.describe HamlLint::Linter::NoPlainNodes do
include_context 'linter'
context 'reports when a tag has an inline plain node' do
diff --git a/spec/helpers/access_tokens_helper_spec.rb b/spec/helpers/access_tokens_helper_spec.rb
index 1d246d3f236..28041203447 100644
--- a/spec/helpers/access_tokens_helper_spec.rb
+++ b/spec/helpers/access_tokens_helper_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-describe AccessTokensHelper do
+RSpec.describe AccessTokensHelper do
describe "#scope_description" do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/helpers/appearances_helper_spec.rb b/spec/helpers/appearances_helper_spec.rb
index ed3e31b3c53..179c69b2a67 100644
--- a/spec/helpers/appearances_helper_spec.rb
+++ b/spec/helpers/appearances_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe AppearancesHelper do
+RSpec.describe AppearancesHelper do
before do
user = create(:user)
allow(helper).to receive(:current_user).and_return(user)
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 0b13acbc577..08107b841d7 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ApplicationHelper do
+RSpec.describe ApplicationHelper do
describe 'current_controller?' do
before do
stub_controller_name('foo')
diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb
index 3fb754f1090..c5fd88ada8f 100644
--- a/spec/helpers/application_settings_helper_spec.rb
+++ b/spec/helpers/application_settings_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ApplicationSettingsHelper do
+RSpec.describe ApplicationSettingsHelper do
context 'when all protocols in use' do
before do
stub_application_setting(enabled_git_access_protocol: '')
diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb
index 23f3449d9a7..1e843ee221b 100644
--- a/spec/helpers/auth_helper_spec.rb
+++ b/spec/helpers/auth_helper_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-describe AuthHelper do
+RSpec.describe AuthHelper do
describe "button_based_providers" do
it 'returns all enabled providers from devise' do
allow(helper).to receive(:auth_providers) { [:twitter, :github] }
diff --git a/spec/helpers/auto_devops_helper_spec.rb b/spec/helpers/auto_devops_helper_spec.rb
index e0fecb0c159..5e5e33c4db5 100644
--- a/spec/helpers/auto_devops_helper_spec.rb
+++ b/spec/helpers/auto_devops_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe AutoDevopsHelper do
+RSpec.describe AutoDevopsHelper do
let_it_be(:project, reload: true) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb
index 2a030742cb9..9e18ab34c1f 100644
--- a/spec/helpers/avatars_helper_spec.rb
+++ b/spec/helpers/avatars_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe AvatarsHelper do
+RSpec.describe AvatarsHelper do
include UploadHelpers
let(:user) { create(:user) }
diff --git a/spec/helpers/award_emoji_helper_spec.rb b/spec/helpers/award_emoji_helper_spec.rb
index 3dee466a80c..51e0a1b9721 100644
--- a/spec/helpers/award_emoji_helper_spec.rb
+++ b/spec/helpers/award_emoji_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe AwardEmojiHelper do
+RSpec.describe AwardEmojiHelper do
describe '.toggle_award_url' do
subject { helper.toggle_award_url(awardable) }
diff --git a/spec/helpers/blame_helper_spec.rb b/spec/helpers/blame_helper_spec.rb
index 8b5de040508..6371c2b63ce 100644
--- a/spec/helpers/blame_helper_spec.rb
+++ b/spec/helpers/blame_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BlameHelper do
+RSpec.describe BlameHelper do
describe '#get_age_map_start_date' do
let(:dates) do
[Time.zone.local(2014, 3, 17, 0, 0, 0),
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index 2631c219222..7d5b4e1c3f0 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BlobHelper do
+RSpec.describe BlobHelper do
include TreeHelper
describe '#highlight' do
diff --git a/spec/helpers/boards_helper_spec.rb b/spec/helpers/boards_helper_spec.rb
index cb9be9d5fb4..a805b96a8cc 100644
--- a/spec/helpers/boards_helper_spec.rb
+++ b/spec/helpers/boards_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BoardsHelper do
+RSpec.describe BoardsHelper do
let_it_be(:project) { create(:project) }
describe '#build_issue_link_base' do
diff --git a/spec/helpers/broadcast_messages_helper_spec.rb b/spec/helpers/broadcast_messages_helper_spec.rb
index 58cc03a9446..21fde35954e 100644
--- a/spec/helpers/broadcast_messages_helper_spec.rb
+++ b/spec/helpers/broadcast_messages_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BroadcastMessagesHelper do
+RSpec.describe BroadcastMessagesHelper do
describe 'current_broadcast_notification_message' do
subject { helper.current_broadcast_notification_message }
diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb
index cf8887f9731..6a5cb73281e 100644
--- a/spec/helpers/button_helper_spec.rb
+++ b/spec/helpers/button_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ButtonHelper do
+RSpec.describe ButtonHelper do
describe 'http_clone_button' do
let(:user) { create(:user) }
let(:project) { build_stubbed(:project) }
diff --git a/spec/helpers/calendar_helper_spec.rb b/spec/helpers/calendar_helper_spec.rb
index 8dba6815e8d..ceed4191ef4 100644
--- a/spec/helpers/calendar_helper_spec.rb
+++ b/spec/helpers/calendar_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe CalendarHelper do
+RSpec.describe CalendarHelper do
describe '#calendar_url_options' do
context 'when signed in' do
it "includes the current_user's feed_token" do
diff --git a/spec/helpers/ci_status_helper_spec.rb b/spec/helpers/ci_status_helper_spec.rb
index 80be119b069..1c8a749944b 100644
--- a/spec/helpers/ci_status_helper_spec.rb
+++ b/spec/helpers/ci_status_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe CiStatusHelper do
+RSpec.describe CiStatusHelper do
include IconsHelper
let(:success_commit) { double("Ci::Pipeline", status: 'success') }
diff --git a/spec/helpers/clusters_helper_spec.rb b/spec/helpers/clusters_helper_spec.rb
index c41d4f0ede7..2b820cd540c 100644
--- a/spec/helpers/clusters_helper_spec.rb
+++ b/spec/helpers/clusters_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ClustersHelper do
+RSpec.describe ClustersHelper do
describe '#has_rbac_enabled?' do
context 'when kubernetes platform has been created' do
let(:platform_kubernetes) { build_stubbed(:cluster_platform_kubernetes) }
diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb
index e036e97f745..11bee36b3a8 100644
--- a/spec/helpers/commits_helper_spec.rb
+++ b/spec/helpers/commits_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe CommitsHelper do
+RSpec.describe CommitsHelper do
describe 'commit_author_link' do
it 'escapes the author email' do
commit = double(
diff --git a/spec/helpers/components_helper_spec.rb b/spec/helpers/components_helper_spec.rb
index 703bee0ca92..4fa6d27993f 100644
--- a/spec/helpers/components_helper_spec.rb
+++ b/spec/helpers/components_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ComponentsHelper do
+RSpec.describe ComponentsHelper do
describe '#gitlab_workhorse_version' do
context 'without a Gitlab-Workhorse header' do
it 'shows the version from Gitlab::Workhorse.version' do
diff --git a/spec/helpers/container_expiration_policies_helper_spec.rb b/spec/helpers/container_expiration_policies_helper_spec.rb
index 6dcbadd89cb..b2a03f8d90f 100644
--- a/spec/helpers/container_expiration_policies_helper_spec.rb
+++ b/spec/helpers/container_expiration_policies_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ContainerExpirationPoliciesHelper do
+RSpec.describe ContainerExpirationPoliciesHelper do
describe '#keep_n_options' do
it 'returns keep_n options formatted for dropdown usage' do
expected_result = [
diff --git a/spec/helpers/dashboard_helper_spec.rb b/spec/helpers/dashboard_helper_spec.rb
index 8a4ea33ac7c..65182dcb729 100644
--- a/spec/helpers/dashboard_helper_spec.rb
+++ b/spec/helpers/dashboard_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe DashboardHelper do
+RSpec.describe DashboardHelper do
let(:user) { build(:user) }
before do
diff --git a/spec/helpers/defer_script_tag_helper_spec.rb b/spec/helpers/defer_script_tag_helper_spec.rb
index 440904188ca..14317e353ab 100644
--- a/spec/helpers/defer_script_tag_helper_spec.rb
+++ b/spec/helpers/defer_script_tag_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe DeferScriptTagHelper do
+RSpec.describe DeferScriptTagHelper do
describe 'script tag' do
script_url = 'test.js'
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index 63aa41bbad5..d27b6f91d27 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe DiffHelper do
+RSpec.describe DiffHelper do
include RepoHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb
index 0ff9080ef94..bc5fe05ab52 100644
--- a/spec/helpers/emails_helper_spec.rb
+++ b/spec/helpers/emails_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe EmailsHelper do
+RSpec.describe EmailsHelper do
describe 'closure_reason_text' do
context 'when given a MergeRequest' do
let(:merge_request) { create(:merge_request) }
diff --git a/spec/helpers/emoji_helper_spec.rb b/spec/helpers/emoji_helper_spec.rb
index 1b73e956f7a..15e4ce03960 100644
--- a/spec/helpers/emoji_helper_spec.rb
+++ b/spec/helpers/emoji_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe EmojiHelper do
+RSpec.describe EmojiHelper do
describe '#emoji_icon' do
let(:options) { {} }
let(:emoji_text) { 'rocket' }
diff --git a/spec/helpers/environment_helper_spec.rb b/spec/helpers/environment_helper_spec.rb
index 53953d72b06..8c542ca01f4 100644
--- a/spec/helpers/environment_helper_spec.rb
+++ b/spec/helpers/environment_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe EnvironmentHelper do
+RSpec.describe EnvironmentHelper do
describe '#render_deployment_status' do
context 'when using a manual deployment' do
it 'renders a span tag' do
diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb
index 48104dfc5a6..03428b43966 100644
--- a/spec/helpers/environments_helper_spec.rb
+++ b/spec/helpers/environments_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe EnvironmentsHelper do
+RSpec.describe EnvironmentsHelper do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :repository) }
let_it_be(:environment) { create(:environment, project: project) }
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index 15d617c0b02..5a0c16cc05b 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe EventsHelper do
+RSpec.describe EventsHelper do
include Gitlab::Routing
describe '#event_commit_title' do
diff --git a/spec/helpers/explore_helper_spec.rb b/spec/helpers/explore_helper_spec.rb
index 1a6af3be055..d843a9d3ce5 100644
--- a/spec/helpers/explore_helper_spec.rb
+++ b/spec/helpers/explore_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ExploreHelper do
+RSpec.describe ExploreHelper do
let(:user) { build(:user) }
before do
diff --git a/spec/helpers/export_helper_spec.rb b/spec/helpers/export_helper_spec.rb
index 3fbda441b5d..7ab9560ca6a 100644
--- a/spec/helpers/export_helper_spec.rb
+++ b/spec/helpers/export_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ExportHelper do
+RSpec.describe ExportHelper do
describe '#project_export_descriptions' do
it 'includes design management' do
expect(project_export_descriptions).to include('Design Management files and data')
diff --git a/spec/helpers/external_link_helper_spec.rb b/spec/helpers/external_link_helper_spec.rb
index 7fc4ef18731..b1a1884d887 100644
--- a/spec/helpers/external_link_helper_spec.rb
+++ b/spec/helpers/external_link_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ExternalLinkHelper do
+RSpec.describe ExternalLinkHelper do
include IconsHelper
it 'returns external link with icon' do
diff --git a/spec/helpers/form_helper_spec.rb b/spec/helpers/form_helper_spec.rb
index 6698d8970e7..79c96e65a0e 100644
--- a/spec/helpers/form_helper_spec.rb
+++ b/spec/helpers/form_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe FormHelper do
+RSpec.describe FormHelper do
describe 'form_errors' do
it 'returns nil when model has no errors' do
model = double(errors: [])
diff --git a/spec/helpers/git_helper_spec.rb b/spec/helpers/git_helper_spec.rb
index 6dfd8d2cc76..0dd9eecb7f0 100644
--- a/spec/helpers/git_helper_spec.rb
+++ b/spec/helpers/git_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitHelper do
+RSpec.describe GitHelper do
describe '#short_sha' do
let(:short_sha) { helper.short_sha('d4e043f6c20749a3ab3f4b8e23f2a8979f4b9100') }
diff --git a/spec/helpers/gitlab_routing_helper_spec.rb b/spec/helpers/gitlab_routing_helper_spec.rb
index 4def04f4284..fb3e9270696 100644
--- a/spec/helpers/gitlab_routing_helper_spec.rb
+++ b/spec/helpers/gitlab_routing_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GitlabRoutingHelper do
+RSpec.describe GitlabRoutingHelper do
let(:project) { build_stubbed(:project) }
let(:group) { build_stubbed(:group) }
diff --git a/spec/helpers/graph_helper_spec.rb b/spec/helpers/graph_helper_spec.rb
index dc389c09e60..3c7e4f970c3 100644
--- a/spec/helpers/graph_helper_spec.rb
+++ b/spec/helpers/graph_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GraphHelper do
+RSpec.describe GraphHelper do
describe '#get_refs' do
let(:project) { create(:project, :repository) }
let(:commit) { project.commit("master") }
diff --git a/spec/helpers/groups/group_members_helper_spec.rb b/spec/helpers/groups/group_members_helper_spec.rb
index 898c330c498..90792331d9b 100644
--- a/spec/helpers/groups/group_members_helper_spec.rb
+++ b/spec/helpers/groups/group_members_helper_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-describe Groups::GroupMembersHelper do
+RSpec.describe Groups::GroupMembersHelper do
describe '.group_member_select_options' do
let(:group) { create(:group) }
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index 5be247c5b49..a739c16f3b1 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe GroupsHelper do
+RSpec.describe GroupsHelper do
include ApplicationHelper
describe 'group_icon_url' do
diff --git a/spec/helpers/hooks_helper_spec.rb b/spec/helpers/hooks_helper_spec.rb
index 4352089c1c0..92e082c4974 100644
--- a/spec/helpers/hooks_helper_spec.rb
+++ b/spec/helpers/hooks_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe HooksHelper do
+RSpec.describe HooksHelper do
let(:project) { create(:project) }
let(:project_hook) { create(:project_hook, project: project) }
let(:system_hook) { create(:system_hook) }
diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb
index 5c26db028b7..3000a044298 100644
--- a/spec/helpers/icons_helper_spec.rb
+++ b/spec/helpers/icons_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe IconsHelper do
+RSpec.describe IconsHelper do
let(:icons_path) { ActionController::Base.helpers.image_path("icons.svg") }
describe 'icon' do
diff --git a/spec/helpers/import_helper_spec.rb b/spec/helpers/import_helper_spec.rb
index a6b283e49dc..18cbbdfd804 100644
--- a/spec/helpers/import_helper_spec.rb
+++ b/spec/helpers/import_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ImportHelper do
+RSpec.describe ImportHelper do
describe '#sanitize_project_name' do
it 'removes leading tildes' do
expect(helper.sanitize_project_name('~~root')).to eq('root')
diff --git a/spec/helpers/instance_configuration_helper_spec.rb b/spec/helpers/instance_configuration_helper_spec.rb
index 31a6c7bc839..1ba06b97088 100644
--- a/spec/helpers/instance_configuration_helper_spec.rb
+++ b/spec/helpers/instance_configuration_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe InstanceConfigurationHelper do
+RSpec.describe InstanceConfigurationHelper do
describe '#instance_configuration_cell_html' do
describe 'if not block is passed' do
it 'returns the parameter if present' do
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index 38ad11846d2..5a88fc1cbf1 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe IssuablesHelper do
+RSpec.describe IssuablesHelper do
let(:label) { build_stubbed(:label) }
let(:label2) { build_stubbed(:label) }
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 3ef6745958c..4ed63704895 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-describe IssuesHelper do
+RSpec.describe IssuesHelper do
let(:project) { create(:project) }
let(:issue) { create :issue, project: project }
let(:ext_project) { create :redmine_project }
diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb
index ec70041d51f..77e1d10354c 100644
--- a/spec/helpers/labels_helper_spec.rb
+++ b/spec/helpers/labels_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe LabelsHelper do
+RSpec.describe LabelsHelper do
describe '#show_label_issuables_link?' do
shared_examples 'a valid response to show_label_issuables_link?' do |issuables_type, when_enabled = true, when_disabled = false|
context "when asking for a #{issuables_type} link" do
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 1fc79a9762a..302ab0cc137 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe MarkupHelper do
+RSpec.describe MarkupHelper do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) do
user = create(:user, username: 'gfm')
diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb
index 946ffcddae7..99e8696e960 100644
--- a/spec/helpers/members_helper_spec.rb
+++ b/spec/helpers/members_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe MembersHelper do
+RSpec.describe MembersHelper do
describe '#remove_member_message' do
let(:requester) { create(:user) }
let(:project) { create(:project, :public) }
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index 8db8c37038e..fcb9efa39d5 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe MergeRequestsHelper do
+RSpec.describe MergeRequestsHelper do
include ActionView::Helpers::UrlHelper
include ProjectForksHelper
diff --git a/spec/helpers/namespaces_helper_spec.rb b/spec/helpers/namespaces_helper_spec.rb
index ebce296d7c2..29e533699de 100644
--- a/spec/helpers/namespaces_helper_spec.rb
+++ b/spec/helpers/namespaces_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe NamespacesHelper do
+RSpec.describe NamespacesHelper do
let!(:admin) { create(:admin) }
let!(:admin_project_creation_level) { nil }
let!(:admin_group) do
diff --git a/spec/helpers/nav_helper_spec.rb b/spec/helpers/nav_helper_spec.rb
index ac1c6c62433..b1c9485e5a1 100644
--- a/spec/helpers/nav_helper_spec.rb
+++ b/spec/helpers/nav_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe NavHelper, :do_not_mock_admin_mode do
+RSpec.describe NavHelper, :do_not_mock_admin_mode do
describe '#header_links' do
include_context 'custom session'
diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb
index 543a9081779..f29f947ba46 100644
--- a/spec/helpers/notes_helper_spec.rb
+++ b/spec/helpers/notes_helper_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-describe NotesHelper do
+RSpec.describe NotesHelper do
include RepoHelpers
let(:owner) { create(:owner) }
diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb
index d8dcce203fe..319c85c19f9 100644
--- a/spec/helpers/notifications_helper_spec.rb
+++ b/spec/helpers/notifications_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe NotificationsHelper do
+RSpec.describe NotificationsHelper do
describe 'notification_icon' do
it { expect(notification_icon(:disabled)).to match('class="fa fa-microphone-slash fa-fw"') }
it { expect(notification_icon(:owner_disabled)).to match('class="fa fa-microphone-slash fa-fw"') }
diff --git a/spec/helpers/onboarding_experiment_helper_spec.rb b/spec/helpers/onboarding_experiment_helper_spec.rb
index cada91bff3c..19d1dca7e5e 100644
--- a/spec/helpers/onboarding_experiment_helper_spec.rb
+++ b/spec/helpers/onboarding_experiment_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe OnboardingExperimentHelper, type: :helper do
+RSpec.describe OnboardingExperimentHelper, type: :helper do
describe '.allow_access_to_onboarding?' do
context "when we're not gitlab.com or dev env" do
it 'returns false' do
diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb
index 55f743ac683..e8a5c4613fe 100644
--- a/spec/helpers/page_layout_helper_spec.rb
+++ b/spec/helpers/page_layout_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe PageLayoutHelper do
+RSpec.describe PageLayoutHelper do
describe 'page_description' do
it 'defaults to nil' do
expect(helper.page_description).to eq nil
diff --git a/spec/helpers/pagination_helper_spec.rb b/spec/helpers/pagination_helper_spec.rb
index 9fb51249edc..4cd6b6f3922 100644
--- a/spec/helpers/pagination_helper_spec.rb
+++ b/spec/helpers/pagination_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe PaginationHelper do
+RSpec.describe PaginationHelper do
describe '#paginate_collection' do
let(:collection) { User.all.page(1) }
diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb
index 7969cfd97b5..2e5a12eadae 100644
--- a/spec/helpers/preferences_helper_spec.rb
+++ b/spec/helpers/preferences_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe PreferencesHelper do
+RSpec.describe PreferencesHelper do
describe '#dashboard_choices' do
let(:user) { build(:user) }
diff --git a/spec/helpers/profiles_helper_spec.rb b/spec/helpers/profiles_helper_spec.rb
index fc282eee26d..4a8ba2b7113 100644
--- a/spec/helpers/profiles_helper_spec.rb
+++ b/spec/helpers/profiles_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ProfilesHelper do
+RSpec.describe ProfilesHelper do
describe '#commit_email_select_options' do
it 'returns an array with private commit email along with all the verified emails' do
user = create(:user)
diff --git a/spec/helpers/projects/alert_management_helper_spec.rb b/spec/helpers/projects/alert_management_helper_spec.rb
index 4de710312a9..efd48ababa1 100644
--- a/spec/helpers/projects/alert_management_helper_spec.rb
+++ b/spec/helpers/projects/alert_management_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Projects::AlertManagementHelper do
+RSpec.describe Projects::AlertManagementHelper do
include Gitlab::Routing.url_helpers
let_it_be(:project, reload: true) { create(:project) }
diff --git a/spec/helpers/projects/error_tracking_helper_spec.rb b/spec/helpers/projects/error_tracking_helper_spec.rb
index 008d749a002..882031a9c86 100644
--- a/spec/helpers/projects/error_tracking_helper_spec.rb
+++ b/spec/helpers/projects/error_tracking_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Projects::ErrorTrackingHelper do
+RSpec.describe Projects::ErrorTrackingHelper do
include Gitlab::Routing.url_helpers
let_it_be(:project, reload: true) { create(:project) }
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 4e072f02ae0..8dafdea454b 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ProjectsHelper do
+RSpec.describe ProjectsHelper do
include ProjectForksHelper
let_it_be(:project) { create(:project) }
diff --git a/spec/helpers/recaptcha_experiment_helper_spec.rb b/spec/helpers/recaptcha_experiment_helper_spec.rb
index a5b233e28a0..e677164c950 100644
--- a/spec/helpers/recaptcha_experiment_helper_spec.rb
+++ b/spec/helpers/recaptcha_experiment_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe RecaptchaExperimentHelper, type: :helper do
+RSpec.describe RecaptchaExperimentHelper, type: :helper do
let(:session) { {} }
before do
diff --git a/spec/helpers/releases_helper_spec.rb b/spec/helpers/releases_helper_spec.rb
index de4086e48db..b84560fc45b 100644
--- a/spec/helpers/releases_helper_spec.rb
+++ b/spec/helpers/releases_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ReleasesHelper do
+RSpec.describe ReleasesHelper do
describe '#illustration' do
it 'returns the correct image path' do
expect(helper.illustration).to match(/illustrations\/releases-(\w+)\.svg/)
diff --git a/spec/helpers/rss_helper_spec.rb b/spec/helpers/rss_helper_spec.rb
index 657f5fb42bc..c7eb33dc6f7 100644
--- a/spec/helpers/rss_helper_spec.rb
+++ b/spec/helpers/rss_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe RssHelper do
+RSpec.describe RssHelper do
describe '#rss_url_options' do
context 'when signed in' do
it "includes the current_user's feed_token" do
diff --git a/spec/helpers/runners_helper_spec.rb b/spec/helpers/runners_helper_spec.rb
index 042714d002e..831369b7db9 100644
--- a/spec/helpers/runners_helper_spec.rb
+++ b/spec/helpers/runners_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe RunnersHelper do
+RSpec.describe RunnersHelper do
it "returns - not contacted yet" do
runner = FactoryBot.build :ci_runner
expect(runner_status_icon(runner)).to include("not connected yet")
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index b209ed869bf..1360a4264a9 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe SearchHelper do
+RSpec.describe SearchHelper do
# Override simple_sanitize for our testing purposes
def simple_sanitize(str)
str
diff --git a/spec/helpers/services_helper_spec.rb b/spec/helpers/services_helper_spec.rb
index cb4e016d9d1..37256c1b387 100644
--- a/spec/helpers/services_helper_spec.rb
+++ b/spec/helpers/services_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ServicesHelper do
+RSpec.describe ServicesHelper do
describe 'event_action_title' do
it { expect(event_action_title('comment')).to eq 'Comment' }
it { expect(event_action_title('something')).to eq 'Something' }
diff --git a/spec/helpers/sessions_helper_spec.rb b/spec/helpers/sessions_helper_spec.rb
index 647771ace92..027943aecee 100644
--- a/spec/helpers/sessions_helper_spec.rb
+++ b/spec/helpers/sessions_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe SessionsHelper do
+RSpec.describe SessionsHelper do
describe '#unconfirmed_email?' do
it 'returns true when the flash alert contains a devise failure unconfirmed message' do
flash[:alert] = t(:unconfirmed, scope: [:devise, :failure])
diff --git a/spec/helpers/sidekiq_helper_spec.rb b/spec/helpers/sidekiq_helper_spec.rb
index 86e52419f9c..6a0a92bafd8 100644
--- a/spec/helpers/sidekiq_helper_spec.rb
+++ b/spec/helpers/sidekiq_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe SidekiqHelper do
+RSpec.describe SidekiqHelper do
describe 'parse_sidekiq_ps' do
it 'parses line with time' do
line = '55137 10,0 2,1 S+ 2:30pm sidekiq 4.1.4 gitlab [0 of 25 busy] '
diff --git a/spec/helpers/snippets_helper_spec.rb b/spec/helpers/snippets_helper_spec.rb
index 6fdf4f5cfb4..8fc54f17e71 100644
--- a/spec/helpers/snippets_helper_spec.rb
+++ b/spec/helpers/snippets_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe SnippetsHelper do
+RSpec.describe SnippetsHelper do
include Gitlab::Routing
include IconsHelper
diff --git a/spec/helpers/sorting_helper_spec.rb b/spec/helpers/sorting_helper_spec.rb
index 5397a47b3dd..6c52016139b 100644
--- a/spec/helpers/sorting_helper_spec.rb
+++ b/spec/helpers/sorting_helper_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-describe SortingHelper do
+RSpec.describe SortingHelper do
include ApplicationHelper
include IconsHelper
include ExploreHelper
diff --git a/spec/helpers/sourcegraph_helper_spec.rb b/spec/helpers/sourcegraph_helper_spec.rb
index 3e8486a5632..6a95c8e4a43 100644
--- a/spec/helpers/sourcegraph_helper_spec.rb
+++ b/spec/helpers/sourcegraph_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe SourcegraphHelper do
+RSpec.describe SourcegraphHelper do
describe '#sourcegraph_url_message' do
let(:sourcegraph_url) { 'http://sourcegraph.example.com' }
diff --git a/spec/helpers/storage_helper_spec.rb b/spec/helpers/storage_helper_spec.rb
index 577e6e5caf0..6fc73d35a59 100644
--- a/spec/helpers/storage_helper_spec.rb
+++ b/spec/helpers/storage_helper_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-describe StorageHelper do
+RSpec.describe StorageHelper do
describe "#storage_counter" do
it "formats bytes to one decimal place" do
expect(helper.storage_counter(1.23.megabytes)).to eq("1.2 MB")
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index db0836c8550..426bca2ced2 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe SubmoduleHelper do
+RSpec.describe SubmoduleHelper do
include RepoHelpers
let(:submodule_item) { double(id: 'hash', path: 'rack') }
diff --git a/spec/helpers/tab_helper_spec.rb b/spec/helpers/tab_helper_spec.rb
index 3a3935a2130..f89d0ac0f5a 100644
--- a/spec/helpers/tab_helper_spec.rb
+++ b/spec/helpers/tab_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe TabHelper do
+RSpec.describe TabHelper do
include ApplicationHelper
describe 'nav_link' do
diff --git a/spec/helpers/time_helper_spec.rb b/spec/helpers/time_helper_spec.rb
index 858d6d341f4..6663a5c81c8 100644
--- a/spec/helpers/time_helper_spec.rb
+++ b/spec/helpers/time_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe TimeHelper do
+RSpec.describe TimeHelper do
describe "#time_interval_in_words" do
it "returns minutes and seconds" do
intervals_in_words = {
diff --git a/spec/helpers/timeboxes_helper_spec.rb b/spec/helpers/timeboxes_helper_spec.rb
index 6fe738914ce..94e997f7a65 100644
--- a/spec/helpers/timeboxes_helper_spec.rb
+++ b/spec/helpers/timeboxes_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe TimeboxesHelper do
+RSpec.describe TimeboxesHelper do
describe '#milestones_filter_dropdown_path' do
let(:project) { create(:project) }
let(:project2) { create(:project) }
diff --git a/spec/helpers/timeboxes_routing_helper_spec.rb b/spec/helpers/timeboxes_routing_helper_spec.rb
index 1b0eb2c0ad2..952194b6704 100644
--- a/spec/helpers/timeboxes_routing_helper_spec.rb
+++ b/spec/helpers/timeboxes_routing_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe TimeboxesRoutingHelper do
+RSpec.describe TimeboxesRoutingHelper do
let(:project) { build_stubbed(:project) }
let(:group) { build_stubbed(:group) }
diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb
index 0811c2af891..2780e5ff1db 100644
--- a/spec/helpers/todos_helper_spec.rb
+++ b/spec/helpers/todos_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe TodosHelper do
+RSpec.describe TodosHelper do
let_it_be(:user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:issue) { create(:issue, title: 'Issue 1') }
diff --git a/spec/helpers/tracking_helper_spec.rb b/spec/helpers/tracking_helper_spec.rb
index b0c98be4130..47b344cfc25 100644
--- a/spec/helpers/tracking_helper_spec.rb
+++ b/spec/helpers/tracking_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe TrackingHelper do
+RSpec.describe TrackingHelper do
describe '#tracking_attrs' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb
index c7cdb4ae45c..511cfaaa7a9 100644
--- a/spec/helpers/tree_helper_spec.rb
+++ b/spec/helpers/tree_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe TreeHelper do
+RSpec.describe TreeHelper do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:sha) { 'c1c67abbaf91f624347bb3ae96eabe3a1b742478' }
diff --git a/spec/helpers/user_callouts_helper_spec.rb b/spec/helpers/user_callouts_helper_spec.rb
index b123b11d278..cb6e39657b0 100644
--- a/spec/helpers/user_callouts_helper_spec.rb
+++ b/spec/helpers/user_callouts_helper_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-describe UserCalloutsHelper do
+RSpec.describe UserCalloutsHelper do
let(:user) { create(:user) }
before do
diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb
index e3e599007a4..8dfdb23c64b 100644
--- a/spec/helpers/users_helper_spec.rb
+++ b/spec/helpers/users_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe UsersHelper do
+RSpec.describe UsersHelper do
include TermsHelper
let(:user) { create(:user) }
diff --git a/spec/helpers/version_check_helper_spec.rb b/spec/helpers/version_check_helper_spec.rb
index 421ff21bfdb..6d849d0720e 100644
--- a/spec/helpers/version_check_helper_spec.rb
+++ b/spec/helpers/version_check_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe VersionCheckHelper do
+RSpec.describe VersionCheckHelper do
describe '#version_status_badge' do
it 'returns nil if not dev environment and not enabled' do
stub_rails_env('development')
diff --git a/spec/helpers/visibility_level_helper_spec.rb b/spec/helpers/visibility_level_helper_spec.rb
index 3b4d82c65ac..9cbace3cfd0 100644
--- a/spec/helpers/visibility_level_helper_spec.rb
+++ b/spec/helpers/visibility_level_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe VisibilityLevelHelper do
+RSpec.describe VisibilityLevelHelper do
include ProjectForksHelper
let(:project) { build(:project) }
diff --git a/spec/helpers/wiki_helper_spec.rb b/spec/helpers/wiki_helper_spec.rb
index 4b53823aaed..f4eb3e53f80 100644
--- a/spec/helpers/wiki_helper_spec.rb
+++ b/spec/helpers/wiki_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe WikiHelper do
+RSpec.describe WikiHelper do
describe '#breadcrumb' do
context 'when the page is at the root level' do
it 'returns the capitalized page name' do
diff --git a/spec/helpers/x509_helper_spec.rb b/spec/helpers/x509_helper_spec.rb
index db3f6158195..4e3e8c8d3f6 100644
--- a/spec/helpers/x509_helper_spec.rb
+++ b/spec/helpers/x509_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe X509Helper do
+RSpec.describe X509Helper do
describe '#x509_subject' do
let(:search_uppercase) { %w[CN OU O] }
let(:search_lowercase) { %w[cn ou o] }
diff --git a/spec/initializers/100_patch_omniauth_saml_spec.rb b/spec/initializers/100_patch_omniauth_saml_spec.rb
index c4d20f79af0..3496eb4d680 100644
--- a/spec/initializers/100_patch_omniauth_saml_spec.rb
+++ b/spec/initializers/100_patch_omniauth_saml_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'OmniAuth::Strategies::SAML', type: :strategy do
+RSpec.describe 'OmniAuth::Strategies::SAML', type: :strategy do
let(:idp_sso_target_url) { 'https://login.example.com/idp' }
let(:strategy) { [OmniAuth::Strategies::SAML, { idp_sso_target_url: idp_sso_target_url }] }
diff --git a/spec/initializers/6_validations_spec.rb b/spec/initializers/6_validations_spec.rb
index 248f967311b..b909fc9db0a 100644
--- a/spec/initializers/6_validations_spec.rb
+++ b/spec/initializers/6_validations_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_relative '../../config/initializers/6_validations.rb'
-describe '6_validations' do
+RSpec.describe '6_validations' do
describe 'validate_storages_config' do
context 'with correct settings' do
before do
diff --git a/spec/initializers/action_mailer_hooks_spec.rb b/spec/initializers/action_mailer_hooks_spec.rb
index 03eee09f737..f04fe804d62 100644
--- a/spec/initializers/action_mailer_hooks_spec.rb
+++ b/spec/initializers/action_mailer_hooks_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'ActionMailer hooks' do
+RSpec.describe 'ActionMailer hooks' do
describe 'smime signature interceptor' do
before do
class_spy(ActionMailer::Base).as_stubbed_const
diff --git a/spec/initializers/active_record_locking_spec.rb b/spec/initializers/active_record_locking_spec.rb
index 5a16aef78e6..e979fa0b793 100644
--- a/spec/initializers/active_record_locking_spec.rb
+++ b/spec/initializers/active_record_locking_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'ActiveRecord locking' do
+RSpec.describe 'ActiveRecord locking' do
let(:issue) { create(:issue) }
shared_examples 'locked model' do
diff --git a/spec/initializers/asset_proxy_setting_spec.rb b/spec/initializers/asset_proxy_setting_spec.rb
index 7eab5de155b..62bb31b2be9 100644
--- a/spec/initializers/asset_proxy_setting_spec.rb
+++ b/spec/initializers/asset_proxy_setting_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'Asset proxy settings initialization' do
+RSpec.describe 'Asset proxy settings initialization' do
describe '#asset_proxy' do
it 'defaults to disabled' do
expect(Banzai::Filter::AssetProxyFilter).to receive(:initialize_settings)
diff --git a/spec/initializers/attr_encrypted_no_db_connection_spec.rb b/spec/initializers/attr_encrypted_no_db_connection_spec.rb
index 14e0e1f2167..ad3d14ed7d4 100644
--- a/spec/initializers/attr_encrypted_no_db_connection_spec.rb
+++ b/spec/initializers/attr_encrypted_no_db_connection_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'GitLab monkey-patches to AttrEncrypted' do
+RSpec.describe 'GitLab monkey-patches to AttrEncrypted' do
describe '#attribute_instance_methods_as_symbols_available?' do
it 'returns false' do
expect(ActiveRecord::Base.__send__(:attribute_instance_methods_as_symbols_available?)).to be_falsy
diff --git a/spec/initializers/attr_encrypted_thread_safe_spec.rb b/spec/initializers/attr_encrypted_thread_safe_spec.rb
index 096b8b196b4..e79b7c716ec 100644
--- a/spec/initializers/attr_encrypted_thread_safe_spec.rb
+++ b/spec/initializers/attr_encrypted_thread_safe_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe AttrEncrypted do
+RSpec.describe AttrEncrypted do
describe '#encrypted_attributes' do
subject do
Class.new(ActiveRecord::Base) do
diff --git a/spec/initializers/database_config_spec.rb b/spec/initializers/database_config_spec.rb
index 7c0b280fdaf..29d499efcd3 100644
--- a/spec/initializers/database_config_spec.rb
+++ b/spec/initializers/database_config_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'Database config initializer' do
+RSpec.describe 'Database config initializer' do
subject do
load Rails.root.join('config/initializers/database_config.rb')
end
diff --git a/spec/initializers/direct_upload_support_spec.rb b/spec/initializers/direct_upload_support_spec.rb
index 7db40f4b5ab..aa77c0905c9 100644
--- a/spec/initializers/direct_upload_support_spec.rb
+++ b/spec/initializers/direct_upload_support_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'Direct upload support' do
+RSpec.describe 'Direct upload support' do
subject do
load Rails.root.join('config/initializers/direct_upload_support.rb')
end
diff --git a/spec/initializers/doorkeeper_spec.rb b/spec/initializers/doorkeeper_spec.rb
index 47c196cb3a3..164225a00b2 100644
--- a/spec/initializers/doorkeeper_spec.rb
+++ b/spec/initializers/doorkeeper_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_relative '../../config/initializers/doorkeeper'
-describe Doorkeeper.configuration do
+RSpec.describe Doorkeeper.configuration do
describe '#default_scopes' do
it 'matches Gitlab::Auth::DEFAULT_SCOPES' do
expect(subject.default_scopes).to eq Gitlab::Auth::DEFAULT_SCOPES
diff --git a/spec/initializers/fog_google_https_private_urls_spec.rb b/spec/initializers/fog_google_https_private_urls_spec.rb
index 8a0d7ad8f15..4825525a3d8 100644
--- a/spec/initializers/fog_google_https_private_urls_spec.rb
+++ b/spec/initializers/fog_google_https_private_urls_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'Fog::Storage::GoogleXML::File', :fog_requests do
+RSpec.describe 'Fog::Storage::GoogleXML::File', :fog_requests do
let(:storage) do
Fog.mock!
Fog::Storage.new(
diff --git a/spec/initializers/hangouts_chat_http_override_spec.rb b/spec/initializers/hangouts_chat_http_override_spec.rb
index 0eee891799f..42236c8c853 100644
--- a/spec/initializers/hangouts_chat_http_override_spec.rb
+++ b/spec/initializers/hangouts_chat_http_override_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'HangoutsChat::Sender Gitlab::HTTP override' do
+RSpec.describe 'HangoutsChat::Sender Gitlab::HTTP override' do
describe 'HangoutsChat::Sender::HTTP#post' do
it 'calls Gitlab::HTTP.post with default protection settings' do
webhook_url = 'https://example.gitlab.com'
diff --git a/spec/initializers/lograge_spec.rb b/spec/initializers/lograge_spec.rb
index 9e5eab4fc6b..4d10d218606 100644
--- a/spec/initializers/lograge_spec.rb
+++ b/spec/initializers/lograge_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'lograge', type: :request do
+RSpec.describe 'lograge', type: :request do
let(:headers) { { 'X-Request-ID' => 'new-correlation-id' } }
let(:large_params) do
diff --git a/spec/initializers/mail_encoding_patch_spec.rb b/spec/initializers/mail_encoding_patch_spec.rb
index 41074af3503..efacaf6b1b4 100644
--- a/spec/initializers/mail_encoding_patch_spec.rb
+++ b/spec/initializers/mail_encoding_patch_spec.rb
@@ -5,7 +5,7 @@ require 'fast_spec_helper'
require 'mail'
require_relative '../../config/initializers/mail_encoding_patch.rb'
-describe 'Mail quoted-printable transfer encoding patch and Unicode characters' do
+RSpec.describe 'Mail quoted-printable transfer encoding patch and Unicode characters' do
shared_examples 'email encoding' do |email|
it 'enclosing in a new object does not change the encoded original' do
new_email = Mail.new(email)
diff --git a/spec/initializers/rest-client-hostname_override_spec.rb b/spec/initializers/rest-client-hostname_override_spec.rb
index 7e36656ba1c..187f18a6b1d 100644
--- a/spec/initializers/rest-client-hostname_override_spec.rb
+++ b/spec/initializers/rest-client-hostname_override_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'rest-client dns rebinding protection' do
+RSpec.describe 'rest-client dns rebinding protection' do
it_behaves_like 'a request using Gitlab::UrlBlocker' do
let(:http_method) { :get }
let(:url_blocked_error_class) { ArgumentError }
diff --git a/spec/initializers/secret_token_spec.rb b/spec/initializers/secret_token_spec.rb
index b7979144c72..a9360e10ee0 100644
--- a/spec/initializers/secret_token_spec.rb
+++ b/spec/initializers/secret_token_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_relative '../../config/initializers/01_secret_token'
-describe 'create_tokens' do
+RSpec.describe 'create_tokens' do
include StubENV
let(:secrets) { ActiveSupport::OrderedOptions.new }
diff --git a/spec/initializers/settings_spec.rb b/spec/initializers/settings_spec.rb
index 6cb45b4c86b..71ea12a41aa 100644
--- a/spec/initializers/settings_spec.rb
+++ b/spec/initializers/settings_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_relative '../../config/initializers/1_settings' unless defined?(Settings)
-describe Settings do
+RSpec.describe Settings do
describe '#ldap' do
it 'can be accessed with dot syntax all the way down' do
expect(Gitlab.config.ldap.servers.main.label).to eq('ldap')
diff --git a/spec/initializers/trusted_proxies_spec.rb b/spec/initializers/trusted_proxies_spec.rb
index a2bd0ff9f1c..2786f034969 100644
--- a/spec/initializers/trusted_proxies_spec.rb
+++ b/spec/initializers/trusted_proxies_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'trusted_proxies' do
+RSpec.describe 'trusted_proxies' do
context 'with default config' do
before do
set_trusted_proxies([])
diff --git a/spec/initializers/zz_metrics_spec.rb b/spec/initializers/zz_metrics_spec.rb
index f41a807f1eb..ad93c30ee22 100644
--- a/spec/initializers/zz_metrics_spec.rb
+++ b/spec/initializers/zz_metrics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'instrument_classes' do
+RSpec.describe 'instrument_classes' do
let(:config) { double(:config) }
before do
diff --git a/spec/lib/after_commit_queue_spec.rb b/spec/lib/after_commit_queue_spec.rb
index 8e9dfd90338..ca383808bfc 100644
--- a/spec/lib/after_commit_queue_spec.rb
+++ b/spec/lib/after_commit_queue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe AfterCommitQueue do
+RSpec.describe AfterCommitQueue do
it 'runs after transaction is committed' do
called = false
test_proc = proc { called = true }
diff --git a/spec/lib/api/api_spec.rb b/spec/lib/api/api_spec.rb
index c83d068ca50..cf08eaa7653 100644
--- a/spec/lib/api/api_spec.rb
+++ b/spec/lib/api/api_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::API do
+RSpec.describe API::API do
describe '.prefix' do
it 'has a prefix defined' do
expect(described_class.prefix).to eq :api
diff --git a/spec/lib/api/entities/branch_spec.rb b/spec/lib/api/entities/branch_spec.rb
index 604f56c0cb2..e07b431964c 100644
--- a/spec/lib/api/entities/branch_spec.rb
+++ b/spec/lib/api/entities/branch_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Entities::Branch do
+RSpec.describe API::Entities::Branch do
describe '#as_json' do
subject { entity.as_json }
diff --git a/spec/lib/api/entities/design_management/design_spec.rb b/spec/lib/api/entities/design_management/design_spec.rb
index 50ca3b43c6a..fe449e3e9bc 100644
--- a/spec/lib/api/entities/design_management/design_spec.rb
+++ b/spec/lib/api/entities/design_management/design_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Entities::DesignManagement::Design do
+RSpec.describe API::Entities::DesignManagement::Design do
let_it_be(:design) { create(:design) }
let(:entity) { described_class.new(design, request: double) }
diff --git a/spec/lib/api/entities/job_request/image_spec.rb b/spec/lib/api/entities/job_request/image_spec.rb
index 092c181ae9c..f13eab6a752 100644
--- a/spec/lib/api/entities/job_request/image_spec.rb
+++ b/spec/lib/api/entities/job_request/image_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Entities::JobRequest::Image do
+RSpec.describe API::Entities::JobRequest::Image do
let(:ports) { [{ number: 80, protocol: 'http', name: 'name' }]}
let(:image) { double(name: 'image_name', entrypoint: ['foo'], ports: ports)}
let(:entity) { described_class.new(image) }
diff --git a/spec/lib/api/entities/job_request/port_spec.rb b/spec/lib/api/entities/job_request/port_spec.rb
index 40ab4cd6231..4820c4a691b 100644
--- a/spec/lib/api/entities/job_request/port_spec.rb
+++ b/spec/lib/api/entities/job_request/port_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ::API::Entities::JobRequest::Port do
+RSpec.describe ::API::Entities::JobRequest::Port do
let(:port) { double(number: 80, protocol: 'http', name: 'name')}
let(:entity) { described_class.new(port) }
diff --git a/spec/lib/api/entities/project_import_failed_relation_spec.rb b/spec/lib/api/entities/project_import_failed_relation_spec.rb
index f8330713480..51a684c4564 100644
--- a/spec/lib/api/entities/project_import_failed_relation_spec.rb
+++ b/spec/lib/api/entities/project_import_failed_relation_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Entities::ProjectImportFailedRelation do
+RSpec.describe API::Entities::ProjectImportFailedRelation do
describe '#as_json' do
subject { entity.as_json }
diff --git a/spec/lib/api/entities/project_import_status_spec.rb b/spec/lib/api/entities/project_import_status_spec.rb
index a800d703496..5eda613a6a6 100644
--- a/spec/lib/api/entities/project_import_status_spec.rb
+++ b/spec/lib/api/entities/project_import_status_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Entities::ProjectImportStatus do
+RSpec.describe API::Entities::ProjectImportStatus do
describe '#as_json' do
subject { entity.as_json }
diff --git a/spec/lib/api/entities/project_repository_storage_move_spec.rb b/spec/lib/api/entities/project_repository_storage_move_spec.rb
index 1c38c8231d4..b0102dc376a 100644
--- a/spec/lib/api/entities/project_repository_storage_move_spec.rb
+++ b/spec/lib/api/entities/project_repository_storage_move_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Entities::ProjectRepositoryStorageMove do
+RSpec.describe API::Entities::ProjectRepositoryStorageMove do
describe '#as_json' do
subject { entity.as_json }
diff --git a/spec/lib/api/entities/release_spec.rb b/spec/lib/api/entities/release_spec.rb
index fa9e1e74f9b..d57c283c1f4 100644
--- a/spec/lib/api/entities/release_spec.rb
+++ b/spec/lib/api/entities/release_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Entities::Release do
+RSpec.describe API::Entities::Release do
let_it_be(:project) { create(:project) }
let(:release) { create(:release, project: project) }
let(:evidence) { release.evidences.first }
diff --git a/spec/lib/api/entities/snippet_spec.rb b/spec/lib/api/entities/snippet_spec.rb
index dada0942e49..f0b2656c112 100644
--- a/spec/lib/api/entities/snippet_spec.rb
+++ b/spec/lib/api/entities/snippet_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ::API::Entities::Snippet do
+RSpec.describe ::API::Entities::Snippet do
let_it_be(:user) { create(:user) }
let_it_be(:personal_snippet) { create(:personal_snippet, :repository, author: user ) }
let_it_be(:project_snippet) { create(:project_snippet, :repository, author: user) }
diff --git a/spec/lib/api/entities/user_spec.rb b/spec/lib/api/entities/user_spec.rb
index 20524b197e0..99ffe0eb925 100644
--- a/spec/lib/api/entities/user_spec.rb
+++ b/spec/lib/api/entities/user_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Entities::User do
+RSpec.describe API::Entities::User do
let(:user) { create(:user) }
let(:current_user) { create(:user) }
diff --git a/spec/lib/api/helpers/graphql_helpers_spec.rb b/spec/lib/api/helpers/graphql_helpers_spec.rb
index c775ba6d5e8..678f4f8a3e3 100644
--- a/spec/lib/api/helpers/graphql_helpers_spec.rb
+++ b/spec/lib/api/helpers/graphql_helpers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Helpers::GraphqlHelpers do
+RSpec.describe API::Helpers::GraphqlHelpers do
describe 'run_graphql!' do
let(:query) { '{ metadata { version } }' }
diff --git a/spec/lib/api/helpers/label_helpers_spec.rb b/spec/lib/api/helpers/label_helpers_spec.rb
index 138e9a22d70..007cb3248e2 100644
--- a/spec/lib/api/helpers/label_helpers_spec.rb
+++ b/spec/lib/api/helpers/label_helpers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Helpers::LabelHelpers do
+RSpec.describe API::Helpers::LabelHelpers do
describe 'create_service_params' do
let(:label_helper) do
Class.new do
diff --git a/spec/lib/api/helpers/pagination_spec.rb b/spec/lib/api/helpers/pagination_spec.rb
index 796c753d6c4..a008c1adeac 100644
--- a/spec/lib/api/helpers/pagination_spec.rb
+++ b/spec/lib/api/helpers/pagination_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Helpers::Pagination do
+RSpec.describe API::Helpers::Pagination do
subject { Class.new.include(described_class).new }
let(:paginator) { double('paginator') }
diff --git a/spec/lib/api/helpers/pagination_strategies_spec.rb b/spec/lib/api/helpers/pagination_strategies_spec.rb
index eaa71159714..e8a4243b407 100644
--- a/spec/lib/api/helpers/pagination_strategies_spec.rb
+++ b/spec/lib/api/helpers/pagination_strategies_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Helpers::PaginationStrategies do
+RSpec.describe API::Helpers::PaginationStrategies do
subject { Class.new.include(described_class).new }
let(:expected_result) { double("result") }
diff --git a/spec/lib/api/helpers/related_resources_helpers_spec.rb b/spec/lib/api/helpers/related_resources_helpers_spec.rb
index eeeb22abd10..a0dc69536b4 100644
--- a/spec/lib/api/helpers/related_resources_helpers_spec.rb
+++ b/spec/lib/api/helpers/related_resources_helpers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Helpers::RelatedResourcesHelpers do
+RSpec.describe API::Helpers::RelatedResourcesHelpers do
subject(:helpers) do
Class.new.include(described_class).new
end
diff --git a/spec/lib/api/helpers/version_spec.rb b/spec/lib/api/helpers/version_spec.rb
index a9f33962537..a87a3c5a026 100644
--- a/spec/lib/api/helpers/version_spec.rb
+++ b/spec/lib/api/helpers/version_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Helpers::Version do
+RSpec.describe API::Helpers::Version do
describe '.new' do
it 'is possible to initialize it with existing API version' do
expect(described_class.new('v4').to_s).to eq 'v4'
diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb
index 3595d06a184..8cba1e0794a 100644
--- a/spec/lib/api/helpers_spec.rb
+++ b/spec/lib/api/helpers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Helpers do
+RSpec.describe API::Helpers do
subject { Class.new.include(described_class).new }
describe '#find_project' do
diff --git a/spec/lib/api/support/git_access_actor_spec.rb b/spec/lib/api/support/git_access_actor_spec.rb
index 69637947c79..70753856419 100644
--- a/spec/lib/api/support/git_access_actor_spec.rb
+++ b/spec/lib/api/support/git_access_actor_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Support::GitAccessActor do
+RSpec.describe API::Support::GitAccessActor do
let(:user) { nil }
let(:key) { nil }
diff --git a/spec/lib/api/validations/validators/absence_spec.rb b/spec/lib/api/validations/validators/absence_spec.rb
index 31120979d4f..bfecaf4e243 100644
--- a/spec/lib/api/validations/validators/absence_spec.rb
+++ b/spec/lib/api/validations/validators/absence_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Validations::Validators::Absence do
+RSpec.describe API::Validations::Validators::Absence do
include ApiValidatorsHelpers
subject do
diff --git a/spec/lib/api/validations/validators/array_none_any_spec.rb b/spec/lib/api/validations/validators/array_none_any_spec.rb
index 03f1c63b117..833adea6554 100644
--- a/spec/lib/api/validations/validators/array_none_any_spec.rb
+++ b/spec/lib/api/validations/validators/array_none_any_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Validations::Validators::ArrayNoneAny do
+RSpec.describe API::Validations::Validators::ArrayNoneAny do
include ApiValidatorsHelpers
subject do
diff --git a/spec/lib/api/validations/validators/file_path_spec.rb b/spec/lib/api/validations/validators/file_path_spec.rb
index 8679f102d23..2c79260b8d5 100644
--- a/spec/lib/api/validations/validators/file_path_spec.rb
+++ b/spec/lib/api/validations/validators/file_path_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Validations::Validators::FilePath do
+RSpec.describe API::Validations::Validators::FilePath do
include ApiValidatorsHelpers
subject do
diff --git a/spec/lib/api/validations/validators/git_ref_spec.rb b/spec/lib/api/validations/validators/git_ref_spec.rb
index 84de6272fe1..0d2d9e8f39a 100644
--- a/spec/lib/api/validations/validators/git_ref_spec.rb
+++ b/spec/lib/api/validations/validators/git_ref_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Validations::Validators::GitRef do
+RSpec.describe API::Validations::Validators::GitRef do
include ApiValidatorsHelpers
subject do
diff --git a/spec/lib/api/validations/validators/git_sha_spec.rb b/spec/lib/api/validations/validators/git_sha_spec.rb
index 39c2fe1dcf9..ae6be52a4c7 100644
--- a/spec/lib/api/validations/validators/git_sha_spec.rb
+++ b/spec/lib/api/validations/validators/git_sha_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Validations::Validators::GitSha do
+RSpec.describe API::Validations::Validators::GitSha do
include ApiValidatorsHelpers
let(:sha) { RepoHelpers.sample_commit.id }
diff --git a/spec/lib/api/validations/validators/integer_none_any_spec.rb b/spec/lib/api/validations/validators/integer_none_any_spec.rb
index a42f69fd96e..33fa7688d18 100644
--- a/spec/lib/api/validations/validators/integer_none_any_spec.rb
+++ b/spec/lib/api/validations/validators/integer_none_any_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Validations::Validators::IntegerNoneAny do
+RSpec.describe API::Validations::Validators::IntegerNoneAny do
include ApiValidatorsHelpers
subject do
diff --git a/spec/lib/api/validations/validators/limit_spec.rb b/spec/lib/api/validations/validators/limit_spec.rb
index 600f74e1fb2..d71dde470cc 100644
--- a/spec/lib/api/validations/validators/limit_spec.rb
+++ b/spec/lib/api/validations/validators/limit_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Validations::Validators::Limit do
+RSpec.describe API::Validations::Validators::Limit do
include ApiValidatorsHelpers
subject do
diff --git a/spec/lib/backup/files_spec.rb b/spec/lib/backup/files_spec.rb
index b75f3bafeef..a7374b82ce0 100644
--- a/spec/lib/backup/files_spec.rb
+++ b/spec/lib/backup/files_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Backup::Files do
+RSpec.describe Backup::Files do
let(:progress) { StringIO.new }
let!(:project) { create(:project) }
diff --git a/spec/lib/backup/manager_spec.rb b/spec/lib/backup/manager_spec.rb
index b86e92d5969..38a5c30506b 100644
--- a/spec/lib/backup/manager_spec.rb
+++ b/spec/lib/backup/manager_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Backup::Manager do
+RSpec.describe Backup::Manager do
include StubENV
let(:progress) { StringIO.new }
diff --git a/spec/lib/backup/repository_spec.rb b/spec/lib/backup/repository_spec.rb
index e0afa256581..c073a45bf68 100644
--- a/spec/lib/backup/repository_spec.rb
+++ b/spec/lib/backup/repository_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Backup::Repository do
+RSpec.describe Backup::Repository do
let(:progress) { StringIO.new }
let!(:project) { create(:project, :wiki_repo) }
diff --git a/spec/lib/backup/uploads_spec.rb b/spec/lib/backup/uploads_spec.rb
index 1f49baeff69..7c2d715b580 100644
--- a/spec/lib/backup/uploads_spec.rb
+++ b/spec/lib/backup/uploads_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Backup::Uploads do
+RSpec.describe Backup::Uploads do
let(:progress) { StringIO.new }
subject(:backup) { described_class.new(progress) }
diff --git a/spec/lib/banzai/color_parser_spec.rb b/spec/lib/banzai/color_parser_spec.rb
index d9202ce77db..95b3955d8fe 100644
--- a/spec/lib/banzai/color_parser_spec.rb
+++ b/spec/lib/banzai/color_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ColorParser do
+RSpec.describe Banzai::ColorParser do
describe '.parse' do
context 'HEX format' do
[
diff --git a/spec/lib/banzai/commit_renderer_spec.rb b/spec/lib/banzai/commit_renderer_spec.rb
index e5a16b167be..a10dd6eb3a2 100644
--- a/spec/lib/banzai/commit_renderer_spec.rb
+++ b/spec/lib/banzai/commit_renderer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::CommitRenderer do
+RSpec.describe Banzai::CommitRenderer do
describe '.render', :clean_gitlab_redis_cache do
it 'renders a commit description and title' do
user = build(:user)
diff --git a/spec/lib/banzai/cross_project_reference_spec.rb b/spec/lib/banzai/cross_project_reference_spec.rb
index cf41af7e7a1..95b78ceb5d5 100644
--- a/spec/lib/banzai/cross_project_reference_spec.rb
+++ b/spec/lib/banzai/cross_project_reference_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::CrossProjectReference do
+RSpec.describe Banzai::CrossProjectReference do
let(:including_class) { Class.new.include(described_class).new }
before do
diff --git a/spec/lib/banzai/filter/absolute_link_filter_spec.rb b/spec/lib/banzai/filter/absolute_link_filter_spec.rb
index b61bd496dba..2cb70850dca 100644
--- a/spec/lib/banzai/filter/absolute_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/absolute_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::AbsoluteLinkFilter do
+RSpec.describe Banzai::Filter::AbsoluteLinkFilter do
def filter(doc, context = {})
described_class.call(doc, context)
end
diff --git a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
index 798112d0f53..8a5b23abaa0 100644
--- a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::AbstractReferenceFilter do
+RSpec.describe Banzai::Filter::AbstractReferenceFilter do
let_it_be(:project) { create(:project) }
let(:doc) { Nokogiri::HTML.fragment('') }
diff --git a/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb b/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb
index bd06dae26ba..334d5c59828 100644
--- a/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb
+++ b/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::AsciiDocPostProcessingFilter do
+RSpec.describe Banzai::Filter::AsciiDocPostProcessingFilter do
include FilterSpecHelper
it "adds class for elements with data-math-style" do
diff --git a/spec/lib/banzai/filter/asset_proxy_filter_spec.rb b/spec/lib/banzai/filter/asset_proxy_filter_spec.rb
index ff2346fe1ba..2a4ee28130b 100644
--- a/spec/lib/banzai/filter/asset_proxy_filter_spec.rb
+++ b/spec/lib/banzai/filter/asset_proxy_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::AssetProxyFilter do
+RSpec.describe Banzai::Filter::AssetProxyFilter do
include FilterSpecHelper
def image(path)
diff --git a/spec/lib/banzai/filter/audio_link_filter_spec.rb b/spec/lib/banzai/filter/audio_link_filter_spec.rb
index a8459137169..4198a50e980 100644
--- a/spec/lib/banzai/filter/audio_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/audio_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::AudioLinkFilter do
+RSpec.describe Banzai::Filter::AudioLinkFilter do
def filter(doc, contexts = {})
contexts.reverse_merge!({
project: project
diff --git a/spec/lib/banzai/filter/autolink_filter_spec.rb b/spec/lib/banzai/filter/autolink_filter_spec.rb
index be6192f9ead..ba15860f3c9 100644
--- a/spec/lib/banzai/filter/autolink_filter_spec.rb
+++ b/spec/lib/banzai/filter/autolink_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::AutolinkFilter do
+RSpec.describe Banzai::Filter::AutolinkFilter do
include FilterSpecHelper
let(:link) { 'http://about.gitlab.com/' }
diff --git a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
index 8e955ec3b6b..e736943914b 100644
--- a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
+++ b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::BlockquoteFenceFilter do
+RSpec.describe Banzai::Filter::BlockquoteFenceFilter do
include FilterSpecHelper
it 'converts blockquote fences to blockquote lines' do
diff --git a/spec/lib/banzai/filter/broadcast_message_placeholders_filter_spec.rb b/spec/lib/banzai/filter/broadcast_message_placeholders_filter_spec.rb
index 1a90abc12d9..a2d35eaa6b6 100644
--- a/spec/lib/banzai/filter/broadcast_message_placeholders_filter_spec.rb
+++ b/spec/lib/banzai/filter/broadcast_message_placeholders_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::BroadcastMessagePlaceholdersFilter do
+RSpec.describe Banzai::Filter::BroadcastMessagePlaceholdersFilter do
include FilterSpecHelper
subject { filter(text, current_user: user, broadcast_message_placeholders: true).to_html }
diff --git a/spec/lib/banzai/filter/broadcast_message_sanitization_filter_spec.rb b/spec/lib/banzai/filter/broadcast_message_sanitization_filter_spec.rb
index 317ac7ef854..1f65268bd3c 100644
--- a/spec/lib/banzai/filter/broadcast_message_sanitization_filter_spec.rb
+++ b/spec/lib/banzai/filter/broadcast_message_sanitization_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::BroadcastMessageSanitizationFilter do
+RSpec.describe Banzai::Filter::BroadcastMessageSanitizationFilter do
include FilterSpecHelper
it_behaves_like 'default whitelist'
diff --git a/spec/lib/banzai/filter/color_filter_spec.rb b/spec/lib/banzai/filter/color_filter_spec.rb
index f8931d37b99..dced3671323 100644
--- a/spec/lib/banzai/filter/color_filter_spec.rb
+++ b/spec/lib/banzai/filter/color_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::ColorFilter, lib: true do
+RSpec.describe Banzai::Filter::ColorFilter, lib: true do
include FilterSpecHelper
let(:color) { '#F00' }
diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
index 5cfb0e6e6f7..f04d3212437 100644
--- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::CommitRangeReferenceFilter do
+RSpec.describe Banzai::Filter::CommitRangeReferenceFilter do
include FilterSpecHelper
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
index 63ec597a0ba..925fd031d95 100644
--- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::CommitReferenceFilter do
+RSpec.describe Banzai::Filter::CommitReferenceFilter do
include FilterSpecHelper
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/lib/banzai/filter/commit_trailers_filter_spec.rb b/spec/lib/banzai/filter/commit_trailers_filter_spec.rb
index 192d00805e0..03a6cc34962 100644
--- a/spec/lib/banzai/filter/commit_trailers_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_trailers_filter_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'ffaker'
-describe Banzai::Filter::CommitTrailersFilter do
+RSpec.describe Banzai::Filter::CommitTrailersFilter do
include FilterSpecHelper
include CommitTrailersSpecHelper
diff --git a/spec/lib/banzai/filter/design_reference_filter_spec.rb b/spec/lib/banzai/filter/design_reference_filter_spec.rb
index 8a6c2e3b3f9..1b558754932 100644
--- a/spec/lib/banzai/filter/design_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/design_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::DesignReferenceFilter do
+RSpec.describe Banzai::Filter::DesignReferenceFilter do
include FilterSpecHelper
include DesignManagementTestHelpers
diff --git a/spec/lib/banzai/filter/emoji_filter_spec.rb b/spec/lib/banzai/filter/emoji_filter_spec.rb
index 4e163668a28..d78763b6939 100644
--- a/spec/lib/banzai/filter/emoji_filter_spec.rb
+++ b/spec/lib/banzai/filter/emoji_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::EmojiFilter do
+RSpec.describe Banzai::Filter::EmojiFilter do
include FilterSpecHelper
it 'replaces supported name emoji' do
diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
index a70c820f97a..7d8fb183dbb 100644
--- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::ExternalIssueReferenceFilter do
+RSpec.describe Banzai::Filter::ExternalIssueReferenceFilter do
include FilterSpecHelper
shared_examples_for "external issue tracker" do
diff --git a/spec/lib/banzai/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb
index 4b2500b31f7..630730dfc1a 100644
--- a/spec/lib/banzai/filter/external_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-shared_examples 'an external link with rel attribute' do
+RSpec.shared_examples 'an external link with rel attribute' do
it 'adds rel="nofollow" to external links' do
expect(doc.at_css('a')).to have_attribute('rel')
expect(doc.at_css('a')['rel']).to include 'nofollow'
@@ -19,7 +19,7 @@ shared_examples 'an external link with rel attribute' do
end
end
-describe Banzai::Filter::ExternalLinkFilter do
+RSpec.describe Banzai::Filter::ExternalLinkFilter do
include FilterSpecHelper
it 'ignores elements without an href attribute' do
diff --git a/spec/lib/banzai/filter/footnote_filter_spec.rb b/spec/lib/banzai/filter/footnote_filter_spec.rb
index c6dcb4e46fd..01b7319fab1 100644
--- a/spec/lib/banzai/filter/footnote_filter_spec.rb
+++ b/spec/lib/banzai/filter/footnote_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::FootnoteFilter do
+RSpec.describe Banzai::Filter::FootnoteFilter do
include FilterSpecHelper
# first[^1] and second[^second]
diff --git a/spec/lib/banzai/filter/front_matter_filter_spec.rb b/spec/lib/banzai/filter/front_matter_filter_spec.rb
index 1b5b1770615..3f966c94dd3 100644
--- a/spec/lib/banzai/filter/front_matter_filter_spec.rb
+++ b/spec/lib/banzai/filter/front_matter_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::FrontMatterFilter do
+RSpec.describe Banzai::Filter::FrontMatterFilter do
include FilterSpecHelper
it 'allows for `encoding:` before the front matter' do
diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
index 00d8b871224..2576dd1bf07 100644
--- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
+++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::GollumTagsFilter do
+RSpec.describe Banzai::Filter::GollumTagsFilter do
include FilterSpecHelper
let(:project) { create(:project) }
diff --git a/spec/lib/banzai/filter/html_entity_filter_spec.rb b/spec/lib/banzai/filter/html_entity_filter_spec.rb
index 6017380725d..d88fa21cde7 100644
--- a/spec/lib/banzai/filter/html_entity_filter_spec.rb
+++ b/spec/lib/banzai/filter/html_entity_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::HtmlEntityFilter do
+RSpec.describe Banzai::Filter::HtmlEntityFilter do
include FilterSpecHelper
let(:unescaped) { 'foo <strike attr="foo">&&amp;&</strike>' }
diff --git a/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb b/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb
index 6475fd14ce4..9f5aa558f24 100644
--- a/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb
+++ b/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::ImageLazyLoadFilter do
+RSpec.describe Banzai::Filter::ImageLazyLoadFilter do
include FilterSpecHelper
def image(path)
diff --git a/spec/lib/banzai/filter/image_link_filter_spec.rb b/spec/lib/banzai/filter/image_link_filter_spec.rb
index 011e3a1e2da..5c04f6b2b3e 100644
--- a/spec/lib/banzai/filter/image_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/image_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::ImageLinkFilter do
+RSpec.describe Banzai::Filter::ImageLinkFilter do
include FilterSpecHelper
def image(path)
diff --git a/spec/lib/banzai/filter/inline_diff_filter_spec.rb b/spec/lib/banzai/filter/inline_diff_filter_spec.rb
index c09065fb746..1ef00139db2 100644
--- a/spec/lib/banzai/filter/inline_diff_filter_spec.rb
+++ b/spec/lib/banzai/filter/inline_diff_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::InlineDiffFilter do
+RSpec.describe Banzai::Filter::InlineDiffFilter do
include FilterSpecHelper
it 'adds inline diff span tags for deletions when using square brackets' do
diff --git a/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb b/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb
index 28bf5bd3e92..8bdb24ab08c 100644
--- a/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb
+++ b/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::InlineGrafanaMetricsFilter do
+RSpec.describe Banzai::Filter::InlineGrafanaMetricsFilter do
include FilterSpecHelper
let_it_be(:project) { create(:project) }
diff --git a/spec/lib/banzai/filter/inline_metrics_filter_spec.rb b/spec/lib/banzai/filter/inline_metrics_filter_spec.rb
index 1546a5e88ed..9b0b95b9da2 100644
--- a/spec/lib/banzai/filter/inline_metrics_filter_spec.rb
+++ b/spec/lib/banzai/filter/inline_metrics_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::InlineMetricsFilter do
+RSpec.describe Banzai::Filter::InlineMetricsFilter do
include FilterSpecHelper
let(:params) { ['foo', 'bar', 12] }
diff --git a/spec/lib/banzai/filter/inline_metrics_redactor_filter_spec.rb b/spec/lib/banzai/filter/inline_metrics_redactor_filter_spec.rb
index 9d8cd729958..5387df1b0e7 100644
--- a/spec/lib/banzai/filter/inline_metrics_redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/inline_metrics_redactor_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::InlineMetricsRedactorFilter do
+RSpec.describe Banzai::Filter::InlineMetricsRedactorFilter do
include FilterSpecHelper
let_it_be(:project) { create(:project) }
diff --git a/spec/lib/banzai/filter/issuable_state_filter_spec.rb b/spec/lib/banzai/filter/issuable_state_filter_spec.rb
index 5950b6878ef..a3851fd7cca 100644
--- a/spec/lib/banzai/filter/issuable_state_filter_spec.rb
+++ b/spec/lib/banzai/filter/issuable_state_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::IssuableStateFilter do
+RSpec.describe Banzai::Filter::IssuableStateFilter do
include ActionView::Helpers::UrlHelper
include FilterSpecHelper
diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
index 603da2b4421..98955d5cde9 100644
--- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::IssueReferenceFilter do
+RSpec.describe Banzai::Filter::IssueReferenceFilter do
include FilterSpecHelper
include DesignManagementTestHelpers
diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb
index 0b697ab2040..dadf98d9b76 100644
--- a/spec/lib/banzai/filter/label_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'html/pipeline'
-describe Banzai::Filter::LabelReferenceFilter do
+RSpec.describe Banzai::Filter::LabelReferenceFilter do
include FilterSpecHelper
let(:project) { create(:project, :public, name: 'sample-project') }
diff --git a/spec/lib/banzai/filter/markdown_filter_spec.rb b/spec/lib/banzai/filter/markdown_filter_spec.rb
index d0a43564903..8d01a651651 100644
--- a/spec/lib/banzai/filter/markdown_filter_spec.rb
+++ b/spec/lib/banzai/filter/markdown_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::MarkdownFilter do
+RSpec.describe Banzai::Filter::MarkdownFilter do
include FilterSpecHelper
describe 'markdown engine from context' do
diff --git a/spec/lib/banzai/filter/math_filter_spec.rb b/spec/lib/banzai/filter/math_filter_spec.rb
index c8fd92edcdf..9f6688f4f7d 100644
--- a/spec/lib/banzai/filter/math_filter_spec.rb
+++ b/spec/lib/banzai/filter/math_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::MathFilter do
+RSpec.describe Banzai::Filter::MathFilter do
include FilterSpecHelper
it 'leaves regular inline code unchanged' do
diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
index 12ee952b10e..f24fcf98b1f 100644
--- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::MergeRequestReferenceFilter do
+RSpec.describe Banzai::Filter::MergeRequestReferenceFilter do
include FilterSpecHelper
let(:project) { create(:project, :public) }
diff --git a/spec/lib/banzai/filter/mermaid_filter_spec.rb b/spec/lib/banzai/filter/mermaid_filter_spec.rb
index ae6725cc14c..c9bfcffe98f 100644
--- a/spec/lib/banzai/filter/mermaid_filter_spec.rb
+++ b/spec/lib/banzai/filter/mermaid_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::MermaidFilter do
+RSpec.describe Banzai::Filter::MermaidFilter do
include FilterSpecHelper
it 'adds `js-render-mermaid` class to the `code` tag' do
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index 0c8413adcba..62b1711ee57 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::MilestoneReferenceFilter do
+RSpec.describe Banzai::Filter::MilestoneReferenceFilter do
include FilterSpecHelper
let(:parent_group) { create(:group, :public) }
diff --git a/spec/lib/banzai/filter/output_safety_spec.rb b/spec/lib/banzai/filter/output_safety_spec.rb
index 5ffe591c9a4..5b7b7298411 100644
--- a/spec/lib/banzai/filter/output_safety_spec.rb
+++ b/spec/lib/banzai/filter/output_safety_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::OutputSafety do
+RSpec.describe Banzai::Filter::OutputSafety do
subject do
Class.new do
include Banzai::Filter::OutputSafety
diff --git a/spec/lib/banzai/filter/plantuml_filter_spec.rb b/spec/lib/banzai/filter/plantuml_filter_spec.rb
index abe525ac47a..5ad94c74514 100644
--- a/spec/lib/banzai/filter/plantuml_filter_spec.rb
+++ b/spec/lib/banzai/filter/plantuml_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::PlantumlFilter do
+RSpec.describe Banzai::Filter::PlantumlFilter do
include FilterSpecHelper
it 'replaces plantuml pre tag with img tag' do
diff --git a/spec/lib/banzai/filter/project_reference_filter_spec.rb b/spec/lib/banzai/filter/project_reference_filter_spec.rb
index a054b79ec03..ac7a90a5893 100644
--- a/spec/lib/banzai/filter/project_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/project_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::ProjectReferenceFilter do
+RSpec.describe Banzai::Filter::ProjectReferenceFilter do
include FilterSpecHelper
def invalidate_reference(reference)
diff --git a/spec/lib/banzai/filter/reference_filter_spec.rb b/spec/lib/banzai/filter/reference_filter_spec.rb
index d889b0b832d..0875a911bfa 100644
--- a/spec/lib/banzai/filter/reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::ReferenceFilter do
+RSpec.describe Banzai::Filter::ReferenceFilter do
let(:project) { build_stubbed(:project) }
describe '#each_node' do
diff --git a/spec/lib/banzai/filter/reference_redactor_filter_spec.rb b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb
index 956bc85e53f..ac1cabb34cc 100644
--- a/spec/lib/banzai/filter/reference_redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::ReferenceRedactorFilter do
+RSpec.describe Banzai::Filter::ReferenceRedactorFilter do
include ActionView::Helpers::UrlHelper
include FilterSpecHelper
diff --git a/spec/lib/banzai/filter/repository_link_filter_spec.rb b/spec/lib/banzai/filter/repository_link_filter_spec.rb
index 81f93f885f7..815053aac2f 100644
--- a/spec/lib/banzai/filter/repository_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/repository_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::RepositoryLinkFilter do
+RSpec.describe Banzai::Filter::RepositoryLinkFilter do
include GitHelpers
include RepoHelpers
diff --git a/spec/lib/banzai/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb
index 607dc3fda47..09dcd5518ff 100644
--- a/spec/lib/banzai/filter/sanitization_filter_spec.rb
+++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::SanitizationFilter do
+RSpec.describe Banzai::Filter::SanitizationFilter do
include FilterSpecHelper
it_behaves_like 'default whitelist'
diff --git a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
index 62ce12406a2..f23fbc5be88 100644
--- a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::SnippetReferenceFilter do
+RSpec.describe Banzai::Filter::SnippetReferenceFilter do
include FilterSpecHelper
let(:project) { create(:project, :public) }
diff --git a/spec/lib/banzai/filter/spaced_link_filter_spec.rb b/spec/lib/banzai/filter/spaced_link_filter_spec.rb
index 98c38813144..2c64657d69d 100644
--- a/spec/lib/banzai/filter/spaced_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/spaced_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::SpacedLinkFilter do
+RSpec.describe Banzai::Filter::SpacedLinkFilter do
include FilterSpecHelper
let(:link) { '[example](page slug)' }
diff --git a/spec/lib/banzai/filter/suggestion_filter_spec.rb b/spec/lib/banzai/filter/suggestion_filter_spec.rb
index 9c4650b73de..7d6092e21e9 100644
--- a/spec/lib/banzai/filter/suggestion_filter_spec.rb
+++ b/spec/lib/banzai/filter/suggestion_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::SuggestionFilter do
+RSpec.describe Banzai::Filter::SuggestionFilter do
include FilterSpecHelper
let(:input) { %(<pre class="code highlight js-syntax-highlight suggestion"><code>foo\n</code></pre>) }
diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
index 5a844fb61e3..a2875fad421 100644
--- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
+++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::SyntaxHighlightFilter do
+RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
include FilterSpecHelper
shared_examples "XSS prevention" do |lang|
diff --git a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
index 05ef77c811a..2d17855707f 100644
--- a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
+++ b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::TableOfContentsFilter do
+RSpec.describe Banzai::Filter::TableOfContentsFilter do
include FilterSpecHelper
def header(level, text)
diff --git a/spec/lib/banzai/filter/table_of_contents_tag_filter_spec.rb b/spec/lib/banzai/filter/table_of_contents_tag_filter_spec.rb
index 20f32d7347d..56f36af5066 100644
--- a/spec/lib/banzai/filter/table_of_contents_tag_filter_spec.rb
+++ b/spec/lib/banzai/filter/table_of_contents_tag_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::TableOfContentsTagFilter do
+RSpec.describe Banzai::Filter::TableOfContentsTagFilter do
include FilterSpecHelper
context 'table of contents' do
diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb
index c366f774895..4e05efce690 100644
--- a/spec/lib/banzai/filter/upload_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::UploadLinkFilter do
+RSpec.describe Banzai::Filter::UploadLinkFilter do
def filter(doc, contexts = {})
contexts.reverse_merge!(
project: project,
diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb
index cd6b68343b5..d8de3e5cc11 100644
--- a/spec/lib/banzai/filter/user_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::UserReferenceFilter do
+RSpec.describe Banzai::Filter::UserReferenceFilter do
include FilterSpecHelper
def get_reference(user)
diff --git a/spec/lib/banzai/filter/video_link_filter_spec.rb b/spec/lib/banzai/filter/video_link_filter_spec.rb
index c324c36fe4d..32fbc6b687f 100644
--- a/spec/lib/banzai/filter/video_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/video_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::VideoLinkFilter do
+RSpec.describe Banzai::Filter::VideoLinkFilter do
def filter(doc, contexts = {})
contexts.reverse_merge!({
project: project
diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
index 827f38ef717..7a4464a2604 100644
--- a/spec/lib/banzai/filter/wiki_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Filter::WikiLinkFilter do
+RSpec.describe Banzai::Filter::WikiLinkFilter do
include FilterSpecHelper
let(:namespace) { build_stubbed(:namespace, name: "wiki_link_ns") }
diff --git a/spec/lib/banzai/filter_array_spec.rb b/spec/lib/banzai/filter_array_spec.rb
index bed41a80d29..47bc5633300 100644
--- a/spec/lib/banzai/filter_array_spec.rb
+++ b/spec/lib/banzai/filter_array_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::FilterArray do
+RSpec.describe Banzai::FilterArray do
describe '#insert_after' do
it 'inserts an element after a provided element' do
filters = described_class.new(%w(a b c))
diff --git a/spec/lib/banzai/issuable_extractor_spec.rb b/spec/lib/banzai/issuable_extractor_spec.rb
index 7fa6048c1c6..c4ee7160e12 100644
--- a/spec/lib/banzai/issuable_extractor_spec.rb
+++ b/spec/lib/banzai/issuable_extractor_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::IssuableExtractor do
+RSpec.describe Banzai::IssuableExtractor do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:extractor) { described_class.new(Banzai::RenderContext.new(project, user)) }
diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb
index aef11775e60..f8d7acd3148 100644
--- a/spec/lib/banzai/object_renderer_spec.rb
+++ b/spec/lib/banzai/object_renderer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ObjectRenderer do
+RSpec.describe Banzai::ObjectRenderer do
let(:project) { create(:project, :repository) }
let(:user) { project.owner }
let(:renderer) do
diff --git a/spec/lib/banzai/pipeline/broadcast_message_pipeline_spec.rb b/spec/lib/banzai/pipeline/broadcast_message_pipeline_spec.rb
index 9832b132b58..41a91c56f3b 100644
--- a/spec/lib/banzai/pipeline/broadcast_message_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/broadcast_message_pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Pipeline::BroadcastMessagePipeline do
+RSpec.describe Banzai::Pipeline::BroadcastMessagePipeline do
before do
stub_commonmark_sourcepos_disabled
end
diff --git a/spec/lib/banzai/pipeline/description_pipeline_spec.rb b/spec/lib/banzai/pipeline/description_pipeline_spec.rb
index 6778a273bba..82d4f883e0d 100644
--- a/spec/lib/banzai/pipeline/description_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/description_pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Pipeline::DescriptionPipeline do
+RSpec.describe Banzai::Pipeline::DescriptionPipeline do
let_it_be(:project) { create(:project) }
def parse(html)
diff --git a/spec/lib/banzai/pipeline/email_pipeline_spec.rb b/spec/lib/banzai/pipeline/email_pipeline_spec.rb
index 77186861225..c7a0b9fefa1 100644
--- a/spec/lib/banzai/pipeline/email_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/email_pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Pipeline::EmailPipeline do
+RSpec.describe Banzai::Pipeline::EmailPipeline do
describe '.filters' do
it 'returns the expected type' do
expect(described_class.filters).to be_kind_of(Banzai::FilterArray)
diff --git a/spec/lib/banzai/pipeline/emoji_pipeline_spec.rb b/spec/lib/banzai/pipeline/emoji_pipeline_spec.rb
index 744df3e0b96..6de9d65f1b2 100644
--- a/spec/lib/banzai/pipeline/emoji_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/emoji_pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Pipeline::EmojiPipeline do
+RSpec.describe Banzai::Pipeline::EmojiPipeline do
def parse(text)
described_class.to_html(text, {})
end
diff --git a/spec/lib/banzai/pipeline/full_pipeline_spec.rb b/spec/lib/banzai/pipeline/full_pipeline_spec.rb
index 4fa39da3eb4..423c1ef1f9a 100644
--- a/spec/lib/banzai/pipeline/full_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/full_pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Pipeline::FullPipeline do
+RSpec.describe Banzai::Pipeline::FullPipeline do
describe 'References' do
let(:project) { create(:project, :public) }
let(:issue) { create(:issue, project: project) }
diff --git a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
index 448422b15e3..c5459ce7403 100644
--- a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Pipeline::GfmPipeline do
+RSpec.describe Banzai::Pipeline::GfmPipeline do
describe 'integration between parsing regular and external issue references' do
let(:project) { create(:redmine_project, :public) }
diff --git a/spec/lib/banzai/pipeline/post_process_pipeline_spec.rb b/spec/lib/banzai/pipeline/post_process_pipeline_spec.rb
index ab72354edcf..d9f45769550 100644
--- a/spec/lib/banzai/pipeline/post_process_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/post_process_pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Pipeline::PostProcessPipeline do
+RSpec.describe Banzai::Pipeline::PostProcessPipeline do
context 'when a document only has upload links' do
it 'does not make any Gitaly calls', :request_store do
markdown = <<-MARKDOWN.strip_heredoc
diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
index b2c24284eb9..4af782c7d73 100644
--- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Pipeline::WikiPipeline do
+RSpec.describe Banzai::Pipeline::WikiPipeline do
let_it_be(:namespace) { create(:namespace, name: "wiki_link_ns") }
let_it_be(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) }
let_it_be(:wiki) { ProjectWiki.new(project, double(:user)) }
diff --git a/spec/lib/banzai/pipeline_spec.rb b/spec/lib/banzai/pipeline_spec.rb
index eeff7287ff5..7d4df2ca5ce 100644
--- a/spec/lib/banzai/pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Pipeline do
+RSpec.describe Banzai::Pipeline do
describe '.[]' do
subject { described_class[name] }
diff --git a/spec/lib/banzai/querying_spec.rb b/spec/lib/banzai/querying_spec.rb
index b7a235b0558..b76f6ec533c 100644
--- a/spec/lib/banzai/querying_spec.rb
+++ b/spec/lib/banzai/querying_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Querying do
+RSpec.describe Banzai::Querying do
describe '.css' do
it 'optimizes queries for elements with classes' do
document = double(:document)
diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb
index b1002c1db25..0eea51262ba 100644
--- a/spec/lib/banzai/reference_parser/base_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::BaseParser do
+RSpec.describe Banzai::ReferenceParser::BaseParser do
include ReferenceParserHelpers
let(:user) { create(:user) }
diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
index 7f7c750fe74..612ce6b93f1 100644
--- a/spec/lib/banzai/reference_parser/commit_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::CommitParser do
+RSpec.describe Banzai::ReferenceParser::CommitParser do
include ReferenceParserHelpers
let(:project) { create(:project, :public) }
diff --git a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
index 78b337466aa..2f64aef4fb7 100644
--- a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::CommitRangeParser do
+RSpec.describe Banzai::ReferenceParser::CommitRangeParser do
include ReferenceParserHelpers
let(:project) { create(:project, :public) }
diff --git a/spec/lib/banzai/reference_parser/design_parser_spec.rb b/spec/lib/banzai/reference_parser/design_parser_spec.rb
index 76708acf887..92d3a4aaad2 100644
--- a/spec/lib/banzai/reference_parser/design_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/design_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::DesignParser do
+RSpec.describe Banzai::ReferenceParser::DesignParser do
include ReferenceParserHelpers
include DesignManagementTestHelpers
diff --git a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
index 9343d52e44b..5f92eb42e74 100644
--- a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::ExternalIssueParser do
+RSpec.describe Banzai::ReferenceParser::ExternalIssueParser do
include ReferenceParserHelpers
let(:project) { create(:project, :public) }
diff --git a/spec/lib/banzai/reference_parser/issue_parser_spec.rb b/spec/lib/banzai/reference_parser/issue_parser_spec.rb
index ac321aca5e9..76f13e7b3aa 100644
--- a/spec/lib/banzai/reference_parser/issue_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/issue_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::IssueParser do
+RSpec.describe Banzai::ReferenceParser::IssueParser do
include ReferenceParserHelpers
let(:project) { create(:project, :public) }
diff --git a/spec/lib/banzai/reference_parser/label_parser_spec.rb b/spec/lib/banzai/reference_parser/label_parser_spec.rb
index 8b66a891e69..8f287e15b37 100644
--- a/spec/lib/banzai/reference_parser/label_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/label_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::LabelParser do
+RSpec.describe Banzai::ReferenceParser::LabelParser do
include ReferenceParserHelpers
let(:project) { create(:project, :public) }
diff --git a/spec/lib/banzai/reference_parser/mentioned_group_parser_spec.rb b/spec/lib/banzai/reference_parser/mentioned_group_parser_spec.rb
index 8346ba93f88..4610da7cbe6 100644
--- a/spec/lib/banzai/reference_parser/mentioned_group_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/mentioned_group_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::MentionedGroupParser do
+RSpec.describe Banzai::ReferenceParser::MentionedGroupParser do
include ReferenceParserHelpers
let(:group) { create(:group, :private) }
diff --git a/spec/lib/banzai/reference_parser/mentioned_project_parser_spec.rb b/spec/lib/banzai/reference_parser/mentioned_project_parser_spec.rb
index b99c02351d0..7eb58ee40d3 100644
--- a/spec/lib/banzai/reference_parser/mentioned_project_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/mentioned_project_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::MentionedProjectParser do
+RSpec.describe Banzai::ReferenceParser::MentionedProjectParser do
include ReferenceParserHelpers
let(:group) { create(:group, :private) }
diff --git a/spec/lib/banzai/reference_parser/mentioned_user_parser_spec.rb b/spec/lib/banzai/reference_parser/mentioned_user_parser_spec.rb
index b10e5d19828..4be07866db1 100644
--- a/spec/lib/banzai/reference_parser/mentioned_user_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/mentioned_user_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::MentionedUserParser do
+RSpec.describe Banzai::ReferenceParser::MentionedUserParser do
include ReferenceParserHelpers
let(:group) { create(:group, :private) }
diff --git a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
index cb65893aea0..32a9f09c3f6 100644
--- a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::MergeRequestParser do
+RSpec.describe Banzai::ReferenceParser::MergeRequestParser do
include ReferenceParserHelpers
let(:user) { create(:user) }
diff --git a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
index 25ba41dd8a0..95f71154e38 100644
--- a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::MilestoneParser do
+RSpec.describe Banzai::ReferenceParser::MilestoneParser do
include ReferenceParserHelpers
let(:project) { create(:project, :public) }
diff --git a/spec/lib/banzai/reference_parser/project_parser_spec.rb b/spec/lib/banzai/reference_parser/project_parser_spec.rb
index e87fa3e8767..6358a04f12a 100644
--- a/spec/lib/banzai/reference_parser/project_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/project_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::ProjectParser do
+RSpec.describe Banzai::ReferenceParser::ProjectParser do
include ReferenceParserHelpers
let(:project) { create(:project, :public) }
diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
index 6581ed0d7c3..cdc660b4f4a 100644
--- a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::SnippetParser do
+RSpec.describe Banzai::ReferenceParser::SnippetParser do
include ReferenceParserHelpers
let(:project) { create(:project, :public) }
diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb
index 71d2e1de3b6..d4f4339cf17 100644
--- a/spec/lib/banzai/reference_parser/user_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::UserParser do
+RSpec.describe Banzai::ReferenceParser::UserParser do
include ReferenceParserHelpers
let(:group) { create(:group) }
diff --git a/spec/lib/banzai/reference_redactor_spec.rb b/spec/lib/banzai/reference_redactor_spec.rb
index 0dec6395fb3..de774267b81 100644
--- a/spec/lib/banzai/reference_redactor_spec.rb
+++ b/spec/lib/banzai/reference_redactor_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::ReferenceRedactor do
+RSpec.describe Banzai::ReferenceRedactor do
let(:user) { create(:user) }
let(:project) { build(:project) }
let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) }
diff --git a/spec/lib/banzai/render_context_spec.rb b/spec/lib/banzai/render_context_spec.rb
index ad17db11613..c4b609b936e 100644
--- a/spec/lib/banzai/render_context_spec.rb
+++ b/spec/lib/banzai/render_context_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::RenderContext do
+RSpec.describe Banzai::RenderContext do
let(:document) { Nokogiri::HTML.fragment('<p>hello</p>') }
describe '#project_for_node' do
diff --git a/spec/lib/banzai/renderer_spec.rb b/spec/lib/banzai/renderer_spec.rb
index b540a76face..52bf3087875 100644
--- a/spec/lib/banzai/renderer_spec.rb
+++ b/spec/lib/banzai/renderer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Banzai::Renderer do
+RSpec.describe Banzai::Renderer do
let(:renderer) { described_class }
def fake_object(fresh:)
diff --git a/spec/lib/bitbucket/collection_spec.rb b/spec/lib/bitbucket/collection_spec.rb
index 5946be71565..349274585c4 100644
--- a/spec/lib/bitbucket/collection_spec.rb
+++ b/spec/lib/bitbucket/collection_spec.rb
@@ -17,7 +17,7 @@ class TestPaginator
end
end
-describe Bitbucket::Collection do
+RSpec.describe Bitbucket::Collection do
it "iterates paginator" do
collection = described_class.new(TestPaginator.new)
diff --git a/spec/lib/bitbucket/connection_spec.rb b/spec/lib/bitbucket/connection_spec.rb
index 5aca93767dc..bed44b94f44 100644
--- a/spec/lib/bitbucket/connection_spec.rb
+++ b/spec/lib/bitbucket/connection_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Bitbucket::Connection do
+RSpec.describe Bitbucket::Connection do
before do
allow_next_instance_of(described_class) do |instance|
allow(instance).to receive(:provider).and_return(double(app_id: '', app_secret: ''))
diff --git a/spec/lib/bitbucket/page_spec.rb b/spec/lib/bitbucket/page_spec.rb
index 6301dd56faf..1d599007d9e 100644
--- a/spec/lib/bitbucket/page_spec.rb
+++ b/spec/lib/bitbucket/page_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Bitbucket::Page do
+RSpec.describe Bitbucket::Page do
let(:response) { { 'values' => [{ 'username' => 'Ben' }], 'pagelen' => 2, 'next' => '' } }
before do
diff --git a/spec/lib/bitbucket/paginator_spec.rb b/spec/lib/bitbucket/paginator_spec.rb
index a1effa14000..e74af8a264b 100644
--- a/spec/lib/bitbucket/paginator_spec.rb
+++ b/spec/lib/bitbucket/paginator_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Bitbucket::Paginator do
+RSpec.describe Bitbucket::Paginator do
let(:last_page) { double(:page, next?: false, items: ['item_2']) }
let(:first_page) { double(:page, next?: true, next: last_page, items: ['item_1']) }
diff --git a/spec/lib/bitbucket/representation/comment_spec.rb b/spec/lib/bitbucket/representation/comment_spec.rb
index 1874296df8c..f6766ab685b 100644
--- a/spec/lib/bitbucket/representation/comment_spec.rb
+++ b/spec/lib/bitbucket/representation/comment_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Bitbucket::Representation::Comment do
+RSpec.describe Bitbucket::Representation::Comment do
describe '#author' do
it { expect(described_class.new('user' => { 'nickname' => 'Ben' }).author).to eq('Ben') }
it { expect(described_class.new({}).author).to be_nil }
diff --git a/spec/lib/bitbucket/representation/issue_spec.rb b/spec/lib/bitbucket/representation/issue_spec.rb
index 655b9b78b47..8c27086546f 100644
--- a/spec/lib/bitbucket/representation/issue_spec.rb
+++ b/spec/lib/bitbucket/representation/issue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Bitbucket::Representation::Issue do
+RSpec.describe Bitbucket::Representation::Issue do
describe '#iid' do
it { expect(described_class.new('id' => 1).iid).to eq(1) }
end
diff --git a/spec/lib/bitbucket/representation/pull_request_comment_spec.rb b/spec/lib/bitbucket/representation/pull_request_comment_spec.rb
index 151055f510f..cdab683492f 100644
--- a/spec/lib/bitbucket/representation/pull_request_comment_spec.rb
+++ b/spec/lib/bitbucket/representation/pull_request_comment_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Bitbucket::Representation::PullRequestComment do
+RSpec.describe Bitbucket::Representation::PullRequestComment do
describe '#iid' do
it { expect(described_class.new('id' => 1).iid).to eq(1) }
end
diff --git a/spec/lib/bitbucket/representation/pull_request_spec.rb b/spec/lib/bitbucket/representation/pull_request_spec.rb
index 6a9df0e5099..6f05d03aa0a 100644
--- a/spec/lib/bitbucket/representation/pull_request_spec.rb
+++ b/spec/lib/bitbucket/representation/pull_request_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Bitbucket::Representation::PullRequest do
+RSpec.describe Bitbucket::Representation::PullRequest do
describe '#iid' do
it { expect(described_class.new('id' => 1).iid).to eq(1) }
end
diff --git a/spec/lib/bitbucket/representation/repo_spec.rb b/spec/lib/bitbucket/representation/repo_spec.rb
index a272695e681..a779a153f25 100644
--- a/spec/lib/bitbucket/representation/repo_spec.rb
+++ b/spec/lib/bitbucket/representation/repo_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Bitbucket::Representation::Repo do
+RSpec.describe Bitbucket::Representation::Repo do
describe '#has_wiki?' do
it { expect(described_class.new({ 'has_wiki' => false }).has_wiki?).to be_falsey }
it { expect(described_class.new({ 'has_wiki' => true }).has_wiki?).to be_truthy }
diff --git a/spec/lib/bitbucket/representation/user_spec.rb b/spec/lib/bitbucket/representation/user_spec.rb
index 0169887a24c..e1f6c724da8 100644
--- a/spec/lib/bitbucket/representation/user_spec.rb
+++ b/spec/lib/bitbucket/representation/user_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Bitbucket::Representation::User do
+RSpec.describe Bitbucket::Representation::User do
describe '#username' do
it 'returns correct value' do
user = described_class.new('username' => 'Ben')
diff --git a/spec/lib/bitbucket_server/client_spec.rb b/spec/lib/bitbucket_server/client_spec.rb
index aa0217856ee..9dcd1500aab 100644
--- a/spec/lib/bitbucket_server/client_spec.rb
+++ b/spec/lib/bitbucket_server/client_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BitbucketServer::Client do
+RSpec.describe BitbucketServer::Client do
let(:base_uri) { 'https://test:7990/stash/' }
let(:options) { { base_uri: base_uri, user: 'bitbucket', password: 'mypassword' } }
let(:project) { 'SOME-PROJECT' }
diff --git a/spec/lib/bitbucket_server/collection_spec.rb b/spec/lib/bitbucket_server/collection_spec.rb
index ddd02bac88a..1a47a30c74b 100644
--- a/spec/lib/bitbucket_server/collection_spec.rb
+++ b/spec/lib/bitbucket_server/collection_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BitbucketServer::Collection do
+RSpec.describe BitbucketServer::Collection do
let(:connection) { instance_double(BitbucketServer::Connection) }
let(:page) { 1 }
let(:paginator) { BitbucketServer::Paginator.new(connection, 'http://more-data', :pull_request, page_offset: page) }
diff --git a/spec/lib/bitbucket_server/connection_spec.rb b/spec/lib/bitbucket_server/connection_spec.rb
index 3a7fe4e7321..873eded58d7 100644
--- a/spec/lib/bitbucket_server/connection_spec.rb
+++ b/spec/lib/bitbucket_server/connection_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BitbucketServer::Connection do
+RSpec.describe BitbucketServer::Connection do
let(:options) { { base_uri: 'https://test:7990', user: 'bitbucket', password: 'mypassword' } }
let(:payload) { { 'test' => 1 } }
let(:headers) { { "Content-Type" => "application/json" } }
diff --git a/spec/lib/bitbucket_server/page_spec.rb b/spec/lib/bitbucket_server/page_spec.rb
index 2da1d0995ca..2d4e946e590 100644
--- a/spec/lib/bitbucket_server/page_spec.rb
+++ b/spec/lib/bitbucket_server/page_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BitbucketServer::Page do
+RSpec.describe BitbucketServer::Page do
let(:response) { { 'values' => [{ 'description' => 'Test' }], 'isLastPage' => false, 'nextPageStart' => 2 } }
before do
diff --git a/spec/lib/bitbucket_server/paginator_spec.rb b/spec/lib/bitbucket_server/paginator_spec.rb
index e01cbeb4270..66bf5bf3f02 100644
--- a/spec/lib/bitbucket_server/paginator_spec.rb
+++ b/spec/lib/bitbucket_server/paginator_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BitbucketServer::Paginator do
+RSpec.describe BitbucketServer::Paginator do
let(:last_page) { double(:page, next?: false, items: ['item_2']) }
let(:first_page) { double(:page, next?: true, next: last_page, items: ['item_1']) }
let(:connection) { instance_double(BitbucketServer::Connection) }
diff --git a/spec/lib/bitbucket_server/representation/activity_spec.rb b/spec/lib/bitbucket_server/representation/activity_spec.rb
index 6988e77ad25..0b7e4542cbe 100644
--- a/spec/lib/bitbucket_server/representation/activity_spec.rb
+++ b/spec/lib/bitbucket_server/representation/activity_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BitbucketServer::Representation::Activity do
+RSpec.describe BitbucketServer::Representation::Activity do
let(:activities) { Gitlab::Json.parse(fixture_file('importers/bitbucket_server/activities.json'))['values'] }
let(:inline_comment) { activities.first }
let(:comment) { activities[3] }
diff --git a/spec/lib/bitbucket_server/representation/comment_spec.rb b/spec/lib/bitbucket_server/representation/comment_spec.rb
index ecaf6a843ae..b568789bd97 100644
--- a/spec/lib/bitbucket_server/representation/comment_spec.rb
+++ b/spec/lib/bitbucket_server/representation/comment_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BitbucketServer::Representation::Comment do
+RSpec.describe BitbucketServer::Representation::Comment do
let(:activities) { Gitlab::Json.parse(fixture_file('importers/bitbucket_server/activities.json'))['values'] }
let(:comment) { activities.first }
diff --git a/spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb b/spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb
index aa3eddf305a..01e56263a5e 100644
--- a/spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb
+++ b/spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BitbucketServer::Representation::PullRequestComment do
+RSpec.describe BitbucketServer::Representation::PullRequestComment do
let(:activities) { Gitlab::Json.parse(fixture_file('importers/bitbucket_server/activities.json'))['values'] }
let(:comment) { activities.second }
diff --git a/spec/lib/bitbucket_server/representation/pull_request_spec.rb b/spec/lib/bitbucket_server/representation/pull_request_spec.rb
index 7e72da05cb1..a05d98f0d4a 100644
--- a/spec/lib/bitbucket_server/representation/pull_request_spec.rb
+++ b/spec/lib/bitbucket_server/representation/pull_request_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BitbucketServer::Representation::PullRequest do
+RSpec.describe BitbucketServer::Representation::PullRequest do
let(:sample_data) { Gitlab::Json.parse(fixture_file('importers/bitbucket_server/pull_request.json')) }
subject { described_class.new(sample_data) }
diff --git a/spec/lib/bitbucket_server/representation/repo_spec.rb b/spec/lib/bitbucket_server/representation/repo_spec.rb
index 429b6d36c59..7a773f47ca5 100644
--- a/spec/lib/bitbucket_server/representation/repo_spec.rb
+++ b/spec/lib/bitbucket_server/representation/repo_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe BitbucketServer::Representation::Repo do
+RSpec.describe BitbucketServer::Representation::Repo do
let(:sample_data) do
<<~DATA
{
diff --git a/spec/lib/constraints/admin_constrainer_spec.rb b/spec/lib/constraints/admin_constrainer_spec.rb
index da178f9e71a..3efe683177c 100644
--- a/spec/lib/constraints/admin_constrainer_spec.rb
+++ b/spec/lib/constraints/admin_constrainer_spec.rb
@@ -2,7 +2,7 @@
#
require 'spec_helper'
-describe Constraints::AdminConstrainer, :do_not_mock_admin_mode do
+RSpec.describe Constraints::AdminConstrainer, :do_not_mock_admin_mode do
let(:user) { create(:user) }
let(:session) { {} }
diff --git a/spec/lib/constraints/feature_constrainer_spec.rb b/spec/lib/constraints/feature_constrainer_spec.rb
index 7665d5b3547..c98dc694186 100644
--- a/spec/lib/constraints/feature_constrainer_spec.rb
+++ b/spec/lib/constraints/feature_constrainer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Constraints::FeatureConstrainer do
+RSpec.describe Constraints::FeatureConstrainer do
describe '#matches' do
it 'calls Feature.enabled? with the correct arguments' do
gate = stub_feature_flag_gate("an object")
diff --git a/spec/lib/constraints/group_url_constrainer_spec.rb b/spec/lib/constraints/group_url_constrainer_spec.rb
index 573de331898..45a5b3afd81 100644
--- a/spec/lib/constraints/group_url_constrainer_spec.rb
+++ b/spec/lib/constraints/group_url_constrainer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Constraints::GroupUrlConstrainer do
+RSpec.describe Constraints::GroupUrlConstrainer do
let!(:group) { create(:group, path: 'gitlab') }
describe '#matches?' do
diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb
index 963e1d5b8e0..1e8aac8479d 100644
--- a/spec/lib/constraints/project_url_constrainer_spec.rb
+++ b/spec/lib/constraints/project_url_constrainer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Constraints::ProjectUrlConstrainer do
+RSpec.describe Constraints::ProjectUrlConstrainer do
let!(:project) { create(:project) }
let!(:namespace) { project.namespace }
diff --git a/spec/lib/constraints/user_url_constrainer_spec.rb b/spec/lib/constraints/user_url_constrainer_spec.rb
index 4f665def3bf..1b68e966585 100644
--- a/spec/lib/constraints/user_url_constrainer_spec.rb
+++ b/spec/lib/constraints/user_url_constrainer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Constraints::UserUrlConstrainer do
+RSpec.describe Constraints::UserUrlConstrainer do
let!(:user) { create(:user, username: 'dz') }
describe '#matches?' do
diff --git a/spec/lib/container_registry/blob_spec.rb b/spec/lib/container_registry/blob_spec.rb
index be7be2f3719..676adc74be2 100644
--- a/spec/lib/container_registry/blob_spec.rb
+++ b/spec/lib/container_registry/blob_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ContainerRegistry::Blob do
+RSpec.describe ContainerRegistry::Blob do
let(:group) { create(:group, name: 'group') }
let(:project) { create(:project, path: 'test', group: group) }
diff --git a/spec/lib/container_registry/client_spec.rb b/spec/lib/container_registry/client_spec.rb
index 18bcff65f41..de92ca5eeec 100644
--- a/spec/lib/container_registry/client_spec.rb
+++ b/spec/lib/container_registry/client_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ContainerRegistry::Client do
+RSpec.describe ContainerRegistry::Client do
let(:token) { '12345' }
let(:options) { { token: token } }
let(:client) { described_class.new("http://container-registry", options) }
diff --git a/spec/lib/container_registry/path_spec.rb b/spec/lib/container_registry/path_spec.rb
index 8c671b4d56d..aa6876225b5 100644
--- a/spec/lib/container_registry/path_spec.rb
+++ b/spec/lib/container_registry/path_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ContainerRegistry::Path do
+RSpec.describe ContainerRegistry::Path do
subject { described_class.new(path) }
describe '#components' do
diff --git a/spec/lib/container_registry/registry_spec.rb b/spec/lib/container_registry/registry_spec.rb
index e509566fae8..d6e2b17f53b 100644
--- a/spec/lib/container_registry/registry_spec.rb
+++ b/spec/lib/container_registry/registry_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ContainerRegistry::Registry do
+RSpec.describe ContainerRegistry::Registry do
let(:path) { nil }
let(:registry) { described_class.new('http://example.com', path: path) }
diff --git a/spec/lib/container_registry/tag_spec.rb b/spec/lib/container_registry/tag_spec.rb
index 085c73caa97..d696b61ac9d 100644
--- a/spec/lib/container_registry/tag_spec.rb
+++ b/spec/lib/container_registry/tag_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ContainerRegistry::Tag do
+RSpec.describe ContainerRegistry::Tag do
let(:group) { create(:group, name: 'group') }
let(:project) { create(:project, path: 'test', group: group) }
diff --git a/spec/lib/csv_builder_spec.rb b/spec/lib/csv_builder_spec.rb
index 0d5e2b81b16..546be3ba6f7 100644
--- a/spec/lib/csv_builder_spec.rb
+++ b/spec/lib/csv_builder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe CsvBuilder do
+RSpec.describe CsvBuilder do
let(:object) { double(question: :answer) }
let(:fake_relation) { FakeRelation.new([object]) }
let(:subject) { described_class.new(fake_relation, 'Q & A' => :question, 'Reversed' => -> (o) { o.question.to_s.reverse }) }
diff --git a/spec/lib/declarative_policy_spec.rb b/spec/lib/declarative_policy_spec.rb
index 5fdb3c27738..fc21bd43f48 100644
--- a/spec/lib/declarative_policy_spec.rb
+++ b/spec/lib/declarative_policy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe DeclarativePolicy do
+RSpec.describe DeclarativePolicy do
describe '.class_for' do
it 'uses declarative_policy_class if present' do
instance = Gitlab::ErrorTracking::ErrorEvent.new
diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb
index 42458d9c306..f2d3a99bb19 100644
--- a/spec/lib/event_filter_spec.rb
+++ b/spec/lib/event_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe EventFilter do
+RSpec.describe EventFilter do
describe '#filter' do
it 'returns "all" if given filter is nil' do
expect(described_class.new(nil).filter).to eq(described_class::ALL)
diff --git a/spec/lib/expand_variables_spec.rb b/spec/lib/expand_variables_spec.rb
index 1b8ec2b1979..4a5b70ff248 100644
--- a/spec/lib/expand_variables_spec.rb
+++ b/spec/lib/expand_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ExpandVariables do
+RSpec.describe ExpandVariables do
describe '#expand' do
context 'table tests' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index a56768a1a88..dbb3aa8797e 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ExtractsPath do
+RSpec.describe ExtractsPath do
include described_class
include RepoHelpers
include Gitlab::Routing
diff --git a/spec/lib/feature/gitaly_spec.rb b/spec/lib/feature/gitaly_spec.rb
index 6654b7627cd..a2181a63335 100644
--- a/spec/lib/feature/gitaly_spec.rb
+++ b/spec/lib/feature/gitaly_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Feature::Gitaly do
+RSpec.describe Feature::Gitaly do
let(:feature_flag) { "mep_mep" }
describe ".enabled?" do
diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb
index 37f8d3ad47d..658c0716510 100644
--- a/spec/lib/feature_spec.rb
+++ b/spec/lib/feature_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Feature, stub_feature_flags: false do
+RSpec.describe Feature, stub_feature_flags: false do
before do
# reset Flipper AR-engine
Feature.reset
diff --git a/spec/lib/file_size_validator_spec.rb b/spec/lib/file_size_validator_spec.rb
index 87376a98c60..c5cb7d6eb30 100644
--- a/spec/lib/file_size_validator_spec.rb
+++ b/spec/lib/file_size_validator_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe FileSizeValidator do
+RSpec.describe FileSizeValidator do
let(:validator) { described_class.new(options) }
let(:note) { create(:note) }
let(:attachment) { AttachmentUploader.new(note) }
diff --git a/spec/lib/forever_spec.rb b/spec/lib/forever_spec.rb
index 9f17308241b..6f6b3055df5 100644
--- a/spec/lib/forever_spec.rb
+++ b/spec/lib/forever_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Forever do
+RSpec.describe Forever do
describe '.date' do
subject { described_class.date }
diff --git a/spec/lib/gitaly/server_spec.rb b/spec/lib/gitaly/server_spec.rb
index 390855b30ad..83df4b28757 100644
--- a/spec/lib/gitaly/server_spec.rb
+++ b/spec/lib/gitaly/server_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitaly::Server do
+RSpec.describe Gitaly::Server do
let(:server) { described_class.new('default') }
describe '.all' do
diff --git a/spec/lib/gitlab/access/branch_protection_spec.rb b/spec/lib/gitlab/access/branch_protection_spec.rb
index e4b763357c4..9b736a30c7e 100644
--- a/spec/lib/gitlab/access/branch_protection_spec.rb
+++ b/spec/lib/gitlab/access/branch_protection_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Access::BranchProtection do
+RSpec.describe Gitlab::Access::BranchProtection do
describe '#any?' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/lib/gitlab/alert_management/alert_params_spec.rb b/spec/lib/gitlab/alert_management/alert_params_spec.rb
index 284af421f05..bb42caebb28 100644
--- a/spec/lib/gitlab/alert_management/alert_params_spec.rb
+++ b/spec/lib/gitlab/alert_management/alert_params_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::AlertManagement::AlertParams do
+RSpec.describe Gitlab::AlertManagement::AlertParams do
let_it_be(:project) { create(:project, :repository, :private) }
describe '.from_generic_alert' do
diff --git a/spec/lib/gitlab/alert_management/alert_status_counts_spec.rb b/spec/lib/gitlab/alert_management/alert_status_counts_spec.rb
index 728cbf11cda..4e471a8eac0 100644
--- a/spec/lib/gitlab/alert_management/alert_status_counts_spec.rb
+++ b/spec/lib/gitlab/alert_management/alert_status_counts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::AlertManagement::AlertStatusCounts do
+RSpec.describe Gitlab::AlertManagement::AlertStatusCounts do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:alert_1) { create(:alert_management_alert, :resolved, project: project) }
diff --git a/spec/lib/gitlab/alert_management/fingerprint_spec.rb b/spec/lib/gitlab/alert_management/fingerprint_spec.rb
index 7865d667f71..af1d1d82de2 100644
--- a/spec/lib/gitlab/alert_management/fingerprint_spec.rb
+++ b/spec/lib/gitlab/alert_management/fingerprint_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::AlertManagement::Fingerprint do
+RSpec.describe Gitlab::AlertManagement::Fingerprint do
using RSpec::Parameterized::TableSyntax
let_it_be(:alert) { create(:alert_management_alert) }
diff --git a/spec/lib/gitlab/alerting/alert_spec.rb b/spec/lib/gitlab/alerting/alert_spec.rb
index d582ff6f32a..9663e6af0d2 100644
--- a/spec/lib/gitlab/alerting/alert_spec.rb
+++ b/spec/lib/gitlab/alerting/alert_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Alerting::Alert do
+RSpec.describe Gitlab::Alerting::Alert do
let_it_be(:project) { create(:project) }
let(:alert) { build(:alerting_alert, project: project, payload: payload) }
diff --git a/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb b/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
index 889efae9585..a834d021ea7 100644
--- a/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
+++ b/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Alerting::NotificationPayloadParser do
+RSpec.describe Gitlab::Alerting::NotificationPayloadParser do
describe '.call' do
let(:starts_at) { Time.current.change(usec: 0) }
let(:payload) do
diff --git a/spec/lib/gitlab/allowable_spec.rb b/spec/lib/gitlab/allowable_spec.rb
index 4905cc4c3db..0535384be6e 100644
--- a/spec/lib/gitlab/allowable_spec.rb
+++ b/spec/lib/gitlab/allowable_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Allowable do
+RSpec.describe Gitlab::Allowable do
subject do
Class.new.include(described_class).new
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/base_query_builder_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/base_query_builder_spec.rb
index 250e2f16aec..80d3f82b404 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/base_query_builder_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/base_query_builder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do
let_it_be(:project) { create(:project, :empty_repo) }
let_it_be(:mr1) { create(:merge_request, target_project: project, source_project: project, allow_broken: true, created_at: 3.months.ago) }
let_it_be(:mr2) { create(:merge_request, target_project: project, source_project: project, allow_broken: true, created_at: 1.month.ago) }
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb
index 92ecec350ae..c1ea000eb7b 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::Median do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::Median do
let_it_be(:project) { create(:project, :repository) }
let(:query) { Project.joins(merge_requests: :metrics) }
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/records_fetcher_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/records_fetcher_spec.rb
index e3429b0ca57..b8f9dde4291 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/records_fetcher_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/records_fetcher_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::RecordsFetcher do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::RecordsFetcher do
around do |example|
Timecop.freeze { example.run }
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start_spec.rb
index 29c8d548754..fe390289ef6 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::CodeStageStart do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::CodeStageStart do
let(:subject) { described_class.new({}) }
let(:project) { create(:project) }
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created_spec.rb
index efdef91c5a2..5cc6b05407f 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::IssueCreated do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::IssueCreated do
it_behaves_like 'cycle analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit_spec.rb
index 50883e1c1e2..715ad5a8e7d 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::IssueFirstMentionedInCommit do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::IssueFirstMentionedInCommit do
it_behaves_like 'cycle analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end_spec.rb
index 85062db370a..56241194f36 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::IssueStageEnd do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::IssueStageEnd do
it_behaves_like 'cycle analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created_spec.rb
index 7858b810661..f3202eab5bb 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestCreated do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestCreated do
it_behaves_like 'cycle analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production_spec.rb
index ba9d8be5a2c..03b0ccfae43 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction do
it_behaves_like 'cycle analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished_spec.rb
index 8e83e10ef96..b0c003e6f2a 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildFinished do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildFinished do
it_behaves_like 'cycle analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb
index 9f6b430a320..8f9aaf6f463 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildStarted do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildStarted do
it_behaves_like 'cycle analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb
index ce2aa0a60db..f1d2ca9f36e 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged do
it_behaves_like 'cycle analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb
index cb63139f0a8..3248af524bd 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::PlanStageStart do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::PlanStageStart do
let(:subject) { described_class.new({}) }
let(:project) { create(:project) }
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
index b05faf5d813..6fc658ecade 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Analytics::CycleAnalytics::StageEvents::StageEvent do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::StageEvent do
let(:instance) { described_class.new({}) }
it { expect(described_class).to respond_to(:name) }
diff --git a/spec/lib/gitlab/anonymous_session_spec.rb b/spec/lib/gitlab/anonymous_session_spec.rb
index 94daa0f2470..0f0795cd9fc 100644
--- a/spec/lib/gitlab/anonymous_session_spec.rb
+++ b/spec/lib/gitlab/anonymous_session_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::AnonymousSession, :clean_gitlab_redis_shared_state do
+RSpec.describe Gitlab::AnonymousSession, :clean_gitlab_redis_shared_state do
let(:default_session_id) { '6919a6f1bb119dd7396fadc38fd18d0d' }
let(:additional_session_id) { '7919a6f1bb119dd7396fadc38fd18d0d' }
diff --git a/spec/lib/gitlab/app_json_logger_spec.rb b/spec/lib/gitlab/app_json_logger_spec.rb
index d11456236cc..89dce969522 100644
--- a/spec/lib/gitlab/app_json_logger_spec.rb
+++ b/spec/lib/gitlab/app_json_logger_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::AppJsonLogger do
+RSpec.describe Gitlab::AppJsonLogger do
subject { described_class.new('/dev/null') }
let(:hash_message) { { 'message' => 'Message', 'project_id' => '123' } }
diff --git a/spec/lib/gitlab/app_logger_spec.rb b/spec/lib/gitlab/app_logger_spec.rb
index 132a10b9409..166b1fda268 100644
--- a/spec/lib/gitlab/app_logger_spec.rb
+++ b/spec/lib/gitlab/app_logger_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::AppLogger do
+RSpec.describe Gitlab::AppLogger do
subject { described_class }
it 'builds a Gitlab::Logger object twice' do
diff --git a/spec/lib/gitlab/app_text_logger_spec.rb b/spec/lib/gitlab/app_text_logger_spec.rb
index c84b986ce40..04c2e946640 100644
--- a/spec/lib/gitlab/app_text_logger_spec.rb
+++ b/spec/lib/gitlab/app_text_logger_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::AppTextLogger do
+RSpec.describe Gitlab::AppTextLogger do
subject { described_class.new('/dev/null') }
let(:hash_message) { { message: 'Message', project_id: 123 } }
diff --git a/spec/lib/gitlab/application_context_spec.rb b/spec/lib/gitlab/application_context_spec.rb
index 3be967ac8a4..88f865adea7 100644
--- a/spec/lib/gitlab/application_context_spec.rb
+++ b/spec/lib/gitlab/application_context_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::ApplicationContext do
+RSpec.describe Gitlab::ApplicationContext do
describe '.with_context' do
it 'yields the block' do
expect { |b| described_class.with_context({}, &b) }.to yield_control
diff --git a/spec/lib/gitlab/application_rate_limiter_spec.rb b/spec/lib/gitlab/application_rate_limiter_spec.rb
index f1a0163d91c..14a7e25a2e8 100644
--- a/spec/lib/gitlab/application_rate_limiter_spec.rb
+++ b/spec/lib/gitlab/application_rate_limiter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::ApplicationRateLimiter, :clean_gitlab_redis_cache do
+RSpec.describe Gitlab::ApplicationRateLimiter, :clean_gitlab_redis_cache do
let(:redis) { double('redis') }
let(:user) { create(:user) }
let(:project) { create(:project) }
diff --git a/spec/lib/gitlab/asciidoc/include_processor_spec.rb b/spec/lib/gitlab/asciidoc/include_processor_spec.rb
index 2781319567c..067dcefb525 100644
--- a/spec/lib/gitlab/asciidoc/include_processor_spec.rb
+++ b/spec/lib/gitlab/asciidoc/include_processor_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'nokogiri'
-describe Gitlab::Asciidoc::IncludeProcessor do
+RSpec.describe Gitlab::Asciidoc::IncludeProcessor do
let_it_be(:project) { create(:project, :repository) }
let(:processor_context) do
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index 24528d79fa8..40a4ab3e173 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
require 'nokogiri'
module Gitlab
- describe Asciidoc do
+ RSpec.describe Asciidoc do
include FakeBlobHelpers
before do
diff --git a/spec/lib/gitlab/asset_proxy_spec.rb b/spec/lib/gitlab/asset_proxy_spec.rb
index e406917a5a4..73b101c0dd8 100644
--- a/spec/lib/gitlab/asset_proxy_spec.rb
+++ b/spec/lib/gitlab/asset_proxy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::AssetProxy do
+RSpec.describe Gitlab::AssetProxy do
context 'when asset proxy is disabled' do
before do
stub_asset_proxy_setting(enabled: false)
diff --git a/spec/lib/gitlab/auth/activity_spec.rb b/spec/lib/gitlab/auth/activity_spec.rb
index e03fafe3826..cbc42c46470 100644
--- a/spec/lib/gitlab/auth/activity_spec.rb
+++ b/spec/lib/gitlab/auth/activity_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Auth::Activity do
+RSpec.describe Gitlab::Auth::Activity do
describe '.each_counter' do
it 'has all static counters defined' do
described_class.each_counter do |counter|
diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb
index 2aef206c7fd..c74e3eb3970 100644
--- a/spec/lib/gitlab/auth/auth_finders_spec.rb
+++ b/spec/lib/gitlab/auth/auth_finders_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::AuthFinders do
+RSpec.describe Gitlab::Auth::AuthFinders do
include described_class
include HttpBasicAuthHelpers
diff --git a/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb b/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb
index 52849f8c172..76775db3a4a 100644
--- a/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb
+++ b/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::BlockedUserTracker do
+RSpec.describe Gitlab::Auth::BlockedUserTracker do
describe '#log_blocked_user_activity!' do
context 'when user is not blocked' do
it 'does not log blocked user activity' do
diff --git a/spec/lib/gitlab/auth/current_user_mode_spec.rb b/spec/lib/gitlab/auth/current_user_mode_spec.rb
index 26e44fa7cc8..60b403780c0 100644
--- a/spec/lib/gitlab/auth/current_user_mode_spec.rb
+++ b/spec/lib/gitlab/auth/current_user_mode_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::CurrentUserMode, :do_not_mock_admin_mode, :request_store do
+RSpec.describe Gitlab::Auth::CurrentUserMode, :do_not_mock_admin_mode, :request_store do
let(:user) { build_stubbed(:user) }
subject { described_class.new(user) }
diff --git a/spec/lib/gitlab/auth/ip_rate_limiter_spec.rb b/spec/lib/gitlab/auth/ip_rate_limiter_spec.rb
index aea1b2921b6..3d782272d7e 100644
--- a/spec/lib/gitlab/auth/ip_rate_limiter_spec.rb
+++ b/spec/lib/gitlab/auth/ip_rate_limiter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::IpRateLimiter, :use_clean_rails_memory_store_caching do
+RSpec.describe Gitlab::Auth::IpRateLimiter, :use_clean_rails_memory_store_caching do
let(:ip) { '10.2.2.3' }
let(:whitelist) { ['127.0.0.1'] }
let(:options) do
diff --git a/spec/lib/gitlab/auth/key_status_checker_spec.rb b/spec/lib/gitlab/auth/key_status_checker_spec.rb
index b1a540eae81..e8ac0d7c394 100644
--- a/spec/lib/gitlab/auth/key_status_checker_spec.rb
+++ b/spec/lib/gitlab/auth/key_status_checker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::KeyStatusChecker do
+RSpec.describe Gitlab::Auth::KeyStatusChecker do
let_it_be(:never_expires_key) { build(:personal_key, expires_at: nil) }
let_it_be(:expired_key) { build(:personal_key, expires_at: 3.days.ago) }
let_it_be(:expiring_soon_key) { build(:personal_key, expires_at: 3.days.from_now) }
diff --git a/spec/lib/gitlab/auth/ldap/access_spec.rb b/spec/lib/gitlab/auth/ldap/access_spec.rb
index 2f691429541..9e269f84b7e 100644
--- a/spec/lib/gitlab/auth/ldap/access_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Ldap::Access do
+RSpec.describe Gitlab::Auth::Ldap::Access do
include LdapHelpers
let(:user) { create(:omniauth_user) }
diff --git a/spec/lib/gitlab/auth/ldap/adapter_spec.rb b/spec/lib/gitlab/auth/ldap/adapter_spec.rb
index 34853acdd0f..78970378b7f 100644
--- a/spec/lib/gitlab/auth/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/adapter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Ldap::Adapter do
+RSpec.describe Gitlab::Auth::Ldap::Adapter do
include LdapHelpers
let(:ldap) { double(:ldap) }
diff --git a/spec/lib/gitlab/auth/ldap/auth_hash_spec.rb b/spec/lib/gitlab/auth/ldap/auth_hash_spec.rb
index 7bc92d0abea..9dff7f7b3dc 100644
--- a/spec/lib/gitlab/auth/ldap/auth_hash_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/auth_hash_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Ldap::AuthHash do
+RSpec.describe Gitlab::Auth::Ldap::AuthHash do
include LdapHelpers
let(:auth_hash) do
diff --git a/spec/lib/gitlab/auth/ldap/authentication_spec.rb b/spec/lib/gitlab/auth/ldap/authentication_spec.rb
index 1f8b1474539..42a893417d8 100644
--- a/spec/lib/gitlab/auth/ldap/authentication_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/authentication_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Ldap::Authentication do
+RSpec.describe Gitlab::Auth::Ldap::Authentication do
let(:dn) { 'uid=John Smith, ou=People, dc=example, dc=com' }
let(:user) { create(:omniauth_user, extern_uid: Gitlab::Auth::Ldap::Person.normalize_dn(dn)) }
let(:login) { 'john' }
diff --git a/spec/lib/gitlab/auth/ldap/config_spec.rb b/spec/lib/gitlab/auth/ldap/config_spec.rb
index 124f072ebe6..4287596af8f 100644
--- a/spec/lib/gitlab/auth/ldap/config_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/config_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Ldap::Config do
+RSpec.describe Gitlab::Auth::Ldap::Config do
include LdapHelpers
let(:config) { described_class.new('ldapmain') }
diff --git a/spec/lib/gitlab/auth/ldap/dn_spec.rb b/spec/lib/gitlab/auth/ldap/dn_spec.rb
index 7aaffa52ae4..e89f764b040 100644
--- a/spec/lib/gitlab/auth/ldap/dn_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/dn_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Ldap::DN do
+RSpec.describe Gitlab::Auth::Ldap::DN do
using RSpec::Parameterized::TableSyntax
describe '#normalize_value' do
diff --git a/spec/lib/gitlab/auth/ldap/person_spec.rb b/spec/lib/gitlab/auth/ldap/person_spec.rb
index 403a48d40ef..6857b561370 100644
--- a/spec/lib/gitlab/auth/ldap/person_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/person_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Ldap::Person do
+RSpec.describe Gitlab::Auth::Ldap::Person do
include LdapHelpers
let(:entry) { ldap_user_entry('john.doe') }
diff --git a/spec/lib/gitlab/auth/ldap/user_spec.rb b/spec/lib/gitlab/auth/ldap/user_spec.rb
index 867633e54df..7ca2878e583 100644
--- a/spec/lib/gitlab/auth/ldap/user_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/user_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Ldap::User do
+RSpec.describe Gitlab::Auth::Ldap::User do
include LdapHelpers
let(:ldap_user) { described_class.new(auth_hash) }
diff --git a/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb
index a2d9e27ea5b..7a60acca95b 100644
--- a/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::OAuth::AuthHash do
+RSpec.describe Gitlab::Auth::OAuth::AuthHash do
let(:provider) { 'ldap'.freeze }
let(:auth_hash) do
described_class.new(
diff --git a/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb b/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb
index 45c1baa4089..8014fbe1687 100644
--- a/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::OAuth::IdentityLinker do
+RSpec.describe Gitlab::Auth::OAuth::IdentityLinker do
let(:user) { create(:user) }
let(:provider) { 'twitter' }
let(:uid) { user.email }
diff --git a/spec/lib/gitlab/auth/o_auth/provider_spec.rb b/spec/lib/gitlab/auth/o_auth/provider_spec.rb
index 8b0d4d786cd..658a9976cc2 100644
--- a/spec/lib/gitlab/auth/o_auth/provider_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/provider_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::OAuth::Provider do
+RSpec.describe Gitlab::Auth::OAuth::Provider do
describe '.enabled?' do
before do
allow(described_class).to receive(:providers).and_return([:ldapmain, :google_oauth2])
diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb
index 62b83ff8b88..ad04fddc675 100644
--- a/spec/lib/gitlab/auth/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::OAuth::User do
+RSpec.describe Gitlab::Auth::OAuth::User do
include LdapHelpers
let(:oauth_user) { described_class.new(auth_hash) }
diff --git a/spec/lib/gitlab/auth/request_authenticator_spec.rb b/spec/lib/gitlab/auth/request_authenticator_spec.rb
index 87c96803c3a..32d64519e2c 100644
--- a/spec/lib/gitlab/auth/request_authenticator_spec.rb
+++ b/spec/lib/gitlab/auth/request_authenticator_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::RequestAuthenticator do
+RSpec.describe Gitlab::Auth::RequestAuthenticator do
let(:env) do
{
'rack.input' => '',
diff --git a/spec/lib/gitlab/auth/saml/auth_hash_spec.rb b/spec/lib/gitlab/auth/saml/auth_hash_spec.rb
index 8b88c16f317..f1fad946f35 100644
--- a/spec/lib/gitlab/auth/saml/auth_hash_spec.rb
+++ b/spec/lib/gitlab/auth/saml/auth_hash_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Saml::AuthHash do
+RSpec.describe Gitlab::Auth::Saml::AuthHash do
include LoginHelpers
let(:raw_info_attr) { { 'groups' => %w(Developers Freelancers) } }
diff --git a/spec/lib/gitlab/auth/saml/identity_linker_spec.rb b/spec/lib/gitlab/auth/saml/identity_linker_spec.rb
index 7912c8fb4b1..743163ad315 100644
--- a/spec/lib/gitlab/auth/saml/identity_linker_spec.rb
+++ b/spec/lib/gitlab/auth/saml/identity_linker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Saml::IdentityLinker do
+RSpec.describe Gitlab::Auth::Saml::IdentityLinker do
let(:user) { create(:user) }
let(:provider) { 'saml' }
let(:uid) { user.email }
diff --git a/spec/lib/gitlab/auth/saml/origin_validator_spec.rb b/spec/lib/gitlab/auth/saml/origin_validator_spec.rb
index ae120b328ab..f13140cdcba 100644
--- a/spec/lib/gitlab/auth/saml/origin_validator_spec.rb
+++ b/spec/lib/gitlab/auth/saml/origin_validator_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Saml::OriginValidator do
+RSpec.describe Gitlab::Auth::Saml::OriginValidator do
let(:session) { instance_double(ActionDispatch::Request::Session) }
subject { described_class.new(session) }
diff --git a/spec/lib/gitlab/auth/saml/user_spec.rb b/spec/lib/gitlab/auth/saml/user_spec.rb
index 55d2f22b923..7f8346f0486 100644
--- a/spec/lib/gitlab/auth/saml/user_spec.rb
+++ b/spec/lib/gitlab/auth/saml/user_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::Saml::User do
+RSpec.describe Gitlab::Auth::Saml::User do
include LdapHelpers
include LoginHelpers
diff --git a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
index ebf7de9c701..a08055ab852 100644
--- a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
+++ b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::UniqueIpsLimiter, :clean_gitlab_redis_shared_state do
+RSpec.describe Gitlab::Auth::UniqueIpsLimiter, :clean_gitlab_redis_shared_state do
include_context 'unique ips sign in limit'
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb b/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
index 7045105a2c7..a2a0eb5428a 100644
--- a/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
+++ b/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth::UserAccessDeniedReason do
+RSpec.describe Gitlab::Auth::UserAccessDeniedReason do
include TermsHelper
let(:user) { build(:user) }
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 5f80f1ee38e..0b391c8cba9 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
+RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
let_it_be(:project) { create(:project) }
let(:gl_auth) { described_class }
diff --git a/spec/lib/gitlab/authorized_keys_spec.rb b/spec/lib/gitlab/authorized_keys_spec.rb
index d89eb9ef114..1053ae2e325 100644
--- a/spec/lib/gitlab/authorized_keys_spec.rb
+++ b/spec/lib/gitlab/authorized_keys_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::AuthorizedKeys do
+RSpec.describe Gitlab::AuthorizedKeys do
let(:logger) { double('logger').as_null_object }
subject(:authorized_keys) { described_class.new(logger) }
diff --git a/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb b/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb
index b77c67b120f..589f6a322d7 100644
--- a/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb
+++ b/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::AddMergeRequestDiffCommitsCount, schema: 20180105212544 do
+RSpec.describe Gitlab::BackgroundMigration::AddMergeRequestDiffCommitsCount, schema: 20180105212544 do
let(:projects_table) { table(:projects) }
let(:merge_requests_table) { table(:merge_requests) }
let(:merge_request_diffs_table) { table(:merge_request_diffs) }
diff --git a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb
index 5c8dcb38511..b08a118d4c3 100644
--- a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb
+++ b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::ArchiveLegacyTraces, schema: 20180529152628 do
+RSpec.describe Gitlab::BackgroundMigration::ArchiveLegacyTraces, schema: 20180529152628 do
include TraceHelpers
let(:namespaces) { table(:namespaces) }
diff --git a/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb b/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb
index fdabc8e8f7c..2be9c03e5bd 100644
--- a/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::BackfillDeploymentClustersFromDeployments, :migration, schema: 20200227140242 do
+RSpec.describe Gitlab::BackgroundMigration::BackfillDeploymentClustersFromDeployments, :migration, schema: 20200227140242 do
subject { described_class.new }
describe '#perform' do
diff --git a/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb b/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb
index 34ac70071bb..550bdc484c9 100644
--- a/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::BackfillEnvironmentIdDeploymentMergeRequests, schema: 20200312134637 do
+RSpec.describe Gitlab::BackgroundMigration::BackfillEnvironmentIdDeploymentMergeRequests, schema: 20200312134637 do
let(:environments) { table(:environments) }
let(:merge_requests) { table(:merge_requests) }
let(:deployments) { table(:deployments) }
diff --git a/spec/lib/gitlab/background_migration/backfill_hashed_project_repositories_spec.rb b/spec/lib/gitlab/background_migration/backfill_hashed_project_repositories_spec.rb
index f64c3ccc058..965835ec84b 100644
--- a/spec/lib/gitlab/background_migration/backfill_hashed_project_repositories_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_hashed_project_repositories_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::BackfillHashedProjectRepositories, schema: 20181130102132 do
+RSpec.describe Gitlab::BackgroundMigration::BackfillHashedProjectRepositories, schema: 20181130102132 do
it_behaves_like 'backfill migration for project repositories', :hashed
end
diff --git a/spec/lib/gitlab/background_migration/backfill_legacy_project_repositories_spec.rb b/spec/lib/gitlab/background_migration/backfill_legacy_project_repositories_spec.rb
index 806d044ab40..47514f95b85 100644
--- a/spec/lib/gitlab/background_migration/backfill_legacy_project_repositories_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_legacy_project_repositories_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::BackfillLegacyProjectRepositories, schema: 20181212171634 do
+RSpec.describe Gitlab::BackgroundMigration::BackfillLegacyProjectRepositories, schema: 20181212171634 do
it_behaves_like 'backfill migration for project repositories', :legacy
end
diff --git a/spec/lib/gitlab/background_migration/backfill_project_fullpath_in_repo_config_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_fullpath_in_repo_config_spec.rb
index 44f5c3380a1..5f76da66545 100644
--- a/spec/lib/gitlab/background_migration/backfill_project_fullpath_in_repo_config_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_project_fullpath_in_repo_config_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::BackfillProjectFullpathInRepoConfig, schema: 20181010133639 do
+RSpec.describe Gitlab::BackgroundMigration::BackfillProjectFullpathInRepoConfig, schema: 20181010133639 do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:group) { namespaces.create!(name: 'foo', path: 'foo') }
diff --git a/spec/lib/gitlab/background_migration/backfill_project_repositories_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_repositories_spec.rb
index cfaef1578a9..8a8edc1af29 100644
--- a/spec/lib/gitlab/background_migration/backfill_project_repositories_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_project_repositories_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
# rubocop:disable RSpec/FactoriesInMigrationSpecs
-describe Gitlab::BackgroundMigration::BackfillProjectRepositories do
+RSpec.describe Gitlab::BackgroundMigration::BackfillProjectRepositories do
let(:group) { create(:group, name: 'foo', path: 'foo') }
describe described_class::ShardFinder do
diff --git a/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb
index a2b4e003d82..4e7a3a33f7e 100644
--- a/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::BackfillProjectSettings, schema: 20200114113341 do
+RSpec.describe Gitlab::BackgroundMigration::BackfillProjectSettings, schema: 20200114113341 do
let(:projects) { table(:projects) }
let(:project_settings) { table(:project_settings) }
let(:namespace) { table(:namespaces).create(name: 'user', path: 'user') }
diff --git a/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb b/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb
index f150ed4bd2e..39b49d008d4 100644
--- a/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::BackfillPushRulesIdInProjects, :migration, schema: 2020_03_25_162730 do
+RSpec.describe Gitlab::BackgroundMigration::BackfillPushRulesIdInProjects, :migration, schema: 2020_03_25_162730 do
let(:push_rules) { table(:push_rules) }
let(:projects) { table(:projects) }
let(:project_settings) { table(:project_settings) }
diff --git a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb
index 27ae60eb278..dcf0229bce9 100644
--- a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migration, schema: 2020_04_20_094444 do
+RSpec.describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migration, schema: 2020_04_20_094444 do
let(:gitlab_shell) { Gitlab::Shell.new }
let(:users) { table(:users) }
let(:snippets) { table(:snippets) }
diff --git a/spec/lib/gitlab/background_migration/digest_column_spec.rb b/spec/lib/gitlab/background_migration/digest_column_spec.rb
index 0c76ebe9c66..a0f904df0d6 100644
--- a/spec/lib/gitlab/background_migration/digest_column_spec.rb
+++ b/spec/lib/gitlab/background_migration/digest_column_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::DigestColumn, schema: 20180913142237 do
+RSpec.describe Gitlab::BackgroundMigration::DigestColumn, schema: 20180913142237 do
let(:personal_access_tokens) { table(:personal_access_tokens) }
let(:users) { table(:users) }
diff --git a/spec/lib/gitlab/background_migration/encrypt_columns_spec.rb b/spec/lib/gitlab/background_migration/encrypt_columns_spec.rb
index 6d3ccde7df2..36a1e4c8b9c 100644
--- a/spec/lib/gitlab/background_migration/encrypt_columns_spec.rb
+++ b/spec/lib/gitlab/background_migration/encrypt_columns_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::EncryptColumns, schema: 20180910115836 do
+RSpec.describe Gitlab::BackgroundMigration::EncryptColumns, schema: 20180910115836 do
let(:model) { Gitlab::BackgroundMigration::Models::EncryptColumns::WebHook }
let(:web_hooks) { table(:web_hooks) }
diff --git a/spec/lib/gitlab/background_migration/encrypt_runners_tokens_spec.rb b/spec/lib/gitlab/background_migration/encrypt_runners_tokens_spec.rb
index 89262788d9b..8a2c2414edc 100644
--- a/spec/lib/gitlab/background_migration/encrypt_runners_tokens_spec.rb
+++ b/spec/lib/gitlab/background_migration/encrypt_runners_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::EncryptRunnersTokens, schema: 20181121111200 do
+RSpec.describe Gitlab::BackgroundMigration::EncryptRunnersTokens, schema: 20181121111200 do
let(:settings) { table(:application_settings) }
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
diff --git a/spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb b/spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb
index cc4ce023f04..cb824880621 100644
--- a/spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb
+++ b/spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::FixCrossProjectLabelLinks, schema: 20180702120647 do
+RSpec.describe Gitlab::BackgroundMigration::FixCrossProjectLabelLinks, schema: 20180702120647 do
let(:namespaces_table) { table(:namespaces) }
let(:projects_table) { table(:projects) }
let(:issues_table) { table(:issues) }
diff --git a/spec/lib/gitlab/background_migration/fix_projects_without_project_feature_spec.rb b/spec/lib/gitlab/background_migration/fix_projects_without_project_feature_spec.rb
index 056ddd7adf9..e2175c41513 100644
--- a/spec/lib/gitlab/background_migration/fix_projects_without_project_feature_spec.rb
+++ b/spec/lib/gitlab/background_migration/fix_projects_without_project_feature_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::FixProjectsWithoutProjectFeature, schema: 2020_01_27_111840 do
+RSpec.describe Gitlab::BackgroundMigration::FixProjectsWithoutProjectFeature, schema: 2020_01_27_111840 do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:project_features) { table(:project_features) }
diff --git a/spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb b/spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb
index 3c3e37df200..fe2b206ea74 100644
--- a/spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb
+++ b/spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::FixProjectsWithoutPrometheusService, :migration, schema: 2020_02_20_115023 do
+RSpec.describe Gitlab::BackgroundMigration::FixProjectsWithoutPrometheusService, :migration, schema: 2020_02_20_115023 do
def service_params_for(project_id, params = {})
{
project_id: project_id,
diff --git a/spec/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids_spec.rb b/spec/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids_spec.rb
index 141a0af6c29..452fc962c7b 100644
--- a/spec/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids_spec.rb
+++ b/spec/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::FixPromotedEpicsDiscussionIds, schema: 20190715193142 do
+RSpec.describe Gitlab::BackgroundMigration::FixPromotedEpicsDiscussionIds, schema: 20190715193142 do
let(:namespaces) { table(:namespaces) }
let(:users) { table(:users) }
let(:epics) { table(:epics) }
diff --git a/spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb b/spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb
index 52760cdd115..7768411828c 100644
--- a/spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb
+++ b/spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::FixUserNamespaceNames, schema: 20190620112608 do
+RSpec.describe Gitlab::BackgroundMigration::FixUserNamespaceNames, schema: 20190620112608 do
let(:namespaces) { table(:namespaces) }
let(:users) { table(:users) }
let(:user) { users.create(name: "The user's full name", projects_limit: 10, username: 'not-null', email: '1') }
diff --git a/spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb b/spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb
index 0fb7eea2bd7..4c04043ebd0 100644
--- a/spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb
+++ b/spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::FixUserProjectRouteNames, schema: 20190620112608 do
+RSpec.describe Gitlab::BackgroundMigration::FixUserProjectRouteNames, schema: 20190620112608 do
let(:namespaces) { table(:namespaces) }
let(:users) { table(:users) }
let(:routes) { table(:routes) }
diff --git a/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb b/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
index 850ef48d44a..bf793e7c537 100644
--- a/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
+++ b/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
# rubocop: disable RSpec/FactoriesInMigrationSpecs
-describe Gitlab::BackgroundMigration::LegacyUploadMover do
+RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover do
let(:test_dir) { FileUploader.options['storage_path'] }
let(:filename) { 'image.png' }
diff --git a/spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb b/spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb
index 85187d039c1..66a1787b2cb 100644
--- a/spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb
+++ b/spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
# rubocop: disable RSpec/FactoriesInMigrationSpecs
-describe Gitlab::BackgroundMigration::LegacyUploadsMigrator do
+RSpec.describe Gitlab::BackgroundMigration::LegacyUploadsMigrator do
let(:test_dir) { FileUploader.options['storage_path'] }
let!(:hashed_project) { create(:project) }
diff --git a/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb b/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb
index 5700cac2e0f..dda4f5a3a36 100644
--- a/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb
+++ b/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::LinkLfsObjectsProjects, :migration, schema: 2020_03_10_075115 do
+RSpec.describe Gitlab::BackgroundMigration::LinkLfsObjectsProjects, :migration, schema: 2020_03_10_075115 do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:fork_networks) { table(:fork_networks) }
diff --git a/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb b/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb
index 9dd97b58014..a3840e3a22e 100644
--- a/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb
+++ b/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::MergeRequestAssigneesMigrationProgressCheck do
+RSpec.describe Gitlab::BackgroundMigration::MergeRequestAssigneesMigrationProgressCheck do
context 'rescheduling' do
context 'when there are ongoing and no dead jobs' do
it 'reschedules check' do
diff --git a/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb b/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb
index adf358f5320..2373e8aad48 100644
--- a/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::MigrateBuildStage, schema: 20180212101928 do
+RSpec.describe Gitlab::BackgroundMigration::MigrateBuildStage, schema: 20180212101928 do
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
let(:stages) { table(:ci_stages) }
diff --git a/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb b/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb
index 79a8cd926a7..c58b2d609e9 100644
--- a/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::MigrateFingerprintSha256WithinKeys, schema: 20200106071113 do
+RSpec.describe Gitlab::BackgroundMigration::MigrateFingerprintSha256WithinKeys, schema: 20200106071113 do
subject(:fingerprint_migrator) { described_class.new }
let(:key_table) { table(:keys) }
diff --git a/spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb b/spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb
index 4411dca3fd9..d53f79c61c1 100644
--- a/spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-describe Gitlab::BackgroundMigration::MigrateIssueTrackersSensitiveData, schema: 20200130145430 do
+RSpec.describe Gitlab::BackgroundMigration::MigrateIssueTrackersSensitiveData, schema: 20200130145430 do
let(:services) { table(:services) }
before do
diff --git a/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb b/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb
index 5f2a27acd9b..c4e33259e13 100644
--- a/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::MigrateLegacyArtifacts, schema: 20180816161409 do
+RSpec.describe Gitlab::BackgroundMigration::MigrateLegacyArtifacts, schema: 20180816161409 do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
diff --git a/spec/lib/gitlab/background_migration/migrate_null_private_profile_to_false_spec.rb b/spec/lib/gitlab/background_migration/migrate_null_private_profile_to_false_spec.rb
index ff88d2a5d00..6ff1157cb86 100644
--- a/spec/lib/gitlab/background_migration/migrate_null_private_profile_to_false_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_null_private_profile_to_false_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::MigrateNullPrivateProfileToFalse, schema: 20190620105427 do
+RSpec.describe Gitlab::BackgroundMigration::MigrateNullPrivateProfileToFalse, schema: 20190620105427 do
let(:users) { table(:users) }
it 'correctly migrates nil private_profile to false' do
diff --git a/spec/lib/gitlab/background_migration/migrate_pages_metadata_spec.rb b/spec/lib/gitlab/background_migration/migrate_pages_metadata_spec.rb
index 10a1d4ee1b9..906a6a747c9 100644
--- a/spec/lib/gitlab/background_migration/migrate_pages_metadata_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_pages_metadata_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::MigratePagesMetadata, schema: 20190919040324 do
+RSpec.describe Gitlab::BackgroundMigration::MigratePagesMetadata, schema: 20190919040324 do
let(:projects) { table(:projects) }
subject(:migrate_pages_metadata) { described_class.new }
diff --git a/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb b/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb
index 437be125cf0..abc5c312455 100644
--- a/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::MigrateStageIndex, schema: 20180420080616 do
+RSpec.describe Gitlab::BackgroundMigration::MigrateStageIndex, schema: 20180420080616 do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
diff --git a/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb b/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb
index 8603eb73bd5..db3cbe7ccdc 100644
--- a/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::MigrateUsersBioToUserDetails, :migration, schema: 20200323074147 do
+RSpec.describe Gitlab::BackgroundMigration::MigrateUsersBioToUserDetails, :migration, schema: 20200323074147 do
let(:users) { table(:users) }
let(:user_details) do
diff --git a/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb b/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb
index 37ddb8b569d..ee0024e8526 100644
--- a/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::PopulateCanonicalEmails, :migration, schema: 20200312053852 do
+RSpec.describe Gitlab::BackgroundMigration::PopulateCanonicalEmails, :migration, schema: 20200312053852 do
let(:migration) { described_class.new }
let_it_be(:users_table) { table(:users) }
diff --git a/spec/lib/gitlab/background_migration/populate_cluster_kubernetes_namespace_table_spec.rb b/spec/lib/gitlab/background_migration/populate_cluster_kubernetes_namespace_table_spec.rb
index d445858b8e8..0ffd0a63935 100644
--- a/spec/lib/gitlab/background_migration/populate_cluster_kubernetes_namespace_table_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_cluster_kubernetes_namespace_table_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::PopulateClusterKubernetesNamespaceTable, schema: 20181022173835 do
+RSpec.describe Gitlab::BackgroundMigration::PopulateClusterKubernetesNamespaceTable, schema: 20181022173835 do
include MigrationHelpers::ClusterHelpers
let(:migration) { described_class.new }
diff --git a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
index e65b3549de0..1e5773ee16b 100644
--- a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::PopulateMergeRequestAssigneesTable, schema: 20190315191339 do
+RSpec.describe Gitlab::BackgroundMigration::PopulateMergeRequestAssigneesTable, schema: 20190315191339 do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:users) { table(:users) }
diff --git a/spec/lib/gitlab/background_migration/populate_untracked_uploads_dependencies/untracked_file_spec.rb b/spec/lib/gitlab/background_migration/populate_untracked_uploads_dependencies/untracked_file_spec.rb
index 0250ebd7759..f1e42f141bf 100644
--- a/spec/lib/gitlab/background_migration/populate_untracked_uploads_dependencies/untracked_file_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_untracked_uploads_dependencies/untracked_file_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
# Rollback DB to 10.5 (later than this was originally written for) because it still needs to work.
-describe Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::UntrackedFile, schema: 20180208183958 do
+RSpec.describe Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::UntrackedFile, schema: 20180208183958 do
include MigrationsHelpers::TrackUntrackedUploadsHelpers
let!(:appearances) { table(:appearances) }
diff --git a/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
index 44cec112bfd..176f52e4a80 100644
--- a/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
# Rollback DB to 10.5 (later than this was originally written for) because it still needs to work.
-describe Gitlab::BackgroundMigration::PopulateUntrackedUploads, schema: 20180208183958 do
+RSpec.describe Gitlab::BackgroundMigration::PopulateUntrackedUploads, schema: 20180208183958 do
include MigrationsHelpers::TrackUntrackedUploadsHelpers
subject { described_class.new }
diff --git a/spec/lib/gitlab/background_migration/populate_user_highest_roles_table_spec.rb b/spec/lib/gitlab/background_migration/populate_user_highest_roles_table_spec.rb
index be661d5b83e..f0b0f77280e 100644
--- a/spec/lib/gitlab/background_migration/populate_user_highest_roles_table_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_user_highest_roles_table_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::PopulateUserHighestRolesTable, schema: 20200311130802 do
+RSpec.describe Gitlab::BackgroundMigration::PopulateUserHighestRolesTable, schema: 20200311130802 do
let(:members) { table(:members) }
let(:users) { table(:users) }
let(:user_highest_roles) { table(:user_highest_roles) }
diff --git a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
index 9daf35d0311..65acc0a67a3 100644
--- a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
+++ b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
# Rollback DB to 10.5 (later than this was originally written for) because it still needs to work.
-describe Gitlab::BackgroundMigration::PrepareUntrackedUploads, schema: 20180208183958 do
+RSpec.describe Gitlab::BackgroundMigration::PrepareUntrackedUploads, schema: 20180208183958 do
include MigrationsHelpers::TrackUntrackedUploadsHelpers
let!(:untracked_files_for_uploads) { table(:untracked_files_for_uploads) }
diff --git a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb b/spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb
index ba87312e2bf..33e1f31d1f1 100644
--- a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb
+++ b/spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::RecalculateProjectAuthorizations, schema: 20200204113223 do
+RSpec.describe Gitlab::BackgroundMigration::RecalculateProjectAuthorizations, schema: 20200204113223 do
let(:users_table) { table(:users) }
let(:namespaces_table) { table(:namespaces) }
let(:projects_table) { table(:projects) }
diff --git a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb b/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb
index edb46efad7c..c1ba1607b89 100644
--- a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb
+++ b/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::RecalculateProjectAuthorizationsWithMinMaxUserId, schema: 20200204113224 do
+RSpec.describe Gitlab::BackgroundMigration::RecalculateProjectAuthorizationsWithMinMaxUserId, schema: 20200204113224 do
let(:users_table) { table(:users) }
let(:min) { 1 }
let(:max) { 5 }
diff --git a/spec/lib/gitlab/background_migration/remove_restricted_todos_spec.rb b/spec/lib/gitlab/background_migration/remove_restricted_todos_spec.rb
index 3de24f577ab..b2fe9bbfcdc 100644
--- a/spec/lib/gitlab/background_migration/remove_restricted_todos_spec.rb
+++ b/spec/lib/gitlab/background_migration/remove_restricted_todos_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::RemoveRestrictedTodos, schema: 20180704204006 do
+RSpec.describe Gitlab::BackgroundMigration::RemoveRestrictedTodos, schema: 20180704204006 do
let(:projects) { table(:projects) }
let(:users) { table(:users) }
let(:todos) { table(:todos) }
diff --git a/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb b/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb
index e057aea6bb3..43fc0fb3691 100644
--- a/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb
+++ b/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::ResetMergeStatus do
+RSpec.describe Gitlab::BackgroundMigration::ResetMergeStatus do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:namespace) { namespaces.create(name: 'gitlab', path: 'gitlab-org') }
diff --git a/spec/lib/gitlab/background_migration/schedule_calculate_wiki_sizes_spec.rb b/spec/lib/gitlab/background_migration/schedule_calculate_wiki_sizes_spec.rb
index 387e3343ede..4e3c58ef2f2 100644
--- a/spec/lib/gitlab/background_migration/schedule_calculate_wiki_sizes_spec.rb
+++ b/spec/lib/gitlab/background_migration/schedule_calculate_wiki_sizes_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20190527194900_schedule_calculate_wiki_sizes.rb')
-describe ScheduleCalculateWikiSizes do
+RSpec.describe ScheduleCalculateWikiSizes do
let(:migration_class) { Gitlab::BackgroundMigration::CalculateWikiSizes }
let(:migration_name) { migration_class.to_s.demodulize }
diff --git a/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb
index 5ce4a322e51..c7849cbe52f 100644
--- a/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb
+++ b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnServices, schema: 20180122154930 do
+RSpec.describe Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnServices, schema: 20180122154930 do
let(:services) { table(:services) }
describe '#perform' do
diff --git a/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb
index 08f1f543f5d..22679f78d3e 100644
--- a/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb
+++ b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnWebhooks, schema: 20180104131052 do
+RSpec.describe Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnWebhooks, schema: 20180104131052 do
let(:web_hooks) { table(:web_hooks) }
describe '#perform' do
diff --git a/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb b/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb
index 70397ae1e30..6c0a1d3a5b0 100644
--- a/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb
+++ b/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::UpdateExistingSubgroupToMatchVisibilityLevelOfParent, schema: 2020_01_10_121314 do
+RSpec.describe Gitlab::BackgroundMigration::UpdateExistingSubgroupToMatchVisibilityLevelOfParent, schema: 2020_01_10_121314 do
include MigrationHelpers::NamespacesHelpers
context 'private visibility level' do
diff --git a/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb b/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb
index d4f52a11ce7..08a4bbe38ac 100644
--- a/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb
+++ b/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
require './db/post_migrate/20200128134110_migrate_commit_notes_mentions_to_db'
require './db/post_migrate/20200211155539_migrate_merge_request_mentions_to_db'
-describe Gitlab::BackgroundMigration::UserMentions::CreateResourceUserMention, schema: 20200211155539 do
+RSpec.describe Gitlab::BackgroundMigration::UserMentions::CreateResourceUserMention, schema: 20200211155539 do
include MigrationsHelpers
context 'when migrating data' do
diff --git a/spec/lib/gitlab/background_migration_spec.rb b/spec/lib/gitlab/background_migration_spec.rb
index 71959f54b38..2d55badfa59 100644
--- a/spec/lib/gitlab/background_migration_spec.rb
+++ b/spec/lib/gitlab/background_migration_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration do
+RSpec.describe Gitlab::BackgroundMigration do
describe '.queue' do
it 'returns background migration worker queue' do
expect(described_class.queue)
diff --git a/spec/lib/gitlab/backtrace_cleaner_spec.rb b/spec/lib/gitlab/backtrace_cleaner_spec.rb
index f3aded9faad..51d99bf5f74 100644
--- a/spec/lib/gitlab/backtrace_cleaner_spec.rb
+++ b/spec/lib/gitlab/backtrace_cleaner_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BacktraceCleaner do
+RSpec.describe Gitlab::BacktraceCleaner do
describe '.clean_backtrace' do
it 'uses the Rails backtrace cleaner' do
backtrace = []
diff --git a/spec/lib/gitlab/badge/coverage/metadata_spec.rb b/spec/lib/gitlab/badge/coverage/metadata_spec.rb
index 2b87508bdef..725ae03ad74 100644
--- a/spec/lib/gitlab/badge/coverage/metadata_spec.rb
+++ b/spec/lib/gitlab/badge/coverage/metadata_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'lib/gitlab/badge/shared/metadata'
-describe Gitlab::Badge::Coverage::Metadata do
+RSpec.describe Gitlab::Badge::Coverage::Metadata do
let(:badge) do
double(project: create(:project), ref: 'feature', job: 'test')
end
diff --git a/spec/lib/gitlab/badge/coverage/report_spec.rb b/spec/lib/gitlab/badge/coverage/report_spec.rb
index 284ca53a996..9c4dfcbfd54 100644
--- a/spec/lib/gitlab/badge/coverage/report_spec.rb
+++ b/spec/lib/gitlab/badge/coverage/report_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Badge::Coverage::Report do
+RSpec.describe Gitlab::Badge::Coverage::Report do
let(:project) { create(:project, :repository) }
let(:job_name) { nil }
diff --git a/spec/lib/gitlab/badge/coverage/template_spec.rb b/spec/lib/gitlab/badge/coverage/template_spec.rb
index 3940b37830e..5a0adfd8e59 100644
--- a/spec/lib/gitlab/badge/coverage/template_spec.rb
+++ b/spec/lib/gitlab/badge/coverage/template_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Badge::Coverage::Template do
+RSpec.describe Gitlab::Badge::Coverage::Template do
let(:badge) { double(entity: 'coverage', status: 90.00, customization: {}) }
let(:template) { described_class.new(badge) }
diff --git a/spec/lib/gitlab/badge/pipeline/metadata_spec.rb b/spec/lib/gitlab/badge/pipeline/metadata_spec.rb
index b096803f921..c8ed0c8ea29 100644
--- a/spec/lib/gitlab/badge/pipeline/metadata_spec.rb
+++ b/spec/lib/gitlab/badge/pipeline/metadata_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'lib/gitlab/badge/shared/metadata'
-describe Gitlab::Badge::Pipeline::Metadata do
+RSpec.describe Gitlab::Badge::Pipeline::Metadata do
let(:badge) { double(project: create(:project), ref: 'feature') }
let(:metadata) { described_class.new(badge) }
diff --git a/spec/lib/gitlab/badge/pipeline/status_spec.rb b/spec/lib/gitlab/badge/pipeline/status_spec.rb
index ab8d1f0ec5b..fcc0d4030fd 100644
--- a/spec/lib/gitlab/badge/pipeline/status_spec.rb
+++ b/spec/lib/gitlab/badge/pipeline/status_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Badge::Pipeline::Status do
+RSpec.describe Gitlab::Badge::Pipeline::Status do
let(:project) { create(:project, :repository) }
let(:sha) { project.commit.sha }
let(:branch) { 'master' }
diff --git a/spec/lib/gitlab/badge/pipeline/template_spec.rb b/spec/lib/gitlab/badge/pipeline/template_spec.rb
index 751a5d6645e..2f0d0782369 100644
--- a/spec/lib/gitlab/badge/pipeline/template_spec.rb
+++ b/spec/lib/gitlab/badge/pipeline/template_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Badge::Pipeline::Template do
+RSpec.describe Gitlab::Badge::Pipeline::Template do
let(:badge) { double(entity: 'pipeline', status: 'success', customization: {}) }
let(:template) { described_class.new(badge) }
diff --git a/spec/lib/gitlab/badge/shared/metadata.rb b/spec/lib/gitlab/badge/shared/metadata.rb
index 809fa54db02..c99a65bb2f4 100644
--- a/spec/lib/gitlab/badge/shared/metadata.rb
+++ b/spec/lib/gitlab/badge/shared/metadata.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'badge metadata' do
+RSpec.shared_examples 'badge metadata' do
describe '#to_html' do
let(:html) { Nokogiri::HTML.parse(metadata.to_html) }
let(:a_href) { html.at('a') }
diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
index 75a23d4f49e..e09430a858c 100644
--- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BareRepositoryImport::Importer, :seed_helper do
+RSpec.describe Gitlab::BareRepositoryImport::Importer, :seed_helper do
let!(:admin) { create(:admin) }
let!(:base_dir) { Dir.mktmpdir + '/' }
let(:bare_repository) { Gitlab::BareRepositoryImport::Repository.new(base_dir, File.join(base_dir, "#{project_path}.git")) }
diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
index d2ecb1869fc..bf115046744 100644
--- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ::Gitlab::BareRepositoryImport::Repository do
+RSpec.describe ::Gitlab::BareRepositoryImport::Repository do
context 'legacy storage' do
subject { described_class.new('/full/path/', '/full/path/to/repo.git') }
diff --git a/spec/lib/gitlab/batch_pop_queueing_spec.rb b/spec/lib/gitlab/batch_pop_queueing_spec.rb
index 28984d52024..41efc5417e4 100644
--- a/spec/lib/gitlab/batch_pop_queueing_spec.rb
+++ b/spec/lib/gitlab/batch_pop_queueing_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BatchPopQueueing do
+RSpec.describe Gitlab::BatchPopQueueing do
include ExclusiveLeaseHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/lib/gitlab/batch_worker_context_spec.rb b/spec/lib/gitlab/batch_worker_context_spec.rb
index 0ba30287ae5..31641f7449e 100644
--- a/spec/lib/gitlab/batch_worker_context_spec.rb
+++ b/spec/lib/gitlab/batch_worker_context_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BatchWorkerContext do
+RSpec.describe Gitlab::BatchWorkerContext do
subject(:batch_context) do
described_class.new(
%w(hello world),
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index 69dc10d1f55..08b7bafddf0 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BitbucketImport::Importer do
+RSpec.describe Gitlab::BitbucketImport::Importer do
include ImportSpecHelper
before do
diff --git a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
index 0dd8547a925..236e04a041b 100644
--- a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BitbucketImport::ProjectCreator do
+RSpec.describe Gitlab::BitbucketImport::ProjectCreator do
let(:user) { create(:user) }
let(:repo) do
diff --git a/spec/lib/gitlab/bitbucket_import/wiki_formatter_spec.rb b/spec/lib/gitlab/bitbucket_import/wiki_formatter_spec.rb
index 7b5c7847f2d..4c285d31979 100644
--- a/spec/lib/gitlab/bitbucket_import/wiki_formatter_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/wiki_formatter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BitbucketImport::WikiFormatter do
+RSpec.describe Gitlab::BitbucketImport::WikiFormatter do
let(:project) do
create(:project,
namespace: create(:namespace, path: 'gitlabhq'),
diff --git a/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb
index 570ad916fb2..5eb27c51f9e 100644
--- a/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BitbucketServerImport::Importer do
+RSpec.describe Gitlab::BitbucketServerImport::Importer do
include ImportSpecHelper
let(:import_url) { 'http://my-bitbucket' }
diff --git a/spec/lib/gitlab/blame_spec.rb b/spec/lib/gitlab/blame_spec.rb
index e1afd5b25bb..e22399723ac 100644
--- a/spec/lib/gitlab/blame_spec.rb
+++ b/spec/lib/gitlab/blame_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Blame do
+RSpec.describe Gitlab::Blame do
let(:project) { create(:project, :repository) }
let(:path) { 'files/ruby/popen.rb' }
let(:commit) { project.commit('master') }
diff --git a/spec/lib/gitlab/blob_helper_spec.rb b/spec/lib/gitlab/blob_helper_spec.rb
index e057385b35f..65fa5bf0120 100644
--- a/spec/lib/gitlab/blob_helper_spec.rb
+++ b/spec/lib/gitlab/blob_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BlobHelper do
+RSpec.describe Gitlab::BlobHelper do
include FakeBlobHelpers
let(:project) { create(:project) }
diff --git a/spec/lib/gitlab/branch_push_merge_commit_analyzer_spec.rb b/spec/lib/gitlab/branch_push_merge_commit_analyzer_spec.rb
index a27f14cd621..f09f38a6127 100644
--- a/spec/lib/gitlab/branch_push_merge_commit_analyzer_spec.rb
+++ b/spec/lib/gitlab/branch_push_merge_commit_analyzer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BranchPushMergeCommitAnalyzer do
+RSpec.describe Gitlab::BranchPushMergeCommitAnalyzer do
let(:project) { create(:project, :repository) }
let(:oldrev) { 'merge-commit-analyze-before' }
let(:newrev) { 'merge-commit-analyze-after' }
diff --git a/spec/lib/gitlab/build_access_spec.rb b/spec/lib/gitlab/build_access_spec.rb
index b7af8ace5b5..c6248f94772 100644
--- a/spec/lib/gitlab/build_access_spec.rb
+++ b/spec/lib/gitlab/build_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::BuildAccess do
+RSpec.describe Gitlab::BuildAccess do
let(:user) { create(:user) }
let(:project) { create(:project) }
diff --git a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
index fc9266f75fb..beeccdf40a1 100644
--- a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
+++ b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do
+RSpec.describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do
let!(:project) { create(:project, :repository) }
let(:pipeline_status) { described_class.new(project) }
let(:cache_key) { pipeline_status.cache_key }
diff --git a/spec/lib/gitlab/cache/import/caching_spec.rb b/spec/lib/gitlab/cache/import/caching_spec.rb
index 7b4308d32ae..d6911dad9d4 100644
--- a/spec/lib/gitlab/cache/import/caching_spec.rb
+++ b/spec/lib/gitlab/cache/import/caching_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Cache::Import::Caching, :clean_gitlab_redis_cache do
+RSpec.describe Gitlab::Cache::Import::Caching, :clean_gitlab_redis_cache do
describe '.read' do
it 'reads a value from the cache' do
described_class.write('foo', 'bar')
diff --git a/spec/lib/gitlab/cache/request_cache_spec.rb b/spec/lib/gitlab/cache/request_cache_spec.rb
index 70a7f090d0a..57aee525ddd 100644
--- a/spec/lib/gitlab/cache/request_cache_spec.rb
+++ b/spec/lib/gitlab/cache/request_cache_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Cache::RequestCache do
+RSpec.describe Gitlab::Cache::RequestCache do
let(:klass) do
Class.new do
extend Gitlab::Cache::RequestCache
diff --git a/spec/lib/gitlab/changes_list_spec.rb b/spec/lib/gitlab/changes_list_spec.rb
index 911450f3a8b..8292764f561 100644
--- a/spec/lib/gitlab/changes_list_spec.rb
+++ b/spec/lib/gitlab/changes_list_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-describe Gitlab::ChangesList do
+RSpec.describe Gitlab::ChangesList do
let(:valid_changes_string) { "\n000000 570e7b2 refs/heads/my_branch\nd14d6c 6fd24d refs/heads/master" }
let(:invalid_changes) { 1 }
diff --git a/spec/lib/gitlab/chat/command_spec.rb b/spec/lib/gitlab/chat/command_spec.rb
index f7f344bf786..89c693daaa0 100644
--- a/spec/lib/gitlab/chat/command_spec.rb
+++ b/spec/lib/gitlab/chat/command_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Chat::Command do
+RSpec.describe Gitlab::Chat::Command do
let(:chat_name) { create(:chat_name) }
let(:command) do
diff --git a/spec/lib/gitlab/chat/output_spec.rb b/spec/lib/gitlab/chat/output_spec.rb
index b179f9e9d0a..38e17c39fad 100644
--- a/spec/lib/gitlab/chat/output_spec.rb
+++ b/spec/lib/gitlab/chat/output_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Chat::Output do
+RSpec.describe Gitlab::Chat::Output do
let(:build) do
create(:ci_build, pipeline: create(:ci_pipeline, source: :chat))
end
diff --git a/spec/lib/gitlab/chat/responder/base_spec.rb b/spec/lib/gitlab/chat/responder/base_spec.rb
index 7fa9bad9d38..667228cbab4 100644
--- a/spec/lib/gitlab/chat/responder/base_spec.rb
+++ b/spec/lib/gitlab/chat/responder/base_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Chat::Responder::Base do
+RSpec.describe Gitlab::Chat::Responder::Base do
let(:project) { double(:project) }
let(:pipeline) { double(:pipeline, project: project) }
let(:build) { double(:build, pipeline: pipeline) }
diff --git a/spec/lib/gitlab/chat/responder/mattermost_spec.rb b/spec/lib/gitlab/chat/responder/mattermost_spec.rb
index f3480dfef06..ca5f83d760a 100644
--- a/spec/lib/gitlab/chat/responder/mattermost_spec.rb
+++ b/spec/lib/gitlab/chat/responder/mattermost_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Chat::Responder::Mattermost do
+RSpec.describe Gitlab::Chat::Responder::Mattermost do
let(:chat_name) { create(:chat_name, chat_id: 'U123') }
let(:pipeline) do
diff --git a/spec/lib/gitlab/chat/responder/slack_spec.rb b/spec/lib/gitlab/chat/responder/slack_spec.rb
index a1553232b32..4801a1c6b66 100644
--- a/spec/lib/gitlab/chat/responder/slack_spec.rb
+++ b/spec/lib/gitlab/chat/responder/slack_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Chat::Responder::Slack do
+RSpec.describe Gitlab::Chat::Responder::Slack do
let(:chat_name) { create(:chat_name, chat_id: 'U123') }
let(:pipeline) do
diff --git a/spec/lib/gitlab/chat/responder_spec.rb b/spec/lib/gitlab/chat/responder_spec.rb
index 9893689cba9..6603dbe8d52 100644
--- a/spec/lib/gitlab/chat/responder_spec.rb
+++ b/spec/lib/gitlab/chat/responder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Chat::Responder do
+RSpec.describe Gitlab::Chat::Responder do
describe '.responder_for' do
context 'using a regular build' do
it 'returns nil' do
diff --git a/spec/lib/gitlab/chat_name_token_spec.rb b/spec/lib/gitlab/chat_name_token_spec.rb
index b2d4a466021..906c02d54db 100644
--- a/spec/lib/gitlab/chat_name_token_spec.rb
+++ b/spec/lib/gitlab/chat_name_token_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::ChatNameToken do
+RSpec.describe Gitlab::ChatNameToken do
context 'when using unknown token' do
let(:token) { }
diff --git a/spec/lib/gitlab/chat_spec.rb b/spec/lib/gitlab/chat_spec.rb
index be606fe6db1..a9df35ace98 100644
--- a/spec/lib/gitlab/chat_spec.rb
+++ b/spec/lib/gitlab/chat_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Chat, :use_clean_rails_memory_store_caching do
+RSpec.describe Gitlab::Chat, :use_clean_rails_memory_store_caching do
describe '.available?' do
it 'returns true when the chatops feature is available' do
stub_feature_flags(chatops: true)
diff --git a/spec/lib/gitlab/checks/branch_check_spec.rb b/spec/lib/gitlab/checks/branch_check_spec.rb
index fd7eaa1603f..92452727017 100644
--- a/spec/lib/gitlab/checks/branch_check_spec.rb
+++ b/spec/lib/gitlab/checks/branch_check_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::BranchCheck do
+RSpec.describe Gitlab::Checks::BranchCheck do
include_context 'change access checks context'
describe '#validate!' do
diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb
index dfc8c59fd74..87936d19239 100644
--- a/spec/lib/gitlab/checks/change_access_spec.rb
+++ b/spec/lib/gitlab/checks/change_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::ChangeAccess do
+RSpec.describe Gitlab::Checks::ChangeAccess do
describe '#exec' do
include_context 'change access checks context'
diff --git a/spec/lib/gitlab/checks/diff_check_spec.rb b/spec/lib/gitlab/checks/diff_check_spec.rb
index 467b4ed3a21..2cca0aed9c6 100644
--- a/spec/lib/gitlab/checks/diff_check_spec.rb
+++ b/spec/lib/gitlab/checks/diff_check_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::DiffCheck do
+RSpec.describe Gitlab::Checks::DiffCheck do
include_context 'change access checks context'
describe '#validate!' do
diff --git a/spec/lib/gitlab/checks/force_push_spec.rb b/spec/lib/gitlab/checks/force_push_spec.rb
index 334dd8635a3..49e02fe5cec 100644
--- a/spec/lib/gitlab/checks/force_push_spec.rb
+++ b/spec/lib/gitlab/checks/force_push_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::ForcePush do
+RSpec.describe Gitlab::Checks::ForcePush do
let_it_be(:project) { create(:project, :repository) }
describe '.force_push?' do
diff --git a/spec/lib/gitlab/checks/lfs_check_spec.rb b/spec/lib/gitlab/checks/lfs_check_spec.rb
index c86481d1abe..713858e0e35 100644
--- a/spec/lib/gitlab/checks/lfs_check_spec.rb
+++ b/spec/lib/gitlab/checks/lfs_check_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::LfsCheck do
+RSpec.describe Gitlab::Checks::LfsCheck do
include_context 'change access checks context'
let(:blob_object) { project.repository.blob_at_branch('lfs', 'files/lfs/lfs_object.iso') }
diff --git a/spec/lib/gitlab/checks/lfs_integrity_spec.rb b/spec/lib/gitlab/checks/lfs_integrity_spec.rb
index 505f117034e..8fec702790c 100644
--- a/spec/lib/gitlab/checks/lfs_integrity_spec.rb
+++ b/spec/lib/gitlab/checks/lfs_integrity_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::LfsIntegrity do
+RSpec.describe Gitlab::Checks::LfsIntegrity do
include ProjectForksHelper
let!(:time_left) { 50 }
diff --git a/spec/lib/gitlab/checks/project_created_spec.rb b/spec/lib/gitlab/checks/project_created_spec.rb
index bbc97155374..f099f19b061 100644
--- a/spec/lib/gitlab/checks/project_created_spec.rb
+++ b/spec/lib/gitlab/checks/project_created_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::ProjectCreated, :clean_gitlab_redis_shared_state do
+RSpec.describe Gitlab::Checks::ProjectCreated, :clean_gitlab_redis_shared_state do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository, namespace: user.namespace) }
let(:protocol) { 'http' }
diff --git a/spec/lib/gitlab/checks/project_moved_spec.rb b/spec/lib/gitlab/checks/project_moved_spec.rb
index 1d1d6211088..e15fa90443b 100644
--- a/spec/lib/gitlab/checks/project_moved_spec.rb
+++ b/spec/lib/gitlab/checks/project_moved_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do
+RSpec.describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository, :wiki_repo, namespace: user.namespace) }
let(:repository) { project.repository }
diff --git a/spec/lib/gitlab/checks/push_check_spec.rb b/spec/lib/gitlab/checks/push_check_spec.rb
index 857d71732fe..45ab13cf0cf 100644
--- a/spec/lib/gitlab/checks/push_check_spec.rb
+++ b/spec/lib/gitlab/checks/push_check_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::PushCheck do
+RSpec.describe Gitlab::Checks::PushCheck do
include_context 'change access checks context'
describe '#validate!' do
diff --git a/spec/lib/gitlab/checks/push_file_count_check_spec.rb b/spec/lib/gitlab/checks/push_file_count_check_spec.rb
index e05102a9ce8..e05070e8f35 100644
--- a/spec/lib/gitlab/checks/push_file_count_check_spec.rb
+++ b/spec/lib/gitlab/checks/push_file_count_check_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::PushFileCountCheck do
+RSpec.describe Gitlab::Checks::PushFileCountCheck do
let(:snippet) { create(:personal_snippet, :repository) }
let(:changes) { { oldrev: oldrev, newrev: newrev, ref: ref } }
let(:timeout) { Gitlab::GitAccess::INTERNAL_TIMEOUT }
diff --git a/spec/lib/gitlab/checks/snippet_check_spec.rb b/spec/lib/gitlab/checks/snippet_check_spec.rb
index 3eee5ccfc0a..2c027486bc9 100644
--- a/spec/lib/gitlab/checks/snippet_check_spec.rb
+++ b/spec/lib/gitlab/checks/snippet_check_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::SnippetCheck do
+RSpec.describe Gitlab::Checks::SnippetCheck do
include_context 'change access checks context'
let(:snippet) { create(:personal_snippet, :repository) }
diff --git a/spec/lib/gitlab/checks/tag_check_spec.rb b/spec/lib/gitlab/checks/tag_check_spec.rb
index 0c94171646e..e2e7d9c9648 100644
--- a/spec/lib/gitlab/checks/tag_check_spec.rb
+++ b/spec/lib/gitlab/checks/tag_check_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::TagCheck do
+RSpec.describe Gitlab::Checks::TagCheck do
include_context 'change access checks context'
describe '#validate!' do
diff --git a/spec/lib/gitlab/checks/timed_logger_spec.rb b/spec/lib/gitlab/checks/timed_logger_spec.rb
index 0ed3940c038..6c488212eca 100644
--- a/spec/lib/gitlab/checks/timed_logger_spec.rb
+++ b/spec/lib/gitlab/checks/timed_logger_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Checks::TimedLogger do
+RSpec.describe Gitlab::Checks::TimedLogger do
let!(:timeout) { 50.seconds }
let!(:start) { Time.now }
let!(:ref) { "bar" }
diff --git a/spec/lib/gitlab/ci/ansi2html_spec.rb b/spec/lib/gitlab/ci/ansi2html_spec.rb
index ee789995bc2..f29a39e4e66 100644
--- a/spec/lib/gitlab/ci/ansi2html_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2html_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Ansi2html do
+RSpec.describe Gitlab::Ci::Ansi2html do
subject { described_class }
it "prints non-ansi as-is" do
diff --git a/spec/lib/gitlab/ci/ansi2json/line_spec.rb b/spec/lib/gitlab/ci/ansi2json/line_spec.rb
index 4b5c3f9489e..8b1cd812a70 100644
--- a/spec/lib/gitlab/ci/ansi2json/line_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json/line_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Ansi2json::Line do
+RSpec.describe Gitlab::Ci::Ansi2json::Line do
let(:offset) { 0 }
let(:style) { Gitlab::Ci::Ansi2json::Style.new }
diff --git a/spec/lib/gitlab/ci/ansi2json/parser_spec.rb b/spec/lib/gitlab/ci/ansi2json/parser_spec.rb
index e161e74c1ff..cf93ebe0721 100644
--- a/spec/lib/gitlab/ci/ansi2json/parser_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json/parser_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
# The rest of the specs for this class are covered in style_spec.rb
-describe Gitlab::Ci::Ansi2json::Parser do
+RSpec.describe Gitlab::Ci::Ansi2json::Parser do
subject { described_class }
describe 'bold?' do
diff --git a/spec/lib/gitlab/ci/ansi2json/result_spec.rb b/spec/lib/gitlab/ci/ansi2json/result_spec.rb
index 5b7b5481400..31c0da95f0a 100644
--- a/spec/lib/gitlab/ci/ansi2json/result_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json/result_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Ansi2json::Result do
+RSpec.describe Gitlab::Ci::Ansi2json::Result do
let(:stream) { StringIO.new('hello') }
let(:state) { Gitlab::Ci::Ansi2json::State.new(nil, stream.size) }
let(:offset) { 0 }
diff --git a/spec/lib/gitlab/ci/ansi2json/style_spec.rb b/spec/lib/gitlab/ci/ansi2json/style_spec.rb
index ad05aa03e83..d27a642ecf3 100644
--- a/spec/lib/gitlab/ci/ansi2json/style_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json/style_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Ansi2json::Style do
+RSpec.describe Gitlab::Ci::Ansi2json::Style do
describe '#set?' do
subject { described_class.new(params).set? }
diff --git a/spec/lib/gitlab/ci/ansi2json_spec.rb b/spec/lib/gitlab/ci/ansi2json_spec.rb
index 124379fa321..cb6949fddc2 100644
--- a/spec/lib/gitlab/ci/ansi2json_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Ansi2json do
+RSpec.describe Gitlab::Ci::Ansi2json do
subject { described_class }
describe 'lines' do
diff --git a/spec/lib/gitlab/ci/artifact_file_reader_spec.rb b/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
index 04017b9ae3e..e982f0eb015 100644
--- a/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
+++ b/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::ArtifactFileReader do
+RSpec.describe Gitlab::Ci::ArtifactFileReader do
let(:job) { create(:ci_build) }
let(:path) { 'generated.yml' } # included in the ci_build_artifacts.zip
diff --git a/spec/lib/gitlab/ci/build/artifacts/adapters/gzip_stream_spec.rb b/spec/lib/gitlab/ci/build/artifacts/adapters/gzip_stream_spec.rb
index cec3e70bb9f..98f909a0ed0 100644
--- a/spec/lib/gitlab/ci/build/artifacts/adapters/gzip_stream_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/adapters/gzip_stream_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Artifacts::Adapters::GzipStream do
+RSpec.describe Gitlab::Ci::Build::Artifacts::Adapters::GzipStream do
describe '#initialize' do
context 'when stream is passed' do
let(:stream) { File.open(expand_fixture_path('junit/junit.xml.gz'), 'rb') }
diff --git a/spec/lib/gitlab/ci/build/artifacts/adapters/raw_stream_spec.rb b/spec/lib/gitlab/ci/build/artifacts/adapters/raw_stream_spec.rb
index 66a234232e1..badff972e60 100644
--- a/spec/lib/gitlab/ci/build/artifacts/adapters/raw_stream_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/adapters/raw_stream_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Artifacts::Adapters::RawStream do
+RSpec.describe Gitlab::Ci::Build::Artifacts::Adapters::RawStream do
describe '#initialize' do
context 'when stream is passed' do
let(:stream) { File.open(expand_fixture_path('junit/junit.xml'), 'rb') }
diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
index 7a413a7aeac..c8ace28108b 100644
--- a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
+RSpec.describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
let(:entries) do
{ 'path/' => {},
'path/dir_1/' => {},
diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
index bfa65c66b33..77b8aa1d591 100644
--- a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Artifacts::Metadata do
+RSpec.describe Gitlab::Ci::Build::Artifacts::Metadata do
def metadata(path = '', **opts)
described_class.new(metadata_file_stream, path, **opts)
end
diff --git a/spec/lib/gitlab/ci/build/artifacts/path_spec.rb b/spec/lib/gitlab/ci/build/artifacts/path_spec.rb
index 7bbef0f5197..27b7dac2ae4 100644
--- a/spec/lib/gitlab/ci/build/artifacts/path_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/path_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Artifacts::Path do
+RSpec.describe Gitlab::Ci::Build::Artifacts::Path do
describe '#valid?' do
context 'when path contains a zero character' do
it 'is not valid' do
diff --git a/spec/lib/gitlab/ci/build/context/build_spec.rb b/spec/lib/gitlab/ci/build/context/build_spec.rb
index 1b73b9a083d..61ca8e759b5 100644
--- a/spec/lib/gitlab/ci/build/context/build_spec.rb
+++ b/spec/lib/gitlab/ci/build/context/build_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Context::Build do
+RSpec.describe Gitlab::Ci::Build::Context::Build do
let(:pipeline) { create(:ci_pipeline) }
let(:seed_attributes) { { 'name' => 'some-job' } }
diff --git a/spec/lib/gitlab/ci/build/context/global_spec.rb b/spec/lib/gitlab/ci/build/context/global_spec.rb
index 65cc41ed3f9..7394708f9b6 100644
--- a/spec/lib/gitlab/ci/build/context/global_spec.rb
+++ b/spec/lib/gitlab/ci/build/context/global_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Context::Global do
+RSpec.describe Gitlab::Ci::Build::Context::Global do
let(:pipeline) { create(:ci_pipeline) }
let(:yaml_variables) { {} }
diff --git a/spec/lib/gitlab/ci/build/credentials/factory_spec.rb b/spec/lib/gitlab/ci/build/credentials/factory_spec.rb
index 159f89f4985..613d360f78d 100644
--- a/spec/lib/gitlab/ci/build/credentials/factory_spec.rb
+++ b/spec/lib/gitlab/ci/build/credentials/factory_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Credentials::Factory do
+RSpec.describe Gitlab::Ci::Build::Credentials::Factory do
let(:build) { create(:ci_build, name: 'spinach', stage: 'test', stage_idx: 0) }
subject { described_class.new(build).create! }
diff --git a/spec/lib/gitlab/ci/build/credentials/registry_spec.rb b/spec/lib/gitlab/ci/build/credentials/registry_spec.rb
index 552580dcbbe..c0a76973f60 100644
--- a/spec/lib/gitlab/ci/build/credentials/registry_spec.rb
+++ b/spec/lib/gitlab/ci/build/credentials/registry_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Credentials::Registry do
+RSpec.describe Gitlab::Ci::Build::Credentials::Registry do
let(:build) { create(:ci_build, name: 'spinach', stage: 'test', stage_idx: 0) }
let(:registry_url) { 'registry.example.com:5005' }
diff --git a/spec/lib/gitlab/ci/build/image_spec.rb b/spec/lib/gitlab/ci/build/image_spec.rb
index 4f7cfc9783a..71cd57d317c 100644
--- a/spec/lib/gitlab/ci/build/image_spec.rb
+++ b/spec/lib/gitlab/ci/build/image_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Image do
+RSpec.describe Gitlab::Ci::Build::Image do
let(:job) { create(:ci_build, :no_options) }
describe '#from_image' do
diff --git a/spec/lib/gitlab/ci/build/policy/changes_spec.rb b/spec/lib/gitlab/ci/build/policy/changes_spec.rb
index 07f52605929..016730e01cd 100644
--- a/spec/lib/gitlab/ci/build/policy/changes_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/changes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Policy::Changes do
+RSpec.describe Gitlab::Ci::Build::Policy::Changes do
let_it_be(:project) { create(:project) }
describe '#satisfied_by?' do
diff --git a/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb b/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb
index 6d96bdc30c7..81c0b76b453 100644
--- a/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Policy::Kubernetes do
+RSpec.describe Gitlab::Ci::Build::Policy::Kubernetes do
let(:pipeline) { create(:ci_pipeline, project: project) }
context 'when kubernetes service is active' do
diff --git a/spec/lib/gitlab/ci/build/policy/refs_spec.rb b/spec/lib/gitlab/ci/build/policy/refs_spec.rb
index c32fdc5c72e..7fd51102d71 100644
--- a/spec/lib/gitlab/ci/build/policy/refs_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/refs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Policy::Refs do
+RSpec.describe Gitlab::Ci::Build::Policy::Refs do
describe '#satisfied_by?' do
context 'when matching ref' do
let(:pipeline) { build_stubbed(:ci_pipeline, ref: 'master') }
diff --git a/spec/lib/gitlab/ci/build/policy/variables_spec.rb b/spec/lib/gitlab/ci/build/policy/variables_spec.rb
index 0e75726b81c..f692aa6146e 100644
--- a/spec/lib/gitlab/ci/build/policy/variables_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Policy::Variables do
+RSpec.describe Gitlab::Ci::Build::Policy::Variables do
let_it_be(:project) { create(:project) }
let(:pipeline) do
diff --git a/spec/lib/gitlab/ci/build/policy_spec.rb b/spec/lib/gitlab/ci/build/policy_spec.rb
index 80d7b2e9dc8..b85b093fd03 100644
--- a/spec/lib/gitlab/ci/build/policy_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Policy do
+RSpec.describe Gitlab::Ci::Build::Policy do
let(:policy) { spy('policy specification') }
before do
diff --git a/spec/lib/gitlab/ci/build/port_spec.rb b/spec/lib/gitlab/ci/build/port_spec.rb
index 1413780dfa6..480418e0851 100644
--- a/spec/lib/gitlab/ci/build/port_spec.rb
+++ b/spec/lib/gitlab/ci/build/port_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Port do
+RSpec.describe Gitlab::Ci::Build::Port do
subject { described_class.new(port) }
context 'when port is defined as an integer' do
diff --git a/spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb
index 5187f99a441..a38ade4bfa5 100644
--- a/spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb
+++ b/spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Prerequisite::Factory do
+RSpec.describe Gitlab::Ci::Build::Prerequisite::Factory do
let(:build) { create(:ci_build) }
describe '.for_build' do
diff --git a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
index 66240380edd..94c14cfa479 100644
--- a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
+++ b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
+RSpec.describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
describe '#unmet?' do
let(:build) { create(:ci_build) }
diff --git a/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb b/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb
index 076de3646b0..cf52f601006 100644
--- a/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Rules::Rule::Clause::Changes do
+RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Changes do
describe '#satisfied_by?' do
it_behaves_like 'a glob matching rule' do
let(:pipeline) { build(:ci_pipeline) }
diff --git a/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb b/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb
index 10843a1435a..86dd5569a96 100644
--- a/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Rules::Rule::Clause::Exists do
+RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Exists do
describe '#satisfied_by?' do
let(:pipeline) { build(:ci_pipeline, project: project, sha: project.repository.head_commit.sha) }
diff --git a/spec/lib/gitlab/ci/build/rules/rule_spec.rb b/spec/lib/gitlab/ci/build/rules/rule_spec.rb
index 04cdaa9d0ae..5694cd5d0a0 100644
--- a/spec/lib/gitlab/ci/build/rules/rule_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules/rule_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Rules::Rule do
+RSpec.describe Gitlab::Ci::Build::Rules::Rule do
let(:seed) do
double('build seed',
to_resource: ci_build,
diff --git a/spec/lib/gitlab/ci/build/rules_spec.rb b/spec/lib/gitlab/ci/build/rules_spec.rb
index 31a9fa055e1..cbeae33fbcf 100644
--- a/spec/lib/gitlab/ci/build/rules_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Rules do
+RSpec.describe Gitlab::Ci::Build::Rules do
let(:pipeline) { create(:ci_pipeline) }
let(:ci_build) { build(:ci_build, pipeline: pipeline) }
diff --git a/spec/lib/gitlab/ci/build/step_spec.rb b/spec/lib/gitlab/ci/build/step_spec.rb
index ea36d38bb10..4b8f68b9fa8 100644
--- a/spec/lib/gitlab/ci/build/step_spec.rb
+++ b/spec/lib/gitlab/ci/build/step_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Build::Step do
+RSpec.describe Gitlab::Ci::Build::Step do
describe '#from_commands' do
subject { described_class.from_commands(job) }
diff --git a/spec/lib/gitlab/ci/charts_spec.rb b/spec/lib/gitlab/ci/charts_spec.rb
index cfb7a3f72fa..e00e5ed3920 100644
--- a/spec/lib/gitlab/ci/charts_spec.rb
+++ b/spec/lib/gitlab/ci/charts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Charts do
+RSpec.describe Gitlab::Ci::Charts do
context "yearchart" do
let(:project) { create(:project) }
let(:chart) { Gitlab::Ci::Charts::YearChart.new(project) }
diff --git a/spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb b/spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb
index 042f9b591b6..52ea925c1c4 100644
--- a/spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb
+++ b/spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Config::EdgeStagesInjector do
+RSpec.describe Gitlab::Ci::Config::EdgeStagesInjector do
describe '#call' do
subject { described_class.new(config).to_hash }
diff --git a/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb b/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb
index 8cfd07df777..028dcd3e1e6 100644
--- a/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Artifacts do
+RSpec.describe Gitlab::Ci::Config::Entry::Artifacts do
let(:entry) { described_class.new(config) }
describe 'validation' do
diff --git a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
index d08ce30618d..f33176c3da3 100644
--- a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Bridge do
+RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
subject { described_class.new(config, name: :my_bridge) }
it_behaves_like 'with inheritable CI config' do
diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
index f7b14360af3..3501812b76e 100644
--- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Cache do
+RSpec.describe Gitlab::Ci::Config::Entry::Cache do
subject(:entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/commands_spec.rb b/spec/lib/gitlab/ci/config/entry/commands_spec.rb
index 8e7f9ab9706..439799fe973 100644
--- a/spec/lib/gitlab/ci/config/entry/commands_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/commands_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Commands do
+RSpec.describe Gitlab::Ci::Config::Entry::Commands do
let(:entry) { described_class.new(config) }
context 'when entry config value is an array of strings' do
diff --git a/spec/lib/gitlab/ci/config/entry/coverage_spec.rb b/spec/lib/gitlab/ci/config/entry/coverage_spec.rb
index 877e3ec6216..c4353e822ae 100644
--- a/spec/lib/gitlab/ci/config/entry/coverage_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/coverage_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Coverage do
+RSpec.describe Gitlab::Ci::Config::Entry::Coverage do
let(:entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/default_spec.rb b/spec/lib/gitlab/ci/config/entry/default_spec.rb
index 23c62bbf92a..6e46d02a96e 100644
--- a/spec/lib/gitlab/ci/config/entry/default_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/default_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Default do
+RSpec.describe Gitlab::Ci::Config::Entry::Default do
let(:entry) { described_class.new(config) }
it_behaves_like 'with inheritable CI config' do
diff --git a/spec/lib/gitlab/ci/config/entry/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
index 8c21d5342cc..22d38913787 100644
--- a/spec/lib/gitlab/ci/config/entry/environment_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Environment do
+RSpec.describe Gitlab::Ci::Config::Entry::Environment do
let(:entry) { described_class.new(config) }
before do
diff --git a/spec/lib/gitlab/ci/config/entry/files_spec.rb b/spec/lib/gitlab/ci/config/entry/files_spec.rb
index 2bebbd7b198..6a101d80c7d 100644
--- a/spec/lib/gitlab/ci/config/entry/files_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/files_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Files do
+RSpec.describe Gitlab::Ci::Config::Entry::Files do
let(:entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/hidden_spec.rb b/spec/lib/gitlab/ci/config/entry/hidden_spec.rb
index 40b73352676..090ef67f39d 100644
--- a/spec/lib/gitlab/ci/config/entry/hidden_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/hidden_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Hidden do
+RSpec.describe Gitlab::Ci::Config::Entry::Hidden do
describe '.matching?' do
subject { described_class.matching?(name, {}) }
diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb
index de3e887a6ed..c3d91057328 100644
--- a/spec/lib/gitlab/ci/config/entry/image_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Image do
+RSpec.describe Gitlab::Ci::Config::Entry::Image do
let(:entry) { described_class.new(config) }
context 'when configuration is a string' do
diff --git a/spec/lib/gitlab/ci/config/entry/include_spec.rb b/spec/lib/gitlab/ci/config/entry/include_spec.rb
index bab11f26fa1..3e816f70c03 100644
--- a/spec/lib/gitlab/ci/config/entry/include_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/include_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ::Gitlab::Ci::Config::Entry::Include do
+RSpec.describe ::Gitlab::Ci::Config::Entry::Include do
subject(:include_entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/inherit/default_spec.rb b/spec/lib/gitlab/ci/config/entry/inherit/default_spec.rb
index 073f93ce542..7cd9b0acb99 100644
--- a/spec/lib/gitlab/ci/config/entry/inherit/default_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/inherit/default_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ::Gitlab::Ci::Config::Entry::Inherit::Default do
+RSpec.describe ::Gitlab::Ci::Config::Entry::Inherit::Default do
using RSpec::Parameterized::TableSyntax
subject { described_class.new(config) }
diff --git a/spec/lib/gitlab/ci/config/entry/inherit/variables_spec.rb b/spec/lib/gitlab/ci/config/entry/inherit/variables_spec.rb
index 06deed11c15..b1a8fbcdbe0 100644
--- a/spec/lib/gitlab/ci/config/entry/inherit/variables_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/inherit/variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ::Gitlab::Ci::Config::Entry::Inherit::Variables do
+RSpec.describe ::Gitlab::Ci::Config::Entry::Inherit::Variables do
using RSpec::Parameterized::TableSyntax
subject { described_class.new(config) }
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index a721f86bb49..180c52ee1ab 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Job do
+RSpec.describe Gitlab::Ci::Config::Entry::Job do
let(:entry) { described_class.new(config, name: :rspec) }
it_behaves_like 'with inheritable CI config' do
diff --git a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
index 203342ab620..8561bd330b7 100644
--- a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Jobs do
+RSpec.describe Gitlab::Ci::Config::Entry::Jobs do
let(:entry) { described_class.new(config) }
let(:config) do
diff --git a/spec/lib/gitlab/ci/config/entry/key_spec.rb b/spec/lib/gitlab/ci/config/entry/key_spec.rb
index 327607e2266..4ee1ffb29ad 100644
--- a/spec/lib/gitlab/ci/config/entry/key_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/key_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Key do
+RSpec.describe Gitlab::Ci::Config::Entry::Key do
let(:entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/kubernetes_spec.rb b/spec/lib/gitlab/ci/config/entry/kubernetes_spec.rb
index 468e83ec506..53809d2d549 100644
--- a/spec/lib/gitlab/ci/config/entry/kubernetes_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/kubernetes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Kubernetes do
+RSpec.describe Gitlab::Ci::Config::Entry::Kubernetes do
subject { described_class.new(config) }
describe 'attributes' do
diff --git a/spec/lib/gitlab/ci/config/entry/need_spec.rb b/spec/lib/gitlab/ci/config/entry/need_spec.rb
index 92b71c5f6cc..5a826bf8282 100644
--- a/spec/lib/gitlab/ci/config/entry/need_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/need_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ::Gitlab::Ci::Config::Entry::Need do
+RSpec.describe ::Gitlab::Ci::Config::Entry::Need do
subject(:need) { described_class.new(config) }
shared_examples 'job type' do
diff --git a/spec/lib/gitlab/ci/config/entry/needs_spec.rb b/spec/lib/gitlab/ci/config/entry/needs_spec.rb
index b8b84b5efd2..f3b9d0c3c84 100644
--- a/spec/lib/gitlab/ci/config/entry/needs_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/needs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ::Gitlab::Ci::Config::Entry::Needs do
+RSpec.describe ::Gitlab::Ci::Config::Entry::Needs do
subject(:needs) { described_class.new(config) }
before do
diff --git a/spec/lib/gitlab/ci/config/entry/paths_spec.rb b/spec/lib/gitlab/ci/config/entry/paths_spec.rb
index 221d5ae5863..dd4e7befc46 100644
--- a/spec/lib/gitlab/ci/config/entry/paths_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/paths_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Paths do
+RSpec.describe Gitlab::Ci::Config::Entry::Paths do
let(:entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/policy_spec.rb b/spec/lib/gitlab/ci/config/entry/policy_spec.rb
index a606eb303e7..46800055dd9 100644
--- a/spec/lib/gitlab/ci/config/entry/policy_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/policy_spec.rb
@@ -4,7 +4,7 @@ require 'fast_spec_helper'
require 'support/helpers/stub_feature_flags'
require_dependency 'active_model'
-describe Gitlab::Ci::Config::Entry::Policy do
+RSpec.describe Gitlab::Ci::Config::Entry::Policy do
let(:entry) { described_class.new(config) }
context 'when using simplified policy' do
diff --git a/spec/lib/gitlab/ci/config/entry/port_spec.rb b/spec/lib/gitlab/ci/config/entry/port_spec.rb
index 5f8f294334e..e2840c07f6b 100644
--- a/spec/lib/gitlab/ci/config/entry/port_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/port_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Port do
+RSpec.describe Gitlab::Ci::Config::Entry::Port do
let(:entry) { described_class.new(config) }
before do
diff --git a/spec/lib/gitlab/ci/config/entry/ports_spec.rb b/spec/lib/gitlab/ci/config/entry/ports_spec.rb
index 2063bd1d86c..f738c4ee875 100644
--- a/spec/lib/gitlab/ci/config/entry/ports_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/ports_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Ports do
+RSpec.describe Gitlab::Ci::Config::Entry::Ports do
let(:entry) { described_class.new(config) }
before do
diff --git a/spec/lib/gitlab/ci/config/entry/prefix_spec.rb b/spec/lib/gitlab/ci/config/entry/prefix_spec.rb
index 8132a674488..b337747f5d6 100644
--- a/spec/lib/gitlab/ci/config/entry/prefix_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/prefix_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Prefix do
+RSpec.describe Gitlab::Ci::Config::Entry::Prefix do
let(:entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
index 8447a29c772..26a4355fb17 100644
--- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Processable do
+RSpec.describe Gitlab::Ci::Config::Entry::Processable do
let(:node_class) do
Class.new(::Gitlab::Config::Entry::Node) do
include Gitlab::Ci::Config::Entry::Processable
diff --git a/spec/lib/gitlab/ci/config/entry/release/assets/link_spec.rb b/spec/lib/gitlab/ci/config/entry/release/assets/link_spec.rb
index 0e346de3d9e..bc320258412 100644
--- a/spec/lib/gitlab/ci/config/entry/release/assets/link_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/release/assets/link_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Release::Assets::Link do
+RSpec.describe Gitlab::Ci::Config::Entry::Release::Assets::Link do
let(:entry) { described_class.new(config) }
describe 'validation' do
diff --git a/spec/lib/gitlab/ci/config/entry/release/assets/links_spec.rb b/spec/lib/gitlab/ci/config/entry/release/assets/links_spec.rb
index d12e8d966ab..440745d9eb3 100644
--- a/spec/lib/gitlab/ci/config/entry/release/assets/links_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/release/assets/links_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Release::Assets::Links do
+RSpec.describe Gitlab::Ci::Config::Entry::Release::Assets::Links do
let(:entry) { described_class.new(config) }
describe 'validation' do
diff --git a/spec/lib/gitlab/ci/config/entry/release/assets_spec.rb b/spec/lib/gitlab/ci/config/entry/release/assets_spec.rb
index 08ad5764eaa..3d44d7d9903 100644
--- a/spec/lib/gitlab/ci/config/entry/release/assets_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/release/assets_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Release::Assets do
+RSpec.describe Gitlab::Ci::Config::Entry::Release::Assets do
let(:entry) { described_class.new(config) }
describe 'validation' do
diff --git a/spec/lib/gitlab/ci/config/entry/release_spec.rb b/spec/lib/gitlab/ci/config/entry/release_spec.rb
index 500897569e9..1559a7467b3 100644
--- a/spec/lib/gitlab/ci/config/entry/release_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/release_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Release do
+RSpec.describe Gitlab::Ci::Config::Entry::Release do
let(:entry) { described_class.new(config) }
describe 'validation' do
diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
index 2c12a88dedb..8afa4fed52f 100644
--- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Reports do
+RSpec.describe Gitlab::Ci::Config::Entry::Reports do
let(:entry) { described_class.new(config) }
describe 'validates ALLOWED_KEYS' do
diff --git a/spec/lib/gitlab/ci/config/entry/retry_spec.rb b/spec/lib/gitlab/ci/config/entry/retry_spec.rb
index 67253c71f6b..b38387a437e 100644
--- a/spec/lib/gitlab/ci/config/entry/retry_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/retry_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Retry do
+RSpec.describe Gitlab::Ci::Config::Entry::Retry do
let(:entry) { described_class.new(config) }
shared_context 'when retry value is a numeric', :numeric do
diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb
index ba2dbf72fba..140b3c4f55b 100644
--- a/spec/lib/gitlab/ci/config/entry/root_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Root do
+RSpec.describe Gitlab::Ci::Config::Entry::Root do
let(:root) { described_class.new(hash) }
describe '.nodes' do
diff --git a/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb b/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
index 20db5f02fc7..4a43e6c9a86 100644
--- a/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
@@ -5,7 +5,7 @@ require 'gitlab_chronic_duration'
require 'support/helpers/stub_feature_flags'
require_dependency 'active_model'
-describe Gitlab::Ci::Config::Entry::Rules::Rule do
+RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
let(:factory) do
Gitlab::Config::Entry::Factory.new(described_class)
.metadata(metadata)
diff --git a/spec/lib/gitlab/ci/config/entry/rules_spec.rb b/spec/lib/gitlab/ci/config/entry/rules_spec.rb
index 3c050801023..7d26365e7b3 100644
--- a/spec/lib/gitlab/ci/config/entry/rules_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/rules_spec.rb
@@ -4,7 +4,7 @@ require 'fast_spec_helper'
require 'support/helpers/stub_feature_flags'
require_dependency 'active_model'
-describe Gitlab::Ci::Config::Entry::Rules do
+RSpec.describe Gitlab::Ci::Config::Entry::Rules do
let(:factory) do
Gitlab::Config::Entry::Factory.new(described_class)
.metadata(metadata)
diff --git a/spec/lib/gitlab/ci/config/entry/script_spec.rb b/spec/lib/gitlab/ci/config/entry/script_spec.rb
index 57dc20ea628..1ddf7881e81 100644
--- a/spec/lib/gitlab/ci/config/entry/script_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/script_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Script do
+RSpec.describe Gitlab::Ci::Config::Entry::Script do
let(:entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb
index 66cca100688..9fbc14c19b9 100644
--- a/spec/lib/gitlab/ci/config/entry/service_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Service do
+RSpec.describe Gitlab::Ci::Config::Entry::Service do
let(:entry) { described_class.new(config) }
before do
diff --git a/spec/lib/gitlab/ci/config/entry/services_spec.rb b/spec/lib/gitlab/ci/config/entry/services_spec.rb
index 764f783b083..e4f8a348d21 100644
--- a/spec/lib/gitlab/ci/config/entry/services_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/services_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Services do
+RSpec.describe Gitlab::Ci::Config::Entry::Services do
let(:entry) { described_class.new(config) }
before do
diff --git a/spec/lib/gitlab/ci/config/entry/stage_spec.rb b/spec/lib/gitlab/ci/config/entry/stage_spec.rb
index 574fa00575a..2a105fb978e 100644
--- a/spec/lib/gitlab/ci/config/entry/stage_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/stage_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Stage do
+RSpec.describe Gitlab::Ci::Config::Entry::Stage do
let(:stage) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/stages_spec.rb b/spec/lib/gitlab/ci/config/entry/stages_spec.rb
index 3e6ff8eca28..1dd11bb03f8 100644
--- a/spec/lib/gitlab/ci/config/entry/stages_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/stages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Stages do
+RSpec.describe Gitlab::Ci::Config::Entry::Stages do
let(:entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/trigger_spec.rb b/spec/lib/gitlab/ci/config/entry/trigger_spec.rb
index dfd9807583c..5b4289741f3 100644
--- a/spec/lib/gitlab/ci/config/entry/trigger_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/trigger_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Trigger do
+RSpec.describe Gitlab::Ci::Config::Entry::Trigger do
subject { described_class.new(config) }
context 'when trigger config is a non-empty string' do
diff --git a/spec/lib/gitlab/ci/config/entry/variables_spec.rb b/spec/lib/gitlab/ci/config/entry/variables_spec.rb
index 1320b366367..d6391092f63 100644
--- a/spec/lib/gitlab/ci/config/entry/variables_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Variables do
+RSpec.describe Gitlab::Ci::Config::Entry::Variables do
let(:entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/workflow_spec.rb b/spec/lib/gitlab/ci/config/entry/workflow_spec.rb
index f2832b94bf0..3d19832e13d 100644
--- a/spec/lib/gitlab/ci/config/entry/workflow_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/workflow_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::Entry::Workflow do
+RSpec.describe Gitlab::Ci::Config::Entry::Workflow do
let(:factory) { Gitlab::Config::Entry::Factory.new(described_class).value(rules_hash) }
let(:config) { factory.create! }
diff --git a/spec/lib/gitlab/ci/config/extendable/entry_spec.rb b/spec/lib/gitlab/ci/config/extendable/entry_spec.rb
index e00104e3c68..69aa3bab77a 100644
--- a/spec/lib/gitlab/ci/config/extendable/entry_spec.rb
+++ b/spec/lib/gitlab/ci/config/extendable/entry_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Config::Extendable::Entry do
+RSpec.describe Gitlab::Ci::Config::Extendable::Entry do
describe '.new' do
context 'when entry key is not included in the context hash' do
it 'raises error' do
diff --git a/spec/lib/gitlab/ci/config/extendable_spec.rb b/spec/lib/gitlab/ci/config/extendable_spec.rb
index 874b224067b..481f55d790e 100644
--- a/spec/lib/gitlab/ci/config/extendable_spec.rb
+++ b/spec/lib/gitlab/ci/config/extendable_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Config::Extendable do
+RSpec.describe Gitlab::Ci::Config::Extendable do
subject { described_class.new(hash) }
describe '#each' do
diff --git a/spec/lib/gitlab/ci/config/external/context_spec.rb b/spec/lib/gitlab/ci/config/external/context_spec.rb
index 610646ca85a..4b9adf7e87b 100644
--- a/spec/lib/gitlab/ci/config/external/context_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/context_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Config::External::Context do
+RSpec.describe Gitlab::Ci::Config::External::Context do
let(:project) { double('Project') }
let(:user) { double('User') }
let(:sha) { '12345' }
diff --git a/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb b/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb
index a8eb13c47bc..8dd92c5b5fd 100644
--- a/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::External::File::Artifact do
+RSpec.describe Gitlab::Ci::Config::External::File::Artifact do
let(:parent_pipeline) { create(:ci_pipeline) }
let(:context) do
Gitlab::Ci::Config::External::Context.new(parent_pipeline: parent_pipeline)
diff --git a/spec/lib/gitlab/ci/config/external/file/base_spec.rb b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
index d472d6527e2..445edb253fd 100644
--- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::External::File::Base do
+RSpec.describe Gitlab::Ci::Config::External::File::Base do
let(:context_params) { { sha: 'HEAD' } }
let(:context) { Gitlab::Ci::Config::External::Context.new(**context_params) }
diff --git a/spec/lib/gitlab/ci/config/external/file/local_spec.rb b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
index c9851239859..993a07568de 100644
--- a/spec/lib/gitlab/ci/config/external/file/local_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::External::File::Local do
+RSpec.describe Gitlab::Ci::Config::External::File::Local do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let(:sha) { '12345' }
diff --git a/spec/lib/gitlab/ci/config/external/file/project_spec.rb b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
index 4d8f0dbc861..a5e4e27df6f 100644
--- a/spec/lib/gitlab/ci/config/external/file/project_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::External::File::Project do
+RSpec.describe Gitlab::Ci::Config::External::File::Project do
let_it_be(:context_project) { create(:project) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
index a23cce9b757..ab60ac215ba 100644
--- a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::External::File::Remote do
+RSpec.describe Gitlab::Ci::Config::External::File::Remote do
include StubRequests
let(:context_params) { { sha: '12345' } }
diff --git a/spec/lib/gitlab/ci/config/external/file/template_spec.rb b/spec/lib/gitlab/ci/config/external/file/template_spec.rb
index 7ea5aadac52..ad1d93a64a1 100644
--- a/spec/lib/gitlab/ci/config/external/file/template_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/template_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::External::File::Template do
+RSpec.describe Gitlab::Ci::Config::External::File::Template do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let(:context_params) { { project: project, sha: '12345', user: user } }
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index fa358f36527..bf14d8d6b34 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::External::Mapper do
+RSpec.describe Gitlab::Ci::Config::External::Mapper do
include StubRequests
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb
index 45f646660a7..b2cf36b2597 100644
--- a/spec/lib/gitlab/ci/config/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config::External::Processor do
+RSpec.describe Gitlab::Ci::Config::External::Processor do
include StubRequests
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/lib/gitlab/ci/config/normalizer_spec.rb b/spec/lib/gitlab/ci/config/normalizer_spec.rb
index db62fb7524d..d3d165ba00f 100644
--- a/spec/lib/gitlab/ci/config/normalizer_spec.rb
+++ b/spec/lib/gitlab/ci/config/normalizer_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Config::Normalizer do
+RSpec.describe Gitlab::Ci::Config::Normalizer do
let(:job_name) { :rspec }
let(:job_config) { { script: 'rspec', parallel: 5, name: 'rspec' } }
let(:config) { { job_name => job_config } }
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 3b65dbe11ec..18be9558829 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Config do
+RSpec.describe Gitlab::Ci::Config do
include StubRequests
let_it_be(:user) { create(:user) }
diff --git a/spec/lib/gitlab/ci/cron_parser_spec.rb b/spec/lib/gitlab/ci/cron_parser_spec.rb
index 8f9f3d7fa37..f724825a9cc 100644
--- a/spec/lib/gitlab/ci/cron_parser_spec.rb
+++ b/spec/lib/gitlab/ci/cron_parser_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::CronParser do
+RSpec.describe Gitlab::Ci::CronParser do
shared_examples_for "returns time in the future" do
it { is_expected.to be > Time.now }
end
diff --git a/spec/lib/gitlab/ci/jwt_spec.rb b/spec/lib/gitlab/ci/jwt_spec.rb
index f2897708b08..a15f3310dab 100644
--- a/spec/lib/gitlab/ci/jwt_spec.rb
+++ b/spec/lib/gitlab/ci/jwt_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Jwt do
+RSpec.describe Gitlab::Ci::Jwt do
let(:namespace) { build_stubbed(:namespace) }
let(:project) { build_stubbed(:project, namespace: namespace) }
let(:user) { build_stubbed(:user) }
diff --git a/spec/lib/gitlab/ci/mask_secret_spec.rb b/spec/lib/gitlab/ci/mask_secret_spec.rb
index 6607aaae399..7b2d6b58518 100644
--- a/spec/lib/gitlab/ci/mask_secret_spec.rb
+++ b/spec/lib/gitlab/ci/mask_secret_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::MaskSecret do
+RSpec.describe Gitlab::Ci::MaskSecret do
subject { described_class }
describe '#mask' do
diff --git a/spec/lib/gitlab/ci/parsers/accessibility/pa11y_spec.rb b/spec/lib/gitlab/ci/parsers/accessibility/pa11y_spec.rb
index 4d87e3b201a..dda61bd5f6b 100644
--- a/spec/lib/gitlab/ci/parsers/accessibility/pa11y_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/accessibility/pa11y_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Parsers::Accessibility::Pa11y do
+RSpec.describe Gitlab::Ci::Parsers::Accessibility::Pa11y do
describe '#parse!' do
subject { described_class.new.parse!(pa11y, accessibility_report) }
diff --git a/spec/lib/gitlab/ci/parsers/coverage/cobertura_spec.rb b/spec/lib/gitlab/ci/parsers/coverage/cobertura_spec.rb
index e97544683db..08a3fbd7867 100644
--- a/spec/lib/gitlab/ci/parsers/coverage/cobertura_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/coverage/cobertura_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Parsers::Coverage::Cobertura do
+RSpec.describe Gitlab::Ci::Parsers::Coverage::Cobertura do
describe '#parse!' do
subject { described_class.new.parse!(cobertura, coverage_report) }
diff --git a/spec/lib/gitlab/ci/parsers/terraform/tfplan_spec.rb b/spec/lib/gitlab/ci/parsers/terraform/tfplan_spec.rb
index 655da6a86e3..f487fccdab7 100644
--- a/spec/lib/gitlab/ci/parsers/terraform/tfplan_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/terraform/tfplan_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Parsers::Terraform::Tfplan do
+RSpec.describe Gitlab::Ci::Parsers::Terraform::Tfplan do
describe '#parse!' do
let(:artifact) { create(:ci_job_artifact, :terraform) }
diff --git a/spec/lib/gitlab/ci/parsers/test/junit_spec.rb b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
index 7b7ace02bba..1f497dea2bf 100644
--- a/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Parsers::Test::Junit do
+RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
describe '#parse!' do
subject { described_class.new.parse!(junit, test_suite, args) }
diff --git a/spec/lib/gitlab/ci/parsers_spec.rb b/spec/lib/gitlab/ci/parsers_spec.rb
index 0a266e7a206..db9a5775d9f 100644
--- a/spec/lib/gitlab/ci/parsers_spec.rb
+++ b/spec/lib/gitlab/ci/parsers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Parsers do
+RSpec.describe Gitlab::Ci::Parsers do
describe '.fabricate!' do
subject { described_class.fabricate!(file_type) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/build/associations_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/build/associations_spec.rb
index 542a2462b59..5fa414f5bd1 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/build/associations_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/build/associations_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Build::Associations do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Build::Associations do
let(:project) { create(:project, :repository) }
let(:user) { create(:user, developer_projects: [project]) }
let(:pipeline) { Ci::Pipeline.new }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
index 094563bd979..6da565a2bf6 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Build do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Build do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user, developer_projects: [project]) }
let(:pipeline) { Ci::Pipeline.new }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
index 56707f4e6e4..f9daff91871 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Command do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Command do
let_it_be(:project) { create(:project, :repository) }
describe '#initialize' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
index fc95bb602c2..55e5b97e9bf 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Config::Content do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
let(:project) { create(:project, ci_config_path: ci_config_path) }
let(:pipeline) { build(:ci_pipeline, project: project) }
let(:command) { Gitlab::Ci::Pipeline::Chain::Command.new(project: project) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb
index f18ad05a704..d60ecc80a6e 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Create do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Create do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb
index 7b76adaf683..4ae51ac8bf9 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:pipeline) { build(:ci_pipeline, project: project) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
index 6dab5679e60..8c02121857a 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Populate do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs_spec.rb
index 92eadf5548c..8b9de16ce5f 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ::Gitlab::Ci::Pipeline::Chain::RemoveUnwantedChatJobs do
+RSpec.describe ::Gitlab::Ci::Pipeline::Chain::RemoveUnwantedChatJobs do
let(:project) { create(:project) }
let(:pipeline) do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
index 1e1d5c2a724..f83cd49d780 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Seed do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
let(:project) { create(:project, :repository) }
let(:user) { create(:user, developer_projects: [project]) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
index ea04862ed74..5d20b1b8fda 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Sequence do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Sequence do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb
index 55d6d35340e..e4768f2ef0d 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Skip do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Skip do
let_it_be(:project, reload: true) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:pipeline, reload: true) { create(:ci_pipeline, project: project) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb
index 8bf8bdf08ff..ae3270cb9b2 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
let_it_be(:project, reload: true) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
index 9a2cf014007..931c62701ce 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Validate::External do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:pipeline) { build(:ci_empty_pipeline, user: user, project: project) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
index 83271007ab0..1dc2e0a1822 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Chain::Validate::Repository do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::Repository do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let(:pipeline) { build_stubbed(:ci_pipeline) }
diff --git a/spec/lib/gitlab/ci/pipeline/duration_spec.rb b/spec/lib/gitlab/ci/pipeline/duration_spec.rb
index a4984092f35..e0b4928d7f7 100644
--- a/spec/lib/gitlab/ci/pipeline/duration_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/duration_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Duration do
+RSpec.describe Gitlab::Ci::Pipeline::Duration do
let(:calculated_duration) { calculate(data) }
shared_examples 'calculating duration' do
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb
index 847d613dba3..6601537a2d3 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
require 'rspec-parameterized'
-describe Gitlab::Ci::Pipeline::Expression::Lexeme::And do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::And do
let(:left) { double('left', evaluate: nil) }
let(:right) { double('right', evaluate: nil) }
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb
index 0e13681a4cf..2bed47f0a87 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Expression::Lexeme::Equals do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Equals do
let(:left) { double('left') }
let(:right) { double('right') }
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb
index a527783ffac..efcea0b0e09 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
require_dependency 're2'
-describe Gitlab::Ci::Pipeline::Expression::Lexeme::Matches do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Matches do
let(:left) { double('left') }
let(:right) { double('right') }
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb
index a3a48f83b27..a81e1713ef0 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Expression::Lexeme::NotEquals do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::NotEquals do
let(:left) { double('left') }
let(:right) { double('right') }
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb
index fb4238ecaf3..f44fe19f86d 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
require_dependency 're2'
-describe Gitlab::Ci::Pipeline::Expression::Lexeme::NotMatches do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::NotMatches do
let(:left) { double('left') }
let(:right) { double('right') }
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/null_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/null_spec.rb
index 7013c6bacbb..49686d1a9bd 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/null_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/null_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Expression::Lexeme::Null do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Null do
describe '.build' do
it 'creates a new instance of the token' do
expect(described_class.build('null'))
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb
index 15505ebc82b..7fe445975eb 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
require 'rspec-parameterized'
-describe Gitlab::Ci::Pipeline::Expression::Lexeme::Or do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Or do
let(:left) { double('left', evaluate: nil) }
let(:right) { double('right', evaluate: nil) }
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb
index 2cc25a07417..1a56a91c471 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Expression::Lexeme::Pattern do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Pattern do
describe '.build' do
it 'creates a new instance of the token' do
expect(described_class.build('/.*/'))
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/string_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/string_spec.rb
index 2a6b90d127f..c6d0d2534a5 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/string_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/string_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Expression::Lexeme::String do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::String do
describe '.build' do
it 'creates a new instance of the token' do
expect(described_class.build('"my string"'))
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/variable_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/variable_spec.rb
index 29e26930249..115674edc48 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/variable_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/variable_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Expression::Lexeme::Variable do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Variable do
describe '.build' do
it 'creates a new instance of the token' do
expect(described_class.build('$VARIABLE'))
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
index 2b0cee2d6f2..61c6ced4dac 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Expression::Lexer do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexer do
let(:token_class) do
Gitlab::Ci::Pipeline::Expression::Token
end
diff --git a/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb
index 10adfa18af6..1704cabfd2e 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Pipeline::Expression::Parser do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Parser do
describe '#tree' do
context 'when using two operators' do
it 'returns a reverse descent parse tree' do
diff --git a/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb
index 79ee4d07e3a..642d6816030 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
require 'rspec-parameterized'
-describe Gitlab::Ci::Pipeline::Expression::Statement do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Statement do
subject do
described_class.new(text, variables)
end
diff --git a/spec/lib/gitlab/ci/pipeline/expression/token_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/token_spec.rb
index aa807cecb72..137e38d2ead 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/token_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/token_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Pipeline::Expression::Token do
+RSpec.describe Gitlab::Ci::Pipeline::Expression::Token do
let(:value) { '$VARIABLE' }
let(:lexeme) { Gitlab::Ci::Pipeline::Expression::Lexeme::Variable }
diff --git a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb
index fe882983333..ae423fa04f9 100644
--- a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Preloader do
+RSpec.describe Gitlab::Ci::Pipeline::Preloader do
let(:stage) { double(:stage) }
let(:commit) { double(:commit) }
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb
index fe19244659f..74c014b6408 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
+RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:head_sha) { project.repository.head_commit.id }
let_it_be(:pipeline) { create(:ci_pipeline, project: project, sha: head_sha) }
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build/resource_group_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build/resource_group_spec.rb
index bf6985156d3..8fcc242ba5f 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build/resource_group_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build/resource_group_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Seed::Build::ResourceGroup do
+RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::ResourceGroup do
let_it_be(:project) { create(:project) }
let(:job) { build(:ci_build, project: project) }
let(:seed) { described_class.new(job, resource_group_key) }
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 01f65939da7..2dea554fe56 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Seed::Build do
+RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
let(:project) { create(:project, :repository) }
let(:head_sha) { project.repository.head_commit.id }
let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: head_sha) }
diff --git a/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb
index ceb3cb28bc9..0268d6e2650 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Seed::Deployment do
+RSpec.describe Gitlab::Ci::Pipeline::Seed::Deployment do
let_it_be(:project, refind: true) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline, project: project,
diff --git a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb
index 4c0464e5e7c..0c8a0de2f34 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Seed::Environment do
+RSpec.describe Gitlab::Ci::Pipeline::Seed::Environment do
let_it_be(:project) { create(:project) }
let(:job) { build(:ci_build, project: project) }
let(:seed) { described_class.new(job) }
diff --git a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
index 875fd457bd0..4b9db9fa6c6 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Pipeline::Seed::Stage do
+RSpec.describe Gitlab::Ci::Pipeline::Seed::Stage do
let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:previous_stages) { [] }
diff --git a/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb
index 31a330f46b1..240ede790e0 100644
--- a/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Reports::AccessibilityReportsComparer do
+RSpec.describe Gitlab::Ci::Reports::AccessibilityReportsComparer do
let(:comparer) { described_class.new(base_reports, head_reports) }
let(:base_reports) { Gitlab::Ci::Reports::AccessibilityReports.new }
let(:head_reports) { Gitlab::Ci::Reports::AccessibilityReports.new }
diff --git a/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb b/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb
index 0dc13b464b1..8c35b2a34cf 100644
--- a/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Reports::AccessibilityReports do
+RSpec.describe Gitlab::Ci::Reports::AccessibilityReports do
let(:accessibility_report) { described_class.new }
let(:url) { 'https://gitlab.com' }
let(:data) do
diff --git a/spec/lib/gitlab/ci/reports/coverage_reports_spec.rb b/spec/lib/gitlab/ci/reports/coverage_reports_spec.rb
index 7cf43ceab32..41ebae863ee 100644
--- a/spec/lib/gitlab/ci/reports/coverage_reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/coverage_reports_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Reports::CoverageReports do
+RSpec.describe Gitlab::Ci::Reports::CoverageReports do
let(:coverage_report) { described_class.new }
it { expect(coverage_report.files).to eq({}) }
diff --git a/spec/lib/gitlab/ci/reports/terraform_reports_spec.rb b/spec/lib/gitlab/ci/reports/terraform_reports_spec.rb
index bfab30543ed..5e94fe2bb3d 100644
--- a/spec/lib/gitlab/ci/reports/terraform_reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/terraform_reports_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Reports::TerraformReports do
+RSpec.describe Gitlab::Ci::Reports::TerraformReports do
it 'initializes plans with and empty hash' do
expect(subject.plans).to eq({})
end
diff --git a/spec/lib/gitlab/ci/reports/test_case_spec.rb b/spec/lib/gitlab/ci/reports/test_case_spec.rb
index b5883867983..8882defbd9e 100644
--- a/spec/lib/gitlab/ci/reports/test_case_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_case_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Reports::TestCase do
+RSpec.describe Gitlab::Ci::Reports::TestCase do
describe '#initialize' do
let(:test_case) { described_class.new(params)}
diff --git a/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
index d731afe1fff..3483dddca3a 100644
--- a/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Reports::TestReportsComparer do
+RSpec.describe Gitlab::Ci::Reports::TestReportsComparer do
include TestReportsHelper
let(:comparer) { described_class.new(base_reports, head_reports) }
diff --git a/spec/lib/gitlab/ci/reports/test_reports_spec.rb b/spec/lib/gitlab/ci/reports/test_reports_spec.rb
index e51728496e1..502859852f2 100644
--- a/spec/lib/gitlab/ci/reports/test_reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_reports_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Reports::TestReports do
+RSpec.describe Gitlab::Ci::Reports::TestReports do
include TestReportsHelper
let(:test_reports) { described_class.new }
diff --git a/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
index 2d2179a690b..6bb6771678a 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Reports::TestSuiteComparer do
+RSpec.describe Gitlab::Ci::Reports::TestSuiteComparer do
include TestReportsHelper
let(:comparer) { described_class.new(name, base_suite, head_suite) }
diff --git a/spec/lib/gitlab/ci/reports/test_suite_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
index e0b2593353a..94915b41a81 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Reports::TestSuite do
+RSpec.describe Gitlab::Ci::Reports::TestSuite do
include TestReportsHelper
let(:test_suite) { described_class.new('Rspec') }
diff --git a/spec/lib/gitlab/ci/status/bridge/factory_spec.rb b/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
index 6c67864855d..021b777a0ff 100644
--- a/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Ci::Status::Bridge::Factory do
+RSpec.describe Gitlab::Ci::Status::Bridge::Factory do
let(:user) { create(:user) }
let(:project) { bridge.project }
let(:status) { factory.fabricate! }
diff --git a/spec/lib/gitlab/static_site_editor/config_spec.rb b/spec/lib/gitlab/static_site_editor/config_spec.rb
index 4cfda83b8f6..0d50e3bfdca 100644
--- a/spec/lib/gitlab/static_site_editor/config_spec.rb
+++ b/spec/lib/gitlab/static_site_editor/config_spec.rb
@@ -30,6 +30,22 @@ describe Gitlab::StaticSiteEditor::Config do
)
end
+ context 'when file has .md.erb extension' do
+ let(:file_path) { 'README.md.erb' }
+
+ before do
+ repository.create_file(
+ project.creator,
+ file_path,
+ '',
+ message: 'message',
+ branch_name: 'master'
+ )
+ end
+
+ it { is_expected.to include(is_supported_content: 'true') }
+ end
+
context 'when file path is nested' do
let(:file_path) { 'lib/README.md' }