diff options
47 files changed, 841 insertions, 456 deletions
diff --git a/.rubocop_todo/layout/first_array_element_indentation.yml b/.rubocop_todo/layout/first_array_element_indentation.yml index 8c4dfa12c2e..7b90488a5c4 100644 --- a/.rubocop_todo/layout/first_array_element_indentation.yml +++ b/.rubocop_todo/layout/first_array_element_indentation.yml @@ -5,26 +5,6 @@ Layout/FirstArrayElementIndentation: Exclude: - 'spec/lib/gitlab/github_import/importer/issues_importer_spec.rb' - 'spec/lib/gitlab/search/found_blob_spec.rb' - - 'spec/lib/gitlab/serializer/ci/variables_spec.rb' - - 'spec/lib/gitlab/sidekiq_config_spec.rb' - - 'spec/lib/gitlab/ssh_public_key_spec.rb' - - 'spec/lib/gitlab/usage_data/topology_spec.rb' - - 'spec/lib/gitlab/usage_data_spec.rb' - - 'spec/lib/gitlab/utils_spec.rb' - - 'spec/lib/gitlab/webpack/manifest_spec.rb' - - 'spec/lib/google_api/cloud_platform/client_spec.rb' - - 'spec/lib/peek/views/bullet_detailed_spec.rb' - - 'spec/lib/system_check/incoming_email_check_spec.rb' - - 'spec/lib/unnested_in_filters/rewriter_spec.rb' - - 'spec/migrations/add_premium_and_ultimate_plan_limits_spec.rb' - - 'spec/migrations/backfill_escalation_policies_for_oncall_schedules_spec.rb' - - 'spec/migrations/slice_merge_request_diff_commit_migrations_spec.rb' - - 'spec/models/analytics/cycle_analytics/project_stage_spec.rb' - - 'spec/models/application_setting_spec.rb' - - 'spec/models/ci/build_spec.rb' - - 'spec/models/ci/build_trace_spec.rb' - - 'spec/models/ci/daily_build_group_report_result_spec.rb' - - 'spec/models/ci/pipeline_spec.rb' - 'spec/models/ci/runner_version_spec.rb' - 'spec/models/repository_spec.rb' - 'spec/models/user_preference_spec.rb' diff --git a/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb b/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb index 1f90f394521..e42e59de78f 100644 --- a/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb +++ b/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb @@ -30,6 +30,9 @@ module Mutations argument :start_and_due_date_widget, ::Types::WorkItems::Widgets::StartAndDueDateUpdateInputType, required: false, description: 'Input for start and due date widget.' + argument :labels_widget, ::Types::WorkItems::Widgets::LabelsUpdateInputType, + required: false, + description: 'Input for labels widget.' end end end diff --git a/app/graphql/types/work_items/widgets/labels_update_input_type.rb b/app/graphql/types/work_items/widgets/labels_update_input_type.rb new file mode 100644 index 00000000000..d38b8cefa63 --- /dev/null +++ b/app/graphql/types/work_items/widgets/labels_update_input_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Types + module WorkItems + module Widgets + class LabelsUpdateInputType < BaseInputObject + graphql_name 'WorkItemWidgetLabelsUpdateInput' + + argument :add_label_ids, [Types::GlobalIDType[::Label]], + required: false, + description: 'Global IDs of labels to be added to the work item.', + prepare: ->(label_ids, _ctx) { label_ids.map(&:model_id) } + argument :remove_label_ids, [Types::GlobalIDType[::Label]], + required: false, + description: 'Global IDs of labels to be removed from the work item.', + prepare: ->(label_ids, _ctx) { label_ids.map(&:model_id) } + end + end + end +end diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb index 6dbd0f7bd7b..957c2afb6d2 100644 --- a/app/helpers/appearances_helper.rb +++ b/app/helpers/appearances_helper.rb @@ -14,7 +14,13 @@ module AppearancesHelper end def brand_image - image_tag(current_appearance.logo_path) if current_appearance&.logo? + image_tag(brand_image_path, alt: brand_title, class: 'gl-w-10') + end + + def brand_image_path + return current_appearance.logo_path if current_appearance&.logo? + + image_path('logo.svg') end def brand_text diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb index d6ffd3deafe..c42e3a5ff99 100644 --- a/app/helpers/wiki_helper.rb +++ b/app/helpers/wiki_helper.rb @@ -65,7 +65,10 @@ module WikiHelper reversed_direction = direction == 'desc' ? 'asc' : 'desc' icon_class = direction == 'desc' ? 'highest' : 'lowest' - link_to(wiki_path(wiki, action: :pages, sort: sort, direction: reversed_direction), + link_options = { action: :pages, direction: reversed_direction } + link_options[:sort] = sort unless wiki.disable_sorting? + + link_to(wiki_path(wiki, **link_options), type: 'button', class: link_class, title: _('Sort direction')) do sprite_icon("sort-#{icon_class}") end diff --git a/app/models/wiki.rb b/app/models/wiki.rb index afdac86d9c7..11ff4333a07 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -173,7 +173,7 @@ class Wiki end def empty? - !repository_exists? || list_pages(limit: 1).empty? + !repository_exists? || list_page_paths.empty? end def exists? @@ -191,13 +191,11 @@ class Wiki # Returns an Array of GitLab WikiPage instances or an # empty Array if this Wiki has no pages. def list_pages(limit: 0, sort: nil, direction: DIRECTION_ASC, load_content: false) - wiki.list_pages( - limit: limit, - sort: sort, - direction_desc: direction == DIRECTION_DESC, - load_content: load_content - ).map do |page| - WikiPage.new(self, page) + if list_pages_with_repository_rpcs? + create_wiki_repository unless repository_exists? + list_pages_with_repository_rpcs(limit: limit, sort: sort, direction: direction, load_content: load_content) + else + list_pages_with_legacy_wiki_service(limit: limit, sort: sort, direction: direction, load_content: load_content) end end @@ -383,6 +381,10 @@ class Wiki false end + def disable_sorting? + list_pages_with_repository_rpcs? + end + private def multi_commit_options(action, message = nil, title = nil) @@ -452,14 +454,7 @@ class Wiki def find_matched_file(title, version) escaped_path = RE2::Regexp.escape(sluggified_title(title)) - # We could not use ALLOWED_EXTENSIONS_REGEX constant or similar regexp with - # Regexp.union. The result combination complicated modifiers: - # /(?i-mx:md|mkdn?|mdown|markdown)|(?i-mx:rdoc).../ - # Regexp used by Gitaly is Go's Regexp package. It does not support those - # features. So, we have to compose another more-friendly regexp to pass to - # Gitaly side. - extension_regexp = Wiki::MARKUPS.map { |_, format| format[:extension_regex].source }.join("|") - path_regexp = Gitlab::EncodingHelper.encode_utf8_no_detect("(?i)^#{escaped_path}\\.(#{extension_regexp})$") + path_regexp = Gitlab::EncodingHelper.encode_utf8_no_detect("(?i)^#{escaped_path}\\.(#{file_extension_regexp})$") matched_files = repository.search_files_by_regexp(path_regexp, version) return if matched_files.blank? @@ -487,7 +482,7 @@ class Wiki format = find_page_format(path) page = Gitlab::Git::WikiPage.new( - url_path: sluggified_title(path.sub(/\.[^.]+\z/, "")), + url_path: sluggified_title(strip_extension(path)), title: canonicalize_filename(path), format: format, path: sluggified_title(path), @@ -509,6 +504,93 @@ class Wiki Feature.enabled?(:wiki_find_page_with_normal_repository_rpcs, group, type: :development) end + + def file_extension_regexp + # We could not use ALLOWED_EXTENSIONS_REGEX constant or similar regexp with + # Regexp.union. The result combination complicated modifiers: + # /(?i-mx:md|mkdn?|mdown|markdown)|(?i-mx:rdoc).../ + # Regexp used by Gitaly is Go's Regexp package. It does not support those + # features. So, we have to compose another more-friendly regexp to pass to + # Gitaly side. + Wiki::MARKUPS.map { |_, format| format[:extension_regex].source }.join("|") + end + + def strip_extension(path) + path.sub(/\.[^.]+\z/, "") + end + + def list_pages_with_repository_rpcs? + group = + if container.is_a?(::Group) + container + else + container.group + end + + Feature.enabled?(:wiki_list_pages_with_normal_repository_rpcs, group, type: :development) + end + + def list_page_paths + return [] if repository.empty? + + path_regexp = Gitlab::EncodingHelper.encode_utf8_no_detect("(?i)\\.(#{file_extension_regexp})$") + repository.search_files_by_regexp(path_regexp, default_branch) + end + + def list_pages_with_repository_rpcs(limit:, sort:, direction:, load_content:) + paths = list_page_paths + return [] if paths.empty? + + pages = paths.map do |path| + page = Gitlab::Git::WikiPage.new( + url_path: sluggified_title(strip_extension(path)), + title: canonicalize_filename(path), + format: find_page_format(path), + path: sluggified_title(path), + raw_data: '', + name: canonicalize_filename(path), + historical: false + ) + WikiPage.new(self, page) + end + sort_pages!(pages, sort, direction) + pages = pages.take(limit) if limit > 0 + fetch_pages_content!(pages) if load_content + + pages + end + + def list_pages_with_legacy_wiki_service(limit:, sort:, direction:, load_content:) + wiki.list_pages( + limit: limit, + sort: sort, + direction_desc: direction == DIRECTION_DESC, + load_content: load_content + ).map do |page| + WikiPage.new(self, page) + end + end + + # After migrating to normal repository RPCs, it's very expensive to sort the + # pages by created_at. We have to either ListLastCommitsForTree RPC call or + # N+1 LastCommitForPath. Either are efficient for a large repository. + # Therefore, we decide to sort the title only. + def sort_pages!(pages, _sort, direction) + # Sort by path to ensure the files inside a sub-folder are grouped and sorted together + pages.sort_by!(&:path) + pages.reverse! if direction == DIRECTION_DESC + end + + def fetch_pages_content!(pages) + blobs = + repository + .blobs_at(pages.map { |page| [default_branch, page.path] } ) + .to_h { |blob| [blob.path, blob.data] } + + pages.each do |page| + page.raw_content = blobs[page.path] + end + end end Wiki.prepend_mod_with('Wiki') diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 5cdd1fdadcb..ad07e0269f6 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -99,6 +99,13 @@ class WikiPage attributes[:content] ||= page&.text_data end + def raw_content=(content) + return if page.nil? + + page.raw_data = content + attributes[:content] = page.text_data + end + # The hierarchy of the directory this page is contained in. def directory wiki.page_title_and_dir(slug)&.last.to_s @@ -118,7 +125,7 @@ class WikiPage def version return unless persisted? - @version ||= @page.version + @version ||= @page.version || last_version end def path @@ -151,7 +158,7 @@ class WikiPage end def last_version - @last_version ||= versions(limit: 1).first + @last_version ||= wiki.repository.last_commit_for_path(wiki.default_branch, page.path) if page end def last_commit_sha diff --git a/app/services/concerns/work_items/widgetable_service.rb b/app/services/concerns/work_items/widgetable_service.rb index beb614c7b76..24ade9336b2 100644 --- a/app/services/concerns/work_items/widgetable_service.rb +++ b/app/services/concerns/work_items/widgetable_service.rb @@ -2,18 +2,22 @@ module WorkItems module WidgetableService - def execute_widgets(work_item:, callback:, widget_params: {}) + def execute_widgets(work_item:, callback:, widget_params: {}, service_params: {}) work_item.widgets.each do |widget| - widget_service(widget).try(callback, params: widget_params[widget.class.api_symbol]) + widget_service(widget, service_params).try(callback, params: widget_params[widget.class.api_symbol]) end end # rubocop:disable Gitlab/ModuleWithInstanceVariables - def widget_service(widget) + def widget_service(widget, service_params) @widget_services ||= {} return @widget_services[widget] if @widget_services.has_key?(widget) - @widget_services[widget] = widget_service_class(widget)&.new(widget: widget, current_user: current_user) + @widget_services[widget] = widget_service_class(widget)&.new( + widget: widget, + current_user: current_user, + service_params: service_params + ) end # rubocop:enable Gitlab/ModuleWithInstanceVariables diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index febb2f56e86..40c7742a3aa 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -266,6 +266,10 @@ class IssuableBaseService < ::BaseProjectService # To be overridden by subclasses end + def prepare_update_params(issuable) + # To be overridden by subclasses + end + def after_update(issuable) handle_description_updated(issuable) end @@ -277,6 +281,7 @@ class IssuableBaseService < ::BaseProjectService end def update(issuable) + prepare_update_params(issuable) handle_quick_actions(issuable) filter_params(issuable) diff --git a/app/services/work_items/update_service.rb b/app/services/work_items/update_service.rb index 2deb8c82741..e87a19422cb 100644 --- a/app/services/work_items/update_service.rb +++ b/app/services/work_items/update_service.rb @@ -26,6 +26,17 @@ module WorkItems private + def prepare_update_params(work_item) + execute_widgets( + work_item: work_item, + callback: :prepare_update_params, + widget_params: @widget_params, + service_params: params + ) + + super + end + def before_update(work_item, skip_spam_check: false) execute_widgets(work_item: work_item, callback: :before_update_callback, widget_params: @widget_params) diff --git a/app/services/work_items/widgets/base_service.rb b/app/services/work_items/widgets/base_service.rb index 37ed2bf4b05..1ff03a09f9f 100644 --- a/app/services/work_items/widgets/base_service.rb +++ b/app/services/work_items/widgets/base_service.rb @@ -5,12 +5,13 @@ module WorkItems class BaseService < ::BaseService WidgetError = Class.new(StandardError) - attr_reader :widget, :work_item, :current_user + attr_reader :widget, :work_item, :current_user, :service_params - def initialize(widget:, current_user:) + def initialize(widget:, current_user:, service_params: {}) @widget = widget @work_item = widget.work_item @current_user = current_user + @service_params = service_params end private diff --git a/app/services/work_items/widgets/labels_service/update_service.rb b/app/services/work_items/widgets/labels_service/update_service.rb new file mode 100644 index 00000000000..f00ea5c95ca --- /dev/null +++ b/app/services/work_items/widgets/labels_service/update_service.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module WorkItems + module Widgets + module LabelsService + class UpdateService < WorkItems::Widgets::BaseService + def prepare_update_params(params: {}) + return if params.blank? + + service_params.merge!(params.slice(:add_label_ids, :remove_label_ids)) + end + end + end + end +end diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index 6650e07be2a..3532c6638ce 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -13,9 +13,9 @@ = render "layouts/flash" .mt-3 .col-sm-12.gl-text-center - %img.gl-w-10{ :alt => _("GitLab Logo"), :src => image_path('logo.svg') } + = brand_image %h1.mb-3.gl-font-size-h2 - = current_appearance&.title.presence || _('GitLab') + = brand_title - if current_appearance&.description? = brand_text = render_if_exists 'layouts/devise_help_text' diff --git a/app/views/shared/wikis/pages.html.haml b/app/views/shared/wikis/pages.html.haml index 21d63a6db3d..79c5bb62f28 100644 --- a/app/views/shared/wikis/pages.html.haml +++ b/app/views/shared/wikis/pages.html.haml @@ -15,7 +15,8 @@ .dropdown.inline.wiki-sort-dropdown .btn-group{ role: 'group' } - = gl_redirect_listbox_tag wiki_sort_options, params[:sort], data: { right: true } + - unless @wiki.disable_sorting? + = gl_redirect_listbox_tag wiki_sort_options, params[:sort], data: { right: true } = wiki_sort_controls(@wiki, params[:sort], params[:direction]) %ul.wiki-pages-list.content-list diff --git a/config/feature_flags/development/wiki_list_pages_with_normal_repository_rpcs.yml b/config/feature_flags/development/wiki_list_pages_with_normal_repository_rpcs.yml new file mode 100644 index 00000000000..4be550b5046 --- /dev/null +++ b/config/feature_flags/development/wiki_list_pages_with_normal_repository_rpcs.yml @@ -0,0 +1,8 @@ +--- +name: wiki_list_pages_with_normal_repository_rpcs +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96461 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372259 +milestone: '15.4' +type: development +group: group::gitaly +default_enabled: false diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 0e387d1b2dc..337c5c077f8 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -5839,6 +5839,7 @@ Input type: `WorkItemUpdateInput` | <a id="mutationworkitemupdatehierarchywidget"></a>`hierarchyWidget` | [`WorkItemWidgetHierarchyUpdateInput`](#workitemwidgethierarchyupdateinput) | Input for hierarchy widget. | | <a id="mutationworkitemupdateid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. | | <a id="mutationworkitemupdateiterationwidget"></a>`iterationWidget` | [`WorkItemWidgetIterationInput`](#workitemwidgetiterationinput) | Input for iteration widget. | +| <a id="mutationworkitemupdatelabelswidget"></a>`labelsWidget` | [`WorkItemWidgetLabelsUpdateInput`](#workitemwidgetlabelsupdateinput) | Input for labels widget. | | <a id="mutationworkitemupdatestartandduedatewidget"></a>`startAndDueDateWidget` | [`WorkItemWidgetStartAndDueDateUpdateInput`](#workitemwidgetstartandduedateupdateinput) | Input for start and due date widget. | | <a id="mutationworkitemupdatestateevent"></a>`stateEvent` | [`WorkItemStateEvent`](#workitemstateevent) | Close or reopen a work item. | | <a id="mutationworkitemupdatetitle"></a>`title` | [`String`](#string) | Title of the work item. | @@ -23494,6 +23495,7 @@ A time-frame defined as a closed inclusive range of two dates. | <a id="workitemupdatedtaskinputdescriptionwidget"></a>`descriptionWidget` | [`WorkItemWidgetDescriptionInput`](#workitemwidgetdescriptioninput) | Input for description widget. | | <a id="workitemupdatedtaskinputhierarchywidget"></a>`hierarchyWidget` | [`WorkItemWidgetHierarchyUpdateInput`](#workitemwidgethierarchyupdateinput) | Input for hierarchy widget. | | <a id="workitemupdatedtaskinputid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. | +| <a id="workitemupdatedtaskinputlabelswidget"></a>`labelsWidget` | [`WorkItemWidgetLabelsUpdateInput`](#workitemwidgetlabelsupdateinput) | Input for labels widget. | | <a id="workitemupdatedtaskinputstartandduedatewidget"></a>`startAndDueDateWidget` | [`WorkItemWidgetStartAndDueDateUpdateInput`](#workitemwidgetstartandduedateupdateinput) | Input for start and due date widget. | | <a id="workitemupdatedtaskinputstateevent"></a>`stateEvent` | [`WorkItemStateEvent`](#workitemstateevent) | Close or reopen a work item. | | <a id="workitemupdatedtaskinputtitle"></a>`title` | [`String`](#string) | Title of the work item. | @@ -23539,6 +23541,15 @@ A time-frame defined as a closed inclusive range of two dates. | ---- | ---- | ----------- | | <a id="workitemwidgetiterationinputiterationid"></a>`iterationId` | [`IterationID`](#iterationid) | Iteration to assign to the work item. | +### `WorkItemWidgetLabelsUpdateInput` + +#### Arguments + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="workitemwidgetlabelsupdateinputaddlabelids"></a>`addLabelIds` | [`[LabelID!]`](#labelid) | Global IDs of labels to be added to the work item. | +| <a id="workitemwidgetlabelsupdateinputremovelabelids"></a>`removeLabelIds` | [`[LabelID!]`](#labelid) | Global IDs of labels to be removed from the work item. | + ### `WorkItemWidgetStartAndDueDateUpdateInput` #### Arguments diff --git a/lib/gitlab/git/wiki_page.rb b/lib/gitlab/git/wiki_page.rb index 57b7e7d53dd..154c79f56b8 100644 --- a/lib/gitlab/git/wiki_page.rb +++ b/lib/gitlab/git/wiki_page.rb @@ -41,6 +41,11 @@ module Gitlab @text_data = @raw_data && Gitlab::EncodingHelper.encode!(@raw_data.dup) end + + def raw_data=(data) + @raw_data = data + @text_data = @raw_data && Gitlab::EncodingHelper.encode!(@raw_data.dup) + end end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 9011df84e10..887c880baab 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -17964,9 +17964,6 @@ msgstr "" msgid "GitLab KAS" msgstr "" -msgid "GitLab Logo" -msgstr "" - msgid "GitLab Pages" msgstr "" diff --git a/spec/features/projects/wikis_spec.rb b/spec/features/projects/wikis_spec.rb index 8ac17413df3..6e130f96999 100644 --- a/spec/features/projects/wikis_spec.rb +++ b/spec/features/projects/wikis_spec.rb @@ -12,14 +12,37 @@ RSpec.describe 'Project wikis', :js do let(:wiki) { create(:project_wiki, user: user, project: project) } let(:project) { create(:project, namespace: user.namespace, creator: user) } - it_behaves_like 'User creates wiki page' - it_behaves_like 'User deletes wiki page' - it_behaves_like 'User previews wiki changes' - it_behaves_like 'User updates wiki page' - it_behaves_like 'User uses wiki shortcuts' - it_behaves_like 'User views AsciiDoc page with includes' - it_behaves_like 'User views a wiki page' - it_behaves_like 'User views wiki pages' - it_behaves_like 'User views wiki sidebar' - it_behaves_like 'User views Git access wiki page' + context 'with legacy wiki rpcs' do + before do + stub_feature_flags(wiki_list_pages_with_normal_repository_rpcs: false) + end + + it_behaves_like 'User creates wiki page' + it_behaves_like 'User deletes wiki page' + it_behaves_like 'User previews wiki changes' + it_behaves_like 'User updates wiki page' + it_behaves_like 'User uses wiki shortcuts' + it_behaves_like 'User views AsciiDoc page with includes' + it_behaves_like 'User views a wiki page' + it_behaves_like 'User views wiki pages' + it_behaves_like 'User views wiki sidebar' + it_behaves_like 'User views Git access wiki page' + end + + context 'with normal repository rpcs' do + before do + stub_feature_flags(wiki_list_pages_with_normal_repository_rpcs: true) + end + + it_behaves_like 'User creates wiki page' + it_behaves_like 'User deletes wiki page' + it_behaves_like 'User previews wiki changes' + it_behaves_like 'User updates wiki page' + it_behaves_like 'User uses wiki shortcuts' + it_behaves_like 'User views AsciiDoc page with includes' + it_behaves_like 'User views a wiki page' + it_behaves_like 'User views wiki pages', false + it_behaves_like 'User views wiki sidebar' + it_behaves_like 'User views Git access wiki page' + end end diff --git a/spec/graphql/types/work_items/widgets/labels_update_input_type_spec.rb b/spec/graphql/types/work_items/widgets/labels_update_input_type_spec.rb new file mode 100644 index 00000000000..3e5f40bde02 --- /dev/null +++ b/spec/graphql/types/work_items/widgets/labels_update_input_type_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Types::WorkItems::Widgets::LabelsUpdateInputType do + it { expect(described_class.graphql_name).to eq('WorkItemWidgetLabelsUpdateInput') } + + it { expect(described_class.arguments.keys).to contain_exactly('addLabelIds', 'removeLabelIds') } +end diff --git a/spec/helpers/appearances_helper_spec.rb b/spec/helpers/appearances_helper_spec.rb index edd704ce739..2206c1ce2ae 100644 --- a/spec/helpers/appearances_helper_spec.rb +++ b/spec/helpers/appearances_helper_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe AppearancesHelper do + let_it_be(:gitlab_logo) { ActionController::Base.helpers.image_path('logo.svg') } + before do user = create(:user) allow(helper).to receive(:current_user).and_return(user) @@ -59,23 +61,59 @@ RSpec.describe AppearancesHelper do end describe '#brand_image' do - let!(:appearance) { create(:appearance, :with_logo) } - context 'when there is a logo' do + let!(:appearance) { create(:appearance, :with_logo) } + it 'returns a path' do - expect(helper.brand_image).to match(%r(img data-src="/uploads/-/system/appearance/.*png)) + expect(helper.brand_image).to match(%r(img .* data-src="/uploads/-/system/appearance/.*png)) + end + + context 'when there is no associated upload' do + before do + # Legacy attachments were not tracked in the uploads table + appearance.logo.upload.destroy! + appearance.reload + end + + it 'falls back to using the original path' do + expect(helper.brand_image).to match(%r(img .* data-src="/uploads/-/system/appearance/.*png)) + end end end - context 'when there is a logo but no associated upload' do - before do - # Legacy attachments were not tracked in the uploads table - appearance.logo.upload.destroy! - appearance.reload + context 'when there is no logo' do + it 'returns path of GitLab logo' do + expect(helper.brand_image).to match(%r(img .* data-src="#{gitlab_logo})) + end + end + + context 'when there is a title' do + let!(:appearance) { create(:appearance, title: 'My title') } + + it 'returns the title' do + expect(helper.brand_image).to match(%r(img alt="My title")) end + end + + context 'when there is no title' do + it 'returns the default title' do + expect(helper.brand_image).to match(%r(img alt="GitLab)) + end + end + end + + describe '#brand_image_path' do + context 'with a custom logo' do + let!(:appearance) { create(:appearance, :with_logo) } + + it 'returns path of custom logo' do + expect(helper.brand_image_path).to match(%r(/uploads/-/system/appearance/.*/dk.png)) + end + end - it 'falls back to using the original path' do - expect(helper.brand_image).to match(%r(img data-src="/uploads/-/system/appearance/.*png)) + context 'with no custom logo' do + it 'returns path of GitLab logo' do + expect(helper.brand_image_path).to eq(gitlab_logo) end end end diff --git a/spec/helpers/wiki_helper_spec.rb b/spec/helpers/wiki_helper_spec.rb index 75128d758f9..e798281ccff 100644 --- a/spec/helpers/wiki_helper_spec.rb +++ b/spec/helpers/wiki_helper_spec.rb @@ -79,37 +79,72 @@ RSpec.describe WikiHelper do let(:classes) { "gl-button btn btn-default btn-icon has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort" } def expected_link(sort, direction, icon_class) - path = "/#{wiki.project.full_path}/-/wikis/pages?direction=#{direction}&sort=#{sort}" + path = + if sort + "/#{wiki.project.full_path}/-/wikis/pages?direction=#{direction}&sort=#{sort}" + else + "/#{wiki.project.full_path}/-/wikis/pages?direction=#{direction}" + end helper.link_to(path, type: 'button', class: classes, title: 'Sort direction') do helper.sprite_icon("sort-#{icon_class}") end end - context 'initial call' do - let(:sort) { nil } - let(:direction) { nil } + context 'wiki sorting enabled' do + before do + allow(wiki).to receive(:disable_sorting?).and_return(false) + end + + context 'initial call' do + let(:sort) { nil } + let(:direction) { nil } - it 'renders with default values' do - expect(wiki_link).to eq(expected_link('title', 'desc', 'lowest')) + it 'renders with default values' do + expect(wiki_link).to eq(expected_link('title', 'desc', 'lowest')) + end + end + + context 'sort by title' do + let(:sort) { 'title' } + let(:direction) { 'asc' } + + it 'renders a link with opposite direction' do + expect(wiki_link).to eq(expected_link('title', 'desc', 'lowest')) + end end - end - context 'sort by title' do - let(:sort) { 'title' } - let(:direction) { 'asc' } + context 'sort by created_at' do + let(:sort) { 'created_at' } + let(:direction) { 'desc' } - it 'renders a link with opposite direction' do - expect(wiki_link).to eq(expected_link('title', 'desc', 'lowest')) + it 'renders a link with opposite direction' do + expect(wiki_link).to eq(expected_link('created_at', 'asc', 'highest')) + end end end - context 'sort by created_at' do - let(:sort) { 'created_at' } - let(:direction) { 'desc' } + context 'wiki sorting disabled' do + before do + allow(wiki).to receive(:disable_sorting?).and_return(true) + end + + context 'sort by created_at' do + let(:sort) { 'created_at' } + let(:direction) { 'asc' } + + it 'ignores created_at and renders a link with opposite direction' do + expect(wiki_link).to eq(expected_link(nil, 'desc', 'lowest')) + end + end + + context 'initial call' do + let(:sort) { nil } + let(:direction) { nil } - it 'renders a link with opposite direction' do - expect(wiki_link).to eq(expected_link('created_at', 'asc', 'highest')) + it 'renders with default values' do + expect(wiki_link).to eq(expected_link(nil, 'desc', 'lowest')) + end end end end diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index a9c0262fdb2..a762fdbde6b 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -118,7 +118,7 @@ RSpec.describe Gitlab::ProjectSearchResults do shared_examples 'blob search repository ref' do |entity_type, blob_type| let(:query) { 'files' } let(:file_finder) { double } - let(:project_branch) { 'project_branch' } + let(:project_branch) { blob_type == 'wiki_blobs' ? entity.default_branch : 'project_branch' } subject(:objects) { results.objects(blob_type) } @@ -209,8 +209,11 @@ RSpec.describe Gitlab::ProjectSearchResults do describe 'wiki search' do let(:project) { create(:project, :public, :wiki_repo) } + let(:project_branch) { 'project_branch' } before do + allow(project.wiki).to receive(:root_ref).and_return(project_branch) + project.wiki.create_page('Files/Title', 'Content') project.wiki.create_page('CHANGELOG', 'Files example') end diff --git a/spec/lib/gitlab/serializer/ci/variables_spec.rb b/spec/lib/gitlab/serializer/ci/variables_spec.rb index 9b0475259fe..02f1d543e4b 100644 --- a/spec/lib/gitlab/serializer/ci/variables_spec.rb +++ b/spec/lib/gitlab/serializer/ci/variables_spec.rb @@ -13,9 +13,10 @@ RSpec.describe Gitlab::Serializer::Ci::Variables do end it 'converts keys into strings and symbolizes hash' do - is_expected.to eq([ - { key: 'key', value: 'value', public: true }, - { key: 'wee', value: 1, public: false } - ]) + is_expected.to eq( + [ + { key: 'key', value: 'value', public: true }, + { key: 'wee', value: 1, public: false } + ]) end end diff --git a/spec/lib/gitlab/sidekiq_config_spec.rb b/spec/lib/gitlab/sidekiq_config_spec.rb index c62302d8bba..c5b00afe672 100644 --- a/spec/lib/gitlab/sidekiq_config_spec.rb +++ b/spec/lib/gitlab/sidekiq_config_spec.rb @@ -193,9 +193,7 @@ RSpec.describe Gitlab::SidekiqConfig do it 'returns worker queue mappings that have queues in the current Sidekiq options' do queues = described_class.routing_queues - expect(queues).to match_array(%w[ - default mailers high_urgency gitaly - ]) + expect(queues).to match_array(%w[default mailers high_urgency gitaly]) expect(queues).not_to include('not_exist') end end diff --git a/spec/lib/gitlab/ssh_public_key_spec.rb b/spec/lib/gitlab/ssh_public_key_spec.rb index 114a18cf99a..a2524314458 100644 --- a/spec/lib/gitlab/ssh_public_key_spec.rb +++ b/spec/lib/gitlab/ssh_public_key_spec.rb @@ -88,12 +88,12 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true, fips_mode: false do it 'returns all supported algorithms' do expect(described_class.supported_algorithms).to eq( %w( - ssh-rsa - ssh-dss - ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 - ssh-ed25519 - sk-ecdsa-sha2-nistp256@openssh.com - sk-ssh-ed25519@openssh.com + ssh-rsa + ssh-dss + ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 + ssh-ed25519 + sk-ecdsa-sha2-nistp256@openssh.com + sk-ssh-ed25519@openssh.com ) ) end @@ -102,12 +102,12 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true, fips_mode: false do it 'returns all supported algorithms' do expect(described_class.supported_algorithms).to eq( %w( - ssh-rsa - ssh-dss - ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 - ssh-ed25519 - sk-ecdsa-sha2-nistp256@openssh.com - sk-ssh-ed25519@openssh.com + ssh-rsa + ssh-dss + ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 + ssh-ed25519 + sk-ecdsa-sha2-nistp256@openssh.com + sk-ssh-ed25519@openssh.com ) ) end diff --git a/spec/lib/gitlab/usage_data/topology_spec.rb b/spec/lib/gitlab/usage_data/topology_spec.rb index dfdf8eaabe8..3fb87e77457 100644 --- a/spec/lib/gitlab/usage_data/topology_spec.rb +++ b/spec/lib/gitlab/usage_data/topology_spec.rb @@ -523,210 +523,210 @@ RSpec.describe Gitlab::UsageData::Topology do receive(:query) .with(/gitlab_usage_ping:ops:rate/) .and_return(result || [ - { - 'metric' => { 'component' => 'http_requests', 'service' => 'workhorse' }, - 'value' => [1000, '0.01'] - } - ]) + { + 'metric' => { 'component' => 'http_requests', 'service' => 'workhorse' }, + 'value' => [1000, '0.01'] + } + ]) end def receive_query_apdex_ratio_query(result: nil) receive(:query) .with(/gitlab_usage_ping:sql_duration_apdex:ratio_rate5m/) .and_return(result || [ - { - 'metric' => {}, - 'value' => [1000, '0.996'] - } - ]) + { + 'metric' => {}, + 'value' => [1000, '0.996'] + } + ]) end def receive_node_memory_query(result: nil) receive(:query) .with(/node_memory_total_bytes/, an_instance_of(Hash)) .and_return(result || [ - { - 'metric' => { 'instance' => 'instance1:8080' }, - 'value' => [1000, '512'] - }, - { - 'metric' => { 'instance' => 'instance2:8090' }, - 'value' => [1000, '1024'] - } - ]) + { + 'metric' => { 'instance' => 'instance1:8080' }, + 'value' => [1000, '512'] + }, + { + 'metric' => { 'instance' => 'instance2:8090' }, + 'value' => [1000, '1024'] + } + ]) end def receive_node_memory_utilization_query(result: nil) receive(:query) .with(/node_memory_utilization/, an_instance_of(Hash)) .and_return(result || [ - { - 'metric' => { 'instance' => 'instance1:8080' }, - 'value' => [1000, '0.45'] - }, - { - 'metric' => { 'instance' => 'instance2:8090' }, - 'value' => [1000, '0.25'] - } - ]) + { + 'metric' => { 'instance' => 'instance1:8080' }, + 'value' => [1000, '0.45'] + }, + { + 'metric' => { 'instance' => 'instance2:8090' }, + 'value' => [1000, '0.25'] + } + ]) end def receive_node_cpu_count_query(result: nil) receive(:query) .with(/node_cpus/, an_instance_of(Hash)) .and_return(result || [ - { - 'metric' => { 'instance' => 'instance2:8090' }, - 'value' => [1000, '16'] - }, - { - 'metric' => { 'instance' => 'instance1:8080' }, - 'value' => [1000, '8'] - } - ]) + { + 'metric' => { 'instance' => 'instance2:8090' }, + 'value' => [1000, '16'] + }, + { + 'metric' => { 'instance' => 'instance1:8080' }, + 'value' => [1000, '8'] + } + ]) end def receive_node_cpu_utilization_query(result: nil) receive(:query) .with(/node_cpu_utilization/, an_instance_of(Hash)) .and_return(result || [ - { - 'metric' => { 'instance' => 'instance2:8090' }, - 'value' => [1000, '0.2'] - }, - { - 'metric' => { 'instance' => 'instance1:8080' }, - 'value' => [1000, '0.1'] - } - ]) + { + 'metric' => { 'instance' => 'instance2:8090' }, + 'value' => [1000, '0.2'] + }, + { + 'metric' => { 'instance' => 'instance1:8080' }, + 'value' => [1000, '0.1'] + } + ]) end def receive_node_uname_info_query(result: nil) receive(:query) .with('node_uname_info') .and_return(result || [ - { - "metric" => { - "__name__" => "node_uname_info", - "domainname" => "(none)", - "instance" => "instance1:9100", - "job" => "node_exporter", - "machine" => "x86_64", - "nodename" => "instance1", - "release" => "4.19.76-linuxkit", - "sysname" => "Linux" - }, - "value" => [1592463033.359, "1"] - }, - { - "metric" => { - "__name__" => "node_uname_info", - "domainname" => "(none)", - "instance" => "instance2:9100", - "job" => "node_exporter", - "machine" => "x86_64", - "nodename" => "instance2", - "release" => "4.15.0-101-generic", - "sysname" => "Linux" - }, - "value" => [1592463033.359, "1"] - } - ]) + { + "metric" => { + "__name__" => "node_uname_info", + "domainname" => "(none)", + "instance" => "instance1:9100", + "job" => "node_exporter", + "machine" => "x86_64", + "nodename" => "instance1", + "release" => "4.19.76-linuxkit", + "sysname" => "Linux" + }, + "value" => [1592463033.359, "1"] + }, + { + "metric" => { + "__name__" => "node_uname_info", + "domainname" => "(none)", + "instance" => "instance2:9100", + "job" => "node_exporter", + "machine" => "x86_64", + "nodename" => "instance2", + "release" => "4.15.0-101-generic", + "sysname" => "Linux" + }, + "value" => [1592463033.359, "1"] + } + ]) end def receive_node_service_memory_rss_query(result: nil) receive(:query) .with(/process_resident_memory_bytes/, an_instance_of(Hash)) .and_return(result || [ - { - 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails' }, - 'value' => [1000, '300'] - }, - { - 'metric' => { 'instance' => 'instance1:8090', 'job' => 'gitlab-sidekiq' }, - 'value' => [1000, '303'] - }, - # instance 2: runs a dedicated Sidekiq + Redis (which uses a different metric name) - { - 'metric' => { 'instance' => 'instance2:8090', 'job' => 'gitlab-sidekiq' }, - 'value' => [1000, '400'] - }, - { - 'metric' => { 'instance' => 'instance2:9121', 'job' => 'redis' }, - 'value' => [1000, '402'] - } - ]) + { + 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails' }, + 'value' => [1000, '300'] + }, + { + 'metric' => { 'instance' => 'instance1:8090', 'job' => 'gitlab-sidekiq' }, + 'value' => [1000, '303'] + }, + # instance 2: runs a dedicated Sidekiq + Redis (which uses a different metric name) + { + 'metric' => { 'instance' => 'instance2:8090', 'job' => 'gitlab-sidekiq' }, + 'value' => [1000, '400'] + }, + { + 'metric' => { 'instance' => 'instance2:9121', 'job' => 'redis' }, + 'value' => [1000, '402'] + } + ]) end def receive_node_service_memory_uss_query(result: nil) receive(:query) .with(/process_unique_memory_bytes/, an_instance_of(Hash)) .and_return(result || [ - { - 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails' }, - 'value' => [1000, '301'] - } - ]) + { + 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails' }, + 'value' => [1000, '301'] + } + ]) end def receive_node_service_memory_pss_query(result: nil) receive(:query) .with(/process_proportional_memory_bytes/, an_instance_of(Hash)) .and_return(result || [ - { - 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails' }, - 'value' => [1000, '302'] - }, - { - 'metric' => { 'instance' => 'instance2:8090', 'job' => 'gitlab-sidekiq' }, - 'value' => [1000, '401'] - } - ]) + { + 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails' }, + 'value' => [1000, '302'] + }, + { + 'metric' => { 'instance' => 'instance2:8090', 'job' => 'gitlab-sidekiq' }, + 'value' => [1000, '401'] + } + ]) end def receive_node_service_process_count_query(result: nil) receive(:query) .with(/service_process:count/, an_instance_of(Hash)) .and_return(result || [ - # instance 1 - { - 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails' }, - 'value' => [1000, '10'] - }, - { - 'metric' => { 'instance' => 'instance1:8090', 'job' => 'gitlab-sidekiq' }, - 'value' => [1000, '5'] - }, - # instance 2 - { - 'metric' => { 'instance' => 'instance2:8090', 'job' => 'gitlab-sidekiq' }, - 'value' => [1000, '15'] - }, - { - 'metric' => { 'instance' => 'instance2:9121', 'job' => 'redis' }, - 'value' => [1000, '1'] - }, - { - 'metric' => { 'instance' => 'instance2:8080', 'job' => 'registry' }, - 'value' => [1000, '1'] - } - ]) + # instance 1 + { + 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails' }, + 'value' => [1000, '10'] + }, + { + 'metric' => { 'instance' => 'instance1:8090', 'job' => 'gitlab-sidekiq' }, + 'value' => [1000, '5'] + }, + # instance 2 + { + 'metric' => { 'instance' => 'instance2:8090', 'job' => 'gitlab-sidekiq' }, + 'value' => [1000, '15'] + }, + { + 'metric' => { 'instance' => 'instance2:9121', 'job' => 'redis' }, + 'value' => [1000, '1'] + }, + { + 'metric' => { 'instance' => 'instance2:8080', 'job' => 'registry' }, + 'value' => [1000, '1'] + } + ]) end def receive_node_service_app_server_workers_query(result: nil) receive(:query) .with(/app_server_workers/, an_instance_of(Hash)) .and_return(result || [ - # instance 1 - { - 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails', 'server' => 'puma' }, - 'value' => [1000, '2'] - }, - # instance 2 - { - 'metric' => { 'instance' => 'instance2:8080', 'job' => 'gitlab-rails', 'server' => 'puma' }, - 'value' => [1000, '1'] - } - ]) + # instance 1 + { + 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails', 'server' => 'puma' }, + 'value' => [1000, '2'] + }, + # instance 2 + { + 'metric' => { 'instance' => 'instance2:8080', 'job' => 'gitlab-rails', 'server' => 'puma' }, + 'value' => [1000, '1'] + } + ]) end end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 745aa20a6a2..dc34b0b10e0 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -1050,12 +1050,13 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do before do allow(described_class).to receive(:operating_system).and_return('ubuntu-20.04') - expect(prometheus_client).to receive(:query).with(/gitlab_usage_ping:gitaly_apdex:ratio_avg_over_time_5m/).and_return([ - { - 'metric' => {}, - 'value' => [1616016381.473, '0.95'] - } - ]) + expect(prometheus_client).to receive(:query) + .with(/gitlab_usage_ping:gitaly_apdex:ratio_avg_over_time_5m/) + .and_return( + [ + { 'metric' => {}, + 'value' => [1616016381.473, '0.95'] } + ]) expect(described_class).to receive(:with_prometheus_client).and_yield(prometheus_client) end diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb index 61323f0646b..d1fdaf7a9db 100644 --- a/spec/lib/gitlab/utils_spec.rb +++ b/spec/lib/gitlab/utils_spec.rb @@ -582,11 +582,12 @@ RSpec.describe Gitlab::Utils do end it 'sorts items like the regular sort_by' do - expect(sorted_list).to eq([ - { name: 'obj 2', priority: 1 }, - { name: 'obj 1', priority: 2 }, - { name: 'obj 3', priority: 3 } - ]) + expect(sorted_list).to eq( + [ + { name: 'obj 2', priority: 1 }, + { name: 'obj 1', priority: 2 }, + { name: 'obj 3', priority: 3 } + ]) end end end diff --git a/spec/lib/gitlab/webpack/manifest_spec.rb b/spec/lib/gitlab/webpack/manifest_spec.rb index 08b4774dd67..24a36258379 100644 --- a/spec/lib/gitlab/webpack/manifest_spec.rb +++ b/spec/lib/gitlab/webpack/manifest_spec.rb @@ -66,10 +66,11 @@ RSpec.describe Gitlab::Webpack::Manifest do describe "webpack errors" do context "when webpack has 'Module build failed' errors in its manifest" do it "errors" do - error_manifest = Gitlab::Json.parse(manifest).merge("errors" => [ - "somethingModule build failed something", - "I am an error" - ]).to_json + error_manifest = Gitlab::Json.parse(manifest).merge("errors" => + [ + "somethingModule build failed something", + "I am an error" + ]).to_json stub_request(:get, "http://hostname:2000/public_path/my_manifest.json").to_return(body: error_manifest, status: 200) expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.to raise_error(Gitlab::Webpack::Manifest::WebpackError) diff --git a/spec/lib/google_api/cloud_platform/client_spec.rb b/spec/lib/google_api/cloud_platform/client_spec.rb index 0f117f495d1..0c207161927 100644 --- a/spec/lib/google_api/cloud_platform/client_spec.rb +++ b/spec/lib/google_api/cloud_platform/client_spec.rb @@ -17,17 +17,19 @@ RSpec.describe GoogleApi::CloudPlatform::Client do let(:tier) { 'mock-tier' } let(:database_list) do - Google::Apis::SqladminV1beta4::ListDatabasesResponse.new(items: [ - Google::Apis::SqladminV1beta4::Database.new(name: 'db_01', instance: database_instance), - Google::Apis::SqladminV1beta4::Database.new(name: 'db_02', instance: database_instance) - ]) + Google::Apis::SqladminV1beta4::ListDatabasesResponse.new( + items: [ + Google::Apis::SqladminV1beta4::Database.new(name: 'db_01', instance: database_instance), + Google::Apis::SqladminV1beta4::Database.new(name: 'db_02', instance: database_instance) + ]) end let(:user_list) do - Google::Apis::SqladminV1beta4::ListUsersResponse.new(items: [ - Google::Apis::SqladminV1beta4::User.new(name: 'user_01', instance: database_instance), - Google::Apis::SqladminV1beta4::User.new(name: 'user_02', instance: database_instance) - ]) + Google::Apis::SqladminV1beta4::ListUsersResponse.new( + items: [ + Google::Apis::SqladminV1beta4::User.new(name: 'user_01', instance: database_instance), + Google::Apis::SqladminV1beta4::User.new(name: 'user_02', instance: database_instance) + ]) end describe '.session_key_for_redirect_uri' do diff --git a/spec/lib/peek/views/bullet_detailed_spec.rb b/spec/lib/peek/views/bullet_detailed_spec.rb index ec2f798a320..6eaf8c50cc0 100644 --- a/spec/lib/peek/views/bullet_detailed_spec.rb +++ b/spec/lib/peek/views/bullet_detailed_spec.rb @@ -44,10 +44,11 @@ RSpec.describe Peek::Views::BulletDetailed do expect(subject.key).to eq('bullet') expect(subject.results[:calls]).to eq(2) expect(subject.results[:warnings]).to eq([Peek::Views::BulletDetailed::WARNING_MESSAGE]) - expect(subject.results[:details]).to eq([ - { notification: 'Title 1: Body 1', backtrace: "first\nsecond\n" }, - { notification: 'Title 2: Body 2', backtrace: "first\nsecond\n" } - ]) + expect(subject.results[:details]).to eq( + [ + { notification: 'Title 1: Body 1', backtrace: "first\nsecond\n" }, + { notification: 'Title 2: Body 2', backtrace: "first\nsecond\n" } + ]) end end end diff --git a/spec/lib/system_check/incoming_email_check_spec.rb b/spec/lib/system_check/incoming_email_check_spec.rb index 5d93b810045..cf3fd3b7967 100644 --- a/spec/lib/system_check/incoming_email_check_spec.rb +++ b/spec/lib/system_check/incoming_email_check_spec.rb @@ -26,11 +26,12 @@ RSpec.describe SystemCheck::IncomingEmailCheck do end it 'runs IMAP and mailroom checks' do - expect(SystemCheck).to receive(:run).with('Reply by email', [ - SystemCheck::IncomingEmail::ImapAuthenticationCheck, - SystemCheck::IncomingEmail::MailRoomEnabledCheck, - SystemCheck::IncomingEmail::MailRoomRunningCheck - ]) + expect(SystemCheck).to receive(:run).with('Reply by email', + [ + SystemCheck::IncomingEmail::ImapAuthenticationCheck, + SystemCheck::IncomingEmail::MailRoomEnabledCheck, + SystemCheck::IncomingEmail::MailRoomRunningCheck + ]) subject.multi_check end @@ -42,10 +43,11 @@ RSpec.describe SystemCheck::IncomingEmailCheck do end it 'runs mailroom checks' do - expect(SystemCheck).to receive(:run).with('Reply by email', [ - SystemCheck::IncomingEmail::MailRoomEnabledCheck, - SystemCheck::IncomingEmail::MailRoomRunningCheck - ]) + expect(SystemCheck).to receive(:run).with('Reply by email', + [ + SystemCheck::IncomingEmail::MailRoomEnabledCheck, + SystemCheck::IncomingEmail::MailRoomRunningCheck + ]) subject.multi_check end diff --git a/spec/lib/unnested_in_filters/rewriter_spec.rb b/spec/lib/unnested_in_filters/rewriter_spec.rb index a808aec7728..21bab42c95c 100644 --- a/spec/lib/unnested_in_filters/rewriter_spec.rb +++ b/spec/lib/unnested_in_filters/rewriter_spec.rb @@ -41,14 +41,15 @@ RSpec.describe UnnestedInFilters::Rewriter do context 'when the order is a Keyset order' do let(:order) do - Gitlab::Pagination::Keyset::Order.build([ - Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( - attribute_name: 'user_type', - order_expression: User.arel_table['user_type'].desc, - nullable: :not_nullable, - distinct: false - ) - ]) + Gitlab::Pagination::Keyset::Order.build( + [ + Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( + attribute_name: 'user_type', + order_expression: User.arel_table['user_type'].desc, + nullable: :not_nullable, + distinct: false + ) + ]) end it { is_expected.to be_truthy } @@ -152,14 +153,15 @@ RSpec.describe UnnestedInFilters::Rewriter do context 'when the order is a Keyset order' do let(:order) do - Gitlab::Pagination::Keyset::Order.build([ - Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( - attribute_name: 'user_type', - order_expression: User.arel_table['user_type'].desc, - nullable: :not_nullable, - distinct: false - ) - ]) + Gitlab::Pagination::Keyset::Order.build( + [ + Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( + attribute_name: 'user_type', + order_expression: User.arel_table['user_type'].desc, + nullable: :not_nullable, + distinct: false + ) + ]) end it 'changes the query' do diff --git a/spec/migrations/add_premium_and_ultimate_plan_limits_spec.rb b/spec/migrations/add_premium_and_ultimate_plan_limits_spec.rb index fb62fc3ca02..0ae4559ca9f 100644 --- a/spec/migrations/add_premium_and_ultimate_plan_limits_spec.rb +++ b/spec/migrations/add_premium_and_ultimate_plan_limits_spec.rb @@ -72,12 +72,14 @@ RSpec.describe AddPremiumAndUltimatePlanLimits, :migration do it 'creates plan limits from the source plan' do migrate! - expect(AddPremiumAndUltimatePlanLimits::PlanLimits.pluck(:plan_id, :storage_size_limit)).to match_array([ - [silver.id, silver_limits.storage_size_limit], - [gold.id, gold_limits.storage_size_limit], - [premium.id, silver_limits.storage_size_limit], - [ultimate.id, gold_limits.storage_size_limit] - ]) + expect(AddPremiumAndUltimatePlanLimits::PlanLimits.pluck(:plan_id, :storage_size_limit)) + .to match_array( + [ + [silver.id, silver_limits.storage_size_limit], + [gold.id, gold_limits.storage_size_limit], + [premium.id, silver_limits.storage_size_limit], + [ultimate.id, gold_limits.storage_size_limit] + ]) end end end diff --git a/spec/migrations/backfill_escalation_policies_for_oncall_schedules_spec.rb b/spec/migrations/backfill_escalation_policies_for_oncall_schedules_spec.rb index da32e92ebb0..87855285203 100644 --- a/spec/migrations/backfill_escalation_policies_for_oncall_schedules_spec.rb +++ b/spec/migrations/backfill_escalation_policies_for_oncall_schedules_spec.rb @@ -57,36 +57,39 @@ RSpec.describe BackfillEscalationPoliciesForOncallSchedules do expect(new_polices).to all have_attributes(name: 'On-call Escalation Policy') expect(new_policy_b1.description).to eq('Immediately notify Schedule B1') expect(new_policy_c1.description).to eq('Immediately notify Schedule C1') - expect(policies.pluck(:project_id)).to eq([ - project_d.id, - project_e.id, - project_f.id, - project_f.id, - project_b.id, - project_c.id - ]) + expect(policies.pluck(:project_id)).to eq( + [ + project_d.id, + project_e.id, + project_f.id, + project_f.id, + project_b.id, + project_c.id + ]) expect(new_rules).to all have_attributes(status: 1, elapsed_time_seconds: 0) - expect(rules.pluck(:policy_id)).to eq([ - rule_d1.policy_id, - rule_e1.policy_id, - rule_f1.policy_id, - rule_f2.policy_id, - rule_f3.policy_id, - new_policy_b1.id, - new_policy_c1.id, - new_policy_c1.id - ]) - expect(rules.pluck(:oncall_schedule_id)).to eq([ - rule_d1.oncall_schedule_id, - rule_e1.oncall_schedule_id, - rule_f1.oncall_schedule_id, - rule_f2.oncall_schedule_id, - rule_f3.oncall_schedule_id, - schedule_b1.id, - schedule_c1.id, - schedule_c2.id - ]) + expect(rules.pluck(:policy_id)).to eq( + [ + rule_d1.policy_id, + rule_e1.policy_id, + rule_f1.policy_id, + rule_f2.policy_id, + rule_f3.policy_id, + new_policy_b1.id, + new_policy_c1.id, + new_policy_c1.id + ]) + expect(rules.pluck(:oncall_schedule_id)).to eq( + [ + rule_d1.oncall_schedule_id, + rule_e1.oncall_schedule_id, + rule_f1.oncall_schedule_id, + rule_f2.oncall_schedule_id, + rule_f3.oncall_schedule_id, + schedule_b1.id, + schedule_c1.id, + schedule_c2.id + ]) end end diff --git a/spec/migrations/slice_merge_request_diff_commit_migrations_spec.rb b/spec/migrations/slice_merge_request_diff_commit_migrations_spec.rb index e03dd73ec8b..b03a5c41a11 100644 --- a/spec/migrations/slice_merge_request_diff_commit_migrations_spec.rb +++ b/spec/migrations/slice_merge_request_diff_commit_migrations_spec.rb @@ -49,12 +49,13 @@ RSpec.describe SliceMergeRequestDiffCommitMigrations, :migration do .pending .to_a - expect(new_jobs.map(&:arguments)).to eq([ - [1, 5_001], - [5_001, 10_001], - [10_001, 15_001], - [15_001, 20_001] - ]) + expect(new_jobs.map(&:arguments)).to eq( + [ + [1, 5_001], + [5_001, 10_001], + [10_001, 15_001], + [15_001, 20_001] + ]) end it 'schedules a background migration for the first job' do diff --git a/spec/models/analytics/cycle_analytics/project_stage_spec.rb b/spec/models/analytics/cycle_analytics/project_stage_spec.rb index a67f9fec443..697b7aee022 100644 --- a/spec/models/analytics/cycle_analytics/project_stage_spec.rb +++ b/spec/models/analytics/cycle_analytics/project_stage_spec.rb @@ -48,10 +48,11 @@ RSpec.describe Analytics::CycleAnalytics::ProjectStage do subject(:distinct_start_and_end_event_identifiers) { described_class.distinct_stages_within_hierarchy(top_level_group).to_a.pluck(:start_event_identifier, :end_event_identifier) } it 'returns distinct stages by start and end events (using stage_event_hash_id)' do - expect(distinct_start_and_end_event_identifiers).to match_array([ - %w[issue_created issue_deployed_to_production], - %w[merge_request_created merge_request_merged] - ]) + expect(distinct_start_and_end_event_identifiers).to match_array( + [ + %w[issue_created issue_deployed_to_production], + %w[merge_request_created merge_request_merged] + ]) end end end diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index db64e8439a5..687ffbe87bf 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -257,11 +257,12 @@ RSpec.describe ApplicationSetting do subject.grafana_url = ' ' + http expect(subject.save).to be false - expect(subject.errors[:grafana_url]).to eq([ - 'must be a valid relative or absolute URL. ' \ - 'Please check your Grafana URL setting in ' \ - 'Admin Area > Settings > Metrics and profiling > Metrics - Grafana' - ]) + expect(subject.errors[:grafana_url]).to eq( + [ + 'must be a valid relative or absolute URL. ' \ + 'Please check your Grafana URL setting in ' \ + 'Admin Area > Settings > Metrics and profiling > Metrics - Grafana' + ]) end end @@ -270,11 +271,12 @@ RSpec.describe ApplicationSetting do subject.grafana_url = javascript expect(subject.save).to be false - expect(subject.errors[:grafana_url]).to eq([ - 'is blocked: Only allowed schemes are http, https. Please check your ' \ - 'Grafana URL setting in ' \ - 'Admin Area > Settings > Metrics and profiling > Metrics - Grafana' - ]) + expect(subject.errors[:grafana_url]).to eq( + [ + 'is blocked: Only allowed schemes are http, https. Please check your ' \ + 'Grafana URL setting in ' \ + 'Admin Area > Settings > Metrics and profiling > Metrics - Grafana' + ]) end end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 279556ac75d..ec0fe456d99 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -5275,10 +5275,11 @@ RSpec.describe Ci::Build do it { expect(matchers.size).to eq(2) } it 'groups build ids' do - expect(matchers.map(&:build_ids)).to match_array([ - [build_without_tags.id], - match_array([build_with_tags.id, other_build_with_tags.id]) - ]) + expect(matchers.map(&:build_ids)).to match_array( + [ + [build_without_tags.id], + match_array([build_with_tags.id, other_build_with_tags.id]) + ]) end it { expect(matchers.map(&:tag_list)).to match_array([[], %w[tag1 tag2]]) } @@ -5475,10 +5476,11 @@ RSpec.describe Ci::Build do create(:ci_job_variable, job: build, key: 'TEST_KEY', value: 'old value') create(:ci_job_variable, job: build, key: 'OLD_KEY', value: 'i will not live for long') - new_build = build.clone(current_user: user, new_job_variables_attributes: [ - { key: 'TEST_KEY', value: 'new value' }, - { key: 'NEW_KEY', value: 'exciting new value' } - ]) + new_build = build.clone(current_user: user, new_job_variables_attributes: + [ + { key: 'TEST_KEY', value: 'new value' }, + { key: 'NEW_KEY', value: 'exciting new value' } + ]) new_build.save! expect(new_build.job_variables.count).to be(2) @@ -5492,9 +5494,10 @@ RSpec.describe Ci::Build do build = create(:ci_build) create(:ci_job_variable, job: build, key: 'TEST_KEY', value: 'old value') - new_build = build.clone(current_user: user, new_job_variables_attributes: [ - { key: 'TEST_KEY', value: 'new value' } - ]) + new_build = build.clone( + current_user: user, + new_job_variables_attributes: [{ key: 'TEST_KEY', value: 'new value' }] + ) new_build.save! expect(new_build.job_variables.count).to be(1) diff --git a/spec/models/ci/build_trace_spec.rb b/spec/models/ci/build_trace_spec.rb index bd24e8be1ac..f2df4874b84 100644 --- a/spec/models/ci/build_trace_spec.rb +++ b/spec/models/ci/build_trace_spec.rb @@ -28,9 +28,10 @@ RSpec.describe Ci::BuildTrace do it_behaves_like 'delegates methods' it 'returns formatted trace' do - expect(subject.lines).to eq([ - { offset: 0, content: [{ text: 'the-stream' }] } - ]) + expect(subject.lines).to eq( + [ + { offset: 0, content: [{ text: 'the-stream' }] } + ]) end context 'with invalid UTF-8 data' do diff --git a/spec/models/ci/daily_build_group_report_result_spec.rb b/spec/models/ci/daily_build_group_report_result_spec.rb index d0141a1469e..cd55817243f 100644 --- a/spec/models/ci/daily_build_group_report_result_spec.rb +++ b/spec/models/ci/daily_build_group_report_result_spec.rb @@ -41,24 +41,25 @@ RSpec.describe Ci::DailyBuildGroupReportResult do let!(:new_pipeline) { create(:ci_pipeline) } it 'creates or updates matching report results' do - described_class.upsert_reports([ - { - project_id: rspec_coverage.project_id, - ref_path: rspec_coverage.ref_path, - last_pipeline_id: new_pipeline.id, - date: rspec_coverage.date, - group_name: 'rspec', - data: { 'coverage' => 81.0 } - }, - { - project_id: rspec_coverage.project_id, - ref_path: rspec_coverage.ref_path, - last_pipeline_id: new_pipeline.id, - date: rspec_coverage.date, - group_name: 'karma', - data: { 'coverage' => 87.0 } - } - ]) + described_class.upsert_reports( + [ + { + project_id: rspec_coverage.project_id, + ref_path: rspec_coverage.ref_path, + last_pipeline_id: new_pipeline.id, + date: rspec_coverage.date, + group_name: 'rspec', + data: { 'coverage' => 81.0 } + }, + { + project_id: rspec_coverage.project_id, + ref_path: rspec_coverage.ref_path, + last_pipeline_id: new_pipeline.id, + date: rspec_coverage.date, + group_name: 'karma', + data: { 'coverage' => 87.0 } + } + ]) rspec_coverage.reload diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 8bf32527342..d854943e277 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -4531,10 +4531,11 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do end it 'returns accessibility report with collected data' do - expect(subject.urls.keys).to match_array([ - "https://pa11y.org/", - "https://about.gitlab.com/" - ]) + expect(subject.urls.keys).to match_array( + [ + "https://pa11y.org/", + "https://about.gitlab.com/" + ]) end context 'when builds are retried' do diff --git a/spec/requests/api/graphql/mutations/work_items/update_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_spec.rb index 909d6549fa5..6b0129c457f 100644 --- a/spec/requests/api/graphql/mutations/work_items/update_spec.rb +++ b/spec/requests/api/graphql/mutations/work_items/update_spec.rb @@ -144,6 +144,78 @@ RSpec.describe 'Update a work item' do end end + context 'with labels widget input' do + shared_examples 'mutation updating work item labels' do + it 'updates labels' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + work_item.reload + end.to change { work_item.labels.count }.to(expected_labels.count) + + expect(work_item.labels).to match_array(expected_labels) + expect(mutation_response['workItem']['widgets']).to include( + 'labels' => { + 'nodes' => match_array(expected_labels.map { |l| { 'id' => l.to_gid.to_s } }) + }, + 'type' => 'LABELS' + ) + end + end + + let_it_be(:existing_label) { create(:label, project: project) } + let_it_be(:label1) { create(:label, project: project) } + let_it_be(:label2) { create(:label, project: project) } + + let(:fields) do + <<~FIELDS + workItem { + widgets { + type + ... on WorkItemWidgetLabels { + labels { + nodes { id } + } + } + } + } + errors + FIELDS + end + + let(:input) do + { 'labelsWidget' => { 'addLabelIds' => add_label_ids, 'removeLabelIds' => remove_label_ids } } + end + + let(:add_label_ids) { [] } + let(:remove_label_ids) { [] } + + before_all do + work_item.update!(labels: [existing_label]) + end + + context 'when only removing labels' do + let(:remove_label_ids) { [existing_label.to_gid.to_s] } + let(:expected_labels) { [] } + + it_behaves_like 'mutation updating work item labels' + end + + context 'when only adding labels' do + let(:add_label_ids) { [label1.to_gid.to_s, label2.to_gid.to_s] } + let(:expected_labels) { [label1, label2, existing_label] } + + it_behaves_like 'mutation updating work item labels' + end + + context 'when adding and removing labels' do + let(:remove_label_ids) { [existing_label.to_gid.to_s] } + let(:add_label_ids) { [label1.to_gid.to_s, label2.to_gid.to_s] } + let(:expected_labels) { [label1, label2] } + + it_behaves_like 'mutation updating work item labels' + end + end + context 'with due and start date widget input' do let(:start_date) { Date.today } let(:due_date) { 1.week.from_now.to_date } diff --git a/spec/support/shared_examples/features/wiki/user_views_wiki_pages_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_wiki_pages_shared_examples.rb index 32cb2b1d187..979c8ac2e84 100644 --- a/spec/support/shared_examples/features/wiki/user_views_wiki_pages_shared_examples.rb +++ b/spec/support/shared_examples/features/wiki/user_views_wiki_pages_shared_examples.rb @@ -4,7 +4,7 @@ # wiki # user -RSpec.shared_examples 'User views wiki pages' do +RSpec.shared_examples 'User views wiki pages' do |support_sorting_by_created_at = true| include WikiHelpers let!(:wiki_page1) do @@ -54,34 +54,37 @@ RSpec.shared_examples 'User views wiki pages' do end end - context 'ordered by created_at' do - let(:pages_ordered_by_created_at) { [wiki_page1, wiki_page2, wiki_page3] } + if support_sorting_by_created_at + context 'ordered by created_at' do + let(:pages_ordered_by_created_at) { [wiki_page1, wiki_page2, wiki_page3] } - before do - page.within('.wiki-sort-dropdown') do - click_button('Title') - click_button('Created date') + before do + stub_feature_flags(wiki_list_pages_with_normal_repository_rpcs: false) + page.within('.wiki-sort-dropdown') do + click_button('Title') + click_button('Created date') + end end - end - context 'asc' do - it 'pages are displayed in direct order' do - pages.each.with_index do |page_title, index| - expect(page_title.text).to eq(pages_ordered_by_created_at[index].title) + context 'asc' do + it 'pages are displayed in direct order' do + pages.each.with_index do |page_title, index| + expect(page_title.text).to eq(pages_ordered_by_created_at[index].title) + end end end - end - context 'desc' do - before do - page.within('.wiki-sort-dropdown') do - page.find('.rspec-reverse-sort').click + context 'desc' do + before do + page.within('.wiki-sort-dropdown') do + page.find('.rspec-reverse-sort').click + end end - end - it 'pages are displayed in reversed order' do - pages.reverse_each.with_index do |page_title, index| - expect(page_title.text).to eq(pages_ordered_by_created_at[index].title) + it 'pages are displayed in reversed order' do + pages.reverse_each.with_index do |page_title, index| + expect(page_title.text).to eq(pages_ordered_by_created_at[index].title) + end end end end diff --git a/spec/support/shared_examples/models/wiki_shared_examples.rb b/spec/support/shared_examples/models/wiki_shared_examples.rb index b9c273b1e1a..7dc36bf227e 100644 --- a/spec/support/shared_examples/models/wiki_shared_examples.rb +++ b/spec/support/shared_examples/models/wiki_shared_examples.rb @@ -180,70 +180,71 @@ RSpec.shared_examples 'wiki model' do it 'returns false' do expect(subject.empty?).to be(false) end - - it 'only instantiates a Wiki page once' do - expect(WikiPage).to receive(:new).once.and_call_original - - subject.empty? - end end end end describe '#list_pages' do - let(:wiki_pages) { subject.list_pages } + shared_examples 'wiki model #list_pages' do + let(:wiki_pages) { subject.list_pages } - before do - subject.create_page('index', 'This is an index') - subject.create_page('index2', 'This is an index2') - subject.create_page('an index3', 'This is an index3') - end + before do + subject.create_page('index', 'This is an index') + subject.create_page('index2', 'This is an index2') + subject.create_page('an index3', 'This is an index3') + end - it 'returns an array of WikiPage instances' do - expect(wiki_pages).to be_present - expect(wiki_pages).to all(be_a(WikiPage)) - end + it 'returns an array of WikiPage instances' do + expect(wiki_pages).to be_present + expect(wiki_pages).to all(be_a(WikiPage)) + end - it 'does not load WikiPage content by default' do - wiki_pages.each do |page| - expect(page.content).to be_empty + it 'does not load WikiPage content by default' do + wiki_pages.each do |page| + expect(page.content).to be_empty + end end - end - it 'returns all pages by default' do - expect(wiki_pages.count).to eq(3) - end + it 'returns all pages by default' do + expect(wiki_pages.count).to eq(3) + end - context 'with limit option' do - it 'returns limited set of pages' do - expect(subject.list_pages(limit: 1).count).to eq(1) + context 'with limit option' do + it 'returns limited set of pages' do + expect(subject.list_pages(limit: 1).count).to eq(1) + end end - end - context 'with sorting options' do - it 'returns pages sorted by title by default' do - pages = ['an index3', 'index', 'index2'] + context 'with sorting options' do + it 'returns pages sorted by title by default' do + pages = ['an index3', 'index', 'index2'] - expect(subject.list_pages.map(&:title)).to eq(pages) - expect(subject.list_pages(direction: 'desc').map(&:title)).to eq(pages.reverse) + expect(subject.list_pages.map(&:title)).to eq(pages) + expect(subject.list_pages(direction: 'desc').map(&:title)).to eq(pages.reverse) + end end - it 'returns pages sorted by created_at' do - pages = ['index', 'index2', 'an index3'] + context 'with load_content option' do + let(:pages) { subject.list_pages(load_content: true) } - expect(subject.list_pages(sort: 'created_at').map(&:title)).to eq(pages) - expect(subject.list_pages(sort: 'created_at', direction: 'desc').map(&:title)).to eq(pages.reverse) + it 'loads WikiPage content' do + expect(pages.first.content).to eq('This is an index3') + expect(pages.second.content).to eq('This is an index') + expect(pages.third.content).to eq('This is an index2') + end end end - context 'with load_content option' do - let(:pages) { subject.list_pages(load_content: true) } - - it 'loads WikiPage content' do - expect(pages.first.content).to eq('This is an index3') - expect(pages.second.content).to eq('This is an index') - expect(pages.third.content).to eq('This is an index2') + context 'list pages with legacy wiki rpcs' do + before do + stub_feature_flags(wiki_list_page_with_normal_repository_rpcs: false) end + + it_behaves_like 'wiki model #list_pages' + end + + context 'list pages with normal repository rpcs' do + it_behaves_like 'wiki model #list_pages' end end @@ -531,7 +532,7 @@ RSpec.shared_examples 'wiki model' do it 'sets the correct commit message' do subject.create_page('test page', 'some content', :markdown, 'commit message') - expect(subject.list_pages.first.page.version.message).to eq('commit message') + expect(subject.list_pages.first.version.message).to eq('commit message') end it 'sets the correct commit email' do diff --git a/spec/views/layouts/devise.html.haml_spec.rb b/spec/views/layouts/devise.html.haml_spec.rb index e69cf93cfb4..b37bdeceb7e 100644 --- a/spec/views/layouts/devise.html.haml_spec.rb +++ b/spec/views/layouts/devise.html.haml_spec.rb @@ -4,4 +4,22 @@ require 'spec_helper' RSpec.describe 'layouts/devise' do it_behaves_like 'a layout which reflects the application theme setting' + + describe 'logo' do + it 'renders GitLab logo' do + render + + expect(rendered).to have_selector('img[alt^="GitLab"]') + end + + context 'with custom logo' do + let_it_be(:appearance) { create(:appearance, logo: fixture_file_upload('spec/fixtures/dk.png')) } + + it 'renders custom logo' do + render + + expect(rendered).to have_selector('img[data-src$="dk.png"]') + end + end + end end |