# frozen_string_literal: true require 'spec_helper' RSpec.describe SearchHelper, feature_category: :global_search do include MarkupHelper include BadgesHelper # Override simple_sanitize for our testing purposes def simple_sanitize(str) str end describe 'search_autocomplete_opts' do context "with no current user" do before do allow(self).to receive(:current_user).and_return(nil) end it "returns nil" do expect(search_autocomplete_opts("q")).to be_nil end end context "with a standard user" do let(:user) { create(:user) } before do allow(self).to receive(:current_user).and_return(user) end it "includes Help sections" do expect(search_autocomplete_opts("hel").size).to eq(8) end it "includes default sections" do expect(search_autocomplete_opts("dash").size).to eq(1) end it "does not include admin sections" do expect(search_autocomplete_opts("admin").size).to eq(0) end it "does not allow regular expression in search term" do expect(search_autocomplete_opts("(webhooks|api)").size).to eq(0) end it "includes the user's groups" do create(:group).add_owner(user) expect(search_autocomplete_opts("gro").size).to eq(1) end it "includes nested group" do create(:group, :nested, name: 'foo').add_owner(user) expect(search_autocomplete_opts('foo').size).to eq(1) end it "includes the user's projects" do project = create(:project, namespace: create(:namespace, owner: user)) expect(search_autocomplete_opts(project.name).size).to eq(1) end shared_examples 'for users' do let_it_be(:another_user) { create(:user, name: 'Jane Doe') } let(:term) { 'jane' } it 'returns users matching the term' do result = search_autocomplete_opts(term) expect(result.size).to eq(1) expect(result.first[:id]).to eq(another_user.id) end context 'when current_user cannot read_users_list' do before do allow(Ability).to receive(:allowed?).and_return(true) allow(Ability).to receive(:allowed?).with(current_user, :read_users_list).and_return(false) end it 'returns an empty array' do expect(search_autocomplete_opts(term)).to eq([]) end end describe 'permissions' do let(:term) { 'jane@doe' } let(:private_email_user) { create(:user, email: term) } let(:public_email_user) { create(:user, :public_email, email: term) } let(:banned_user) { create(:user, :banned, email: term) } let(:user_with_other_email) { create(:user, email: 'something@else') } let(:secondary_email) { create(:email, :confirmed, user: user_with_other_email, email: term) } let(:ids) { search_autocomplete_opts(term).pluck(:id) } context 'when current_user is an admin' do before do allow(current_user).to receive(:can_admin_all_resources?).and_return(true) end it 'includes users with matching public emails' do public_email_user expect(ids).to include(public_email_user.id) end it 'includes users in forbidden states' do banned_user expect(ids).to include(banned_user.id) end it 'includes users without matching public emails but with matching private emails' do private_email_user expect(ids).to include(private_email_user.id) end it 'includes users matching on secondary email' do secondary_email expect(ids).to include(secondary_email.user_id) end end context 'when current_user is not an admin' do before do allow(current_user).to receive(:can_admin_all_resources?).and_return(false) end it 'includes users with matching public emails' do public_email_user expect(ids).to include(public_email_user.id) end it 'does not include users in forbidden states' do banned_user expect(ids).not_to include(banned_user.id) end it 'does not include users without matching public emails but with matching private emails' do private_email_user expect(ids).not_to include(private_email_user.id) end it 'does not include users matching on secondary email' do secondary_email expect(ids).not_to include(secondary_email.user_id) end end end context 'with limiting' do let!(:users) { create_list(:user, 6, name: 'Jane Doe') } it 'only returns the first 5 users' do result = search_autocomplete_opts(term) expect(result.size).to eq(5) end end end include_examples 'for users' it "includes the required project attrs" do project = create(:project, namespace: create(:namespace, owner: user)) result = search_autocomplete_opts(project.name).first expect(result.keys).to match_array(%i[category id value label url avatar_url]) end it "includes the required group attrs" do create(:group).add_owner(user) result = search_autocomplete_opts("gro").first expect(result.keys).to match_array(%i[category id value label url avatar_url]) end it 'includes the users recently viewed issues and project with correct order', :aggregate_failures do recent_issues = instance_double(::Gitlab::Search::RecentIssues) expect(::Gitlab::Search::RecentIssues).to receive(:new).with(user: user).and_return(recent_issues) project1 = create(:project, :with_avatar, namespace: user.namespace) project2 = create(:project, namespace: user.namespace) issue1 = create(:issue, title: 'issue 1', project: project1) issue2 = create(:issue, title: 'issue 2', project: project2) project = create(:project, title: 'the search term') project.add_developer(user) expect(recent_issues).to receive(:search).with('the search term').and_return(Issue.id_in_ordered([issue1.id, issue2.id])) results = search_autocomplete_opts("the search term") expect(results.count).to eq(3) expect(results[0]).to include({ category: 'Recent issues', id: issue1.id, label: 'issue 1', url: Gitlab::Routing.url_helpers.project_issue_path(issue1.project, issue1), avatar_url: project1.avatar_url }) expect(results[1]).to include({ category: 'Recent issues', id: issue2.id, label: 'issue 2', url: Gitlab::Routing.url_helpers.project_issue_path(issue2.project, issue2), avatar_url: '' # This project didn't have an avatar so set this to '' }) expect(results[2]).to include({ category: 'Projects', id: project.id, label: project.full_name, url: Gitlab::Routing.url_helpers.project_path(project) }) end it 'includes the users recently viewed issues with the exact same name', :aggregate_failures do recent_issues = instance_double(::Gitlab::Search::RecentIssues) expect(::Gitlab::Search::RecentIssues).to receive(:new).with(user: user).and_return(recent_issues) project1 = create(:project, namespace: user.namespace) project2 = create(:project, namespace: user.namespace) issue1 = create(:issue, title: 'issue same_name', project: project1) issue2 = create(:issue, title: 'issue same_name', project: project2) expect(recent_issues).to receive(:search).with('the search term').and_return(Issue.id_in_ordered([issue1.id, issue2.id])) results = search_autocomplete_opts("the search term") expect(results.count).to eq(2) expect(results[0]).to include({ category: 'Recent issues', id: issue1.id, label: 'issue same_name', url: Gitlab::Routing.url_helpers.project_issue_path(issue1.project, issue1), avatar_url: '' # This project didn't have an avatar so set this to '' }) expect(results[1]).to include({ category: 'Recent issues', id: issue2.id, label: 'issue same_name', url: Gitlab::Routing.url_helpers.project_issue_path(issue2.project, issue2), avatar_url: '' # This project didn't have an avatar so set this to '' }) end it 'includes the users recently viewed merge requests', :aggregate_failures do recent_merge_requests = instance_double(::Gitlab::Search::RecentMergeRequests) expect(::Gitlab::Search::RecentMergeRequests).to receive(:new).with(user: user).and_return(recent_merge_requests) project1 = create(:project, :with_avatar, namespace: user.namespace) project2 = create(:project, namespace: user.namespace) merge_request1 = create(:merge_request, :unique_branches, title: 'Merge request 1', target_project: project1, source_project: project1) merge_request2 = create(:merge_request, :unique_branches, title: 'Merge request 2', target_project: project2, source_project: project2) expect(recent_merge_requests).to receive(:search).with('the search term').and_return(MergeRequest.id_in_ordered([merge_request1.id, merge_request2.id])) results = search_autocomplete_opts("the search term") expect(results.count).to eq(2) expect(results[0]).to include({ category: 'Recent merge requests', id: merge_request1.id, label: 'Merge request 1', url: Gitlab::Routing.url_helpers.project_merge_request_path(merge_request1.project, merge_request1), avatar_url: project1.avatar_url }) expect(results[1]).to include({ category: 'Recent merge requests', id: merge_request2.id, label: 'Merge request 2', url: Gitlab::Routing.url_helpers.project_merge_request_path(merge_request2.project, merge_request2), avatar_url: '' # This project didn't have an avatar so set this to '' }) end it "does not include the public group" do group = create(:group) expect(search_autocomplete_opts(group.name).size).to eq(0) end context "with a current project" do before do @project = create(:project, :repository) allow(self).to receive(:can?).and_return(true) allow(self).to receive(:can?).with(user, :read_feature_flag, @project).and_return(false) end it 'returns repository related labels based on users abilities', :aggregate_failures do expect(search_autocomplete_opts("Files").size).to eq(1) expect(search_autocomplete_opts("Commits").size).to eq(1) expect(search_autocomplete_opts("Network").size).to eq(1) expect(search_autocomplete_opts("Graph").size).to eq(1) allow(self).to receive(:can?).with(user, :read_code, @project).and_return(false) expect(search_autocomplete_opts("Files").size).to eq(0) expect(search_autocomplete_opts("Commits").size).to eq(0) allow(self).to receive(:can?).with(user, :read_repository_graphs, @project).and_return(false) expect(search_autocomplete_opts("Network").size).to eq(0) expect(search_autocomplete_opts("Graph").size).to eq(0) end context 'when user does not have access to project' do it 'does not include issues by iid' do issue = create(:issue, project: @project) results = search_autocomplete_opts("\##{issue.iid}") expect(results.count).to eq(0) end end context 'when user has project access' do before do @project = create(:project, :repository, namespace: user.namespace) allow(self).to receive(:can?).with(user, :read_feature_flag, @project).and_return(true) end it 'includes issues by iid', :aggregate_failures do issue = create(:issue, project: @project, title: 'test title') results = search_autocomplete_opts("\##{issue.iid}") expect(results.count).to eq(1) expect(results.first).to include({ category: 'In this project', id: issue.id, label: "test title (##{issue.iid})", url: ::Gitlab::Routing.url_helpers.project_issue_path(issue.project, issue), avatar_url: '' # project has no avatar }) end end context 'with a search scope' do let(:term) { 'bla' } let(:scope) { 'project' } it 'returns scoped resource results' do expect(self).to receive(:resource_results).with(term, scope: scope).and_return([]) search_autocomplete_opts(term, filter: :search, scope: scope) end end end end context 'with an admin user' do let(:admin) { create(:admin) } before do allow(self).to receive(:current_user).and_return(admin) end context 'when admin mode setting is disabled', :do_not_mock_admin_mode_setting do it 'includes admin sections' do expect(search_autocomplete_opts('admin').size).to eq(1) end end context 'when admin mode setting is enabled' do context 'when in admin mode', :enable_admin_mode do it 'includes admin sections' do expect(search_autocomplete_opts('admin').size).to eq(1) end end context 'when not in admin mode' do it 'does not include admin sections' do expect(search_autocomplete_opts('admin').size).to eq(0) end end end end end describe 'resource_results' do using RSpec::Parameterized::TableSyntax let_it_be(:user) { create(:user, name: 'User') } let_it_be(:group) { create(:group, name: 'Group') } let_it_be(:project) { create(:project, name: 'Project') } let!(:issue) { create(:issue, project: project) } let(:issue_iid) { "\##{issue.iid}" } before do allow(self).to receive(:current_user).and_return(user) group.add_owner(user) project.add_owner(user) @project = project end where(:term, :size, :category) do 'g' | 0 | 'Groups' 'gr' | 1 | 'Groups' 'gro' | 1 | 'Groups' 'p' | 0 | 'Projects' 'pr' | 1 | 'Projects' 'pro' | 1 | 'Projects' 'u' | 0 | 'Users' 'us' | 1 | 'Users' 'use' | 1 | 'Users' ref(:issue_iid) | 1 | 'In this project' end with_them do it 'returns results only if the term is more than or equal to Gitlab::Search::Params::MIN_TERM_LENGTH' do results = resource_results(term) expect(results.size).to eq(size) expect(results.first[:category]).to eq(category) if size == 1 end end context 'with a search scope' do let(:term) { 'bla' } let(:scope) { 'project' } it 'returns only scope-specific results' do expect(self).to receive(:scope_specific_results).with(term, scope).and_return([]) expect(self).not_to receive(:groups_autocomplete) expect(self).not_to receive(:projects_autocomplete) expect(self).not_to receive(:users_autocomplete) expect(self).not_to receive(:issue_autocomplete) resource_results(term, scope: scope) end end end describe 'scope_specific_results' do using RSpec::Parameterized::TableSyntax let_it_be(:user) { create(:user, name: 'Searched') } let_it_be(:project) { create(:project, name: 'Searched') } let_it_be(:issue) { create(:issue, title: 'Searched', project: project) } before do allow(self).to receive(:current_user).and_return(user) allow_next_instance_of(Gitlab::Search::RecentIssues) do |recent_issues| allow(recent_issues).to receive(:search).and_return([issue]) end project.add_developer(user) end where(:scope, :category) do 'user' | 'Users' 'project' | 'Projects' 'issue' | 'Recent issues' end with_them do it 'returns results only for the specific scope' do results = scope_specific_results('sea', scope) expect(results.size).to eq(1) expect(results.first[:category]).to eq(category) end end context 'when scope is unknown' do it 'does not return any results' do expect(scope_specific_results('sea', 'other')).to eq([]) end end end describe 'projects_autocomplete' do let_it_be(:user) { create(:user) } let_it_be(:project_1) { create(:project, name: 'test 1') } let_it_be(:project_2) { create(:project, name: 'test 2') } let(:search_term) { 'test' } before do allow(self).to receive(:current_user).and_return(user) end context 'when the user does not have access to projects' do it 'does not return any results' do expect(projects_autocomplete(search_term)).to eq([]) end end context 'when the user has access to one project' do before do project_2.add_developer(user) end it 'returns the project' do expect(projects_autocomplete(search_term).pluck(:id)).to eq([project_2.id]) end context 'when a project namespace matches the search term but the project does not' do let_it_be(:group) { create(:group, name: 'test group') } let_it_be(:project_3) { create(:project, name: 'nothing', namespace: group) } before do group.add_owner(user) end it 'returns all projects matching the term' do expect(projects_autocomplete(search_term).pluck(:id)).to match_array([project_2.id, project_3.id]) end end end end describe 'search_entries_info' do using RSpec::Parameterized::TableSyntax where(:scope, :label) do 'blobs' | 'code result' 'commits' | 'commit' 'issues' | 'issue' 'merge_requests' | 'merge request' 'milestones' | 'milestone' 'notes' | 'comment' 'projects' | 'project' 'snippet_titles' | 'snippet' 'users' | 'user' 'wiki_blobs' | 'wiki result' end with_them do it 'uses the correct singular label' do collection = Kaminari.paginate_array([:foo]).page(1).per(10) expect(search_entries_info(collection, scope, 'foo')).to eq("Showing 1 #{label} for  foo ") end it 'uses the correct plural label' do collection = Kaminari.paginate_array([:foo] * 23).page(1).per(10) expect(search_entries_info(collection, scope, 'foo')).to eq("Showing 1 - 10 of 23 #{label.pluralize} for  foo ") end end it 'raises an error for unrecognized scopes' do expect do collection = Kaminari.paginate_array([:foo]).page(1).per(10) search_entries_info(collection, 'unknown', 'foo') end.to raise_error(RuntimeError) end end describe 'search_entries_empty_message' do let!(:group) { build(:group) } let!(:project) { build(:project, group: group) } context 'global search' do let(:message) { search_entries_empty_message('projects', '

foo

', nil, nil) } it 'returns the formatted entry message' do expect(message).to eq("We couldn't find any projects matching <h1>foo</h1>") expect(message).to be_html_safe end end context 'group search' do let(:message) { search_entries_empty_message('projects', '

foo

', group, nil) } it 'returns the formatted entry message' do expect(message).to start_with('We couldn't find any projects matching <h1>foo</h1> in group foo', group, project) } it 'returns the formatted entry message' do expect(message).to start_with('We couldn't find any projects matching <h1>foo</h1> in project test' 'this test should not be blue' | 'this test should not be blue' 'Click Me test' | 'Click Me test' ' test' | ' test' 'Lorem test ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec.' | 'Lorem test ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Don...' 'some image' | 'some image' '

Additional information test:

' | 'Additional information test:' end with_them do it 'sanitizes, truncates, and highlights the search term' do expect(subject).to eq(expected) end end end end describe '#search_service' do using RSpec::Parameterized::TableSyntax subject { search_service } before do allow(self).to receive(:current_user).and_return(:the_current_user) end shared_context 'with inputs' do where(:input, :expected) do '0' | false '1' | true 'yes' | true 'no' | false 'true' | true 'false' | false true | true false | false end end describe 'for confidential' do let(:params) { { confidential: input } } include_context 'with inputs' with_them do it 'transforms param' do expect(::SearchService).to receive(:new).with(:the_current_user, { confidential: expected }) subject end end end describe 'for include_archived' do let(:params) { { include_archived: input } } include_context 'with inputs' with_them do it 'transforms param' do expect(::SearchService).to receive(:new).with(:the_current_user, { include_archived: expected }) subject end end end end describe '#issuable_state_to_badge_class' do context 'with merge request' do it 'returns correct badge based on status' do expect(issuable_state_to_badge_class(build(:merge_request, :merged))).to eq(:info) expect(issuable_state_to_badge_class(build(:merge_request, :closed))).to eq(:danger) expect(issuable_state_to_badge_class(build(:merge_request, :opened))).to eq(:success) end end context 'with an issue' do it 'returns correct badge based on status' do expect(issuable_state_to_badge_class(build(:issue, :closed))).to eq(:info) expect(issuable_state_to_badge_class(build(:issue, :opened))).to eq(:success) end end end describe '#issuable_state_text' do context 'with merge request' do it 'returns correct badge based on status' do expect(issuable_state_text(build(:merge_request, :merged))).to eq(_('Merged')) expect(issuable_state_text(build(:merge_request, :closed))).to eq(_('Closed')) expect(issuable_state_text(build(:merge_request, :opened))).to eq(_('Open')) end end context 'with an issue' do it 'returns correct badge based on status' do expect(issuable_state_text(build(:issue, :closed))).to eq(_('Closed')) expect(issuable_state_text(build(:issue, :opened))).to eq(_('Open')) end end end describe '#search_sort_options' do let(:user) { create(:user) } mock_created_sort = [ { title: _('Created date'), sortable: true, sortParam: { asc: 'created_asc', desc: 'created_desc' } }, { title: _('Updated date'), sortable: true, sortParam: { asc: 'updated_asc', desc: 'updated_desc' } } ] before do allow(self).to receive(:current_user).and_return(user) end it 'returns the correct data' do expect(search_sort_options).to eq(mock_created_sort) end end describe '#header_search_context' do let(:user) { create(:user) } let(:can_download) { false } let_it_be(:group) { nil } let_it_be(:project) { nil } let(:scope) { nil } let(:ref) { nil } let(:snippet) { nil } before do @project = project @group = group @ref = ref @snippet = snippet allow(self).to receive(:current_user).and_return(user) allow(self).to receive(:search_scope).and_return(scope) allow(self).to receive(:can?).and_return(can_download) end context 'no group or project data' do it 'does not add :group, :group_metadata, or :scope to hash' do expect(header_search_context[:group]).to eq(nil) expect(header_search_context[:group_metadata]).to eq(nil) expect(header_search_context[:scope]).to eq(nil) end it 'does not add :project, :project_metadata, :code_search, or :ref' do expect(header_search_context[:project]).to eq(nil) expect(header_search_context[:project_metadata]).to eq(nil) expect(header_search_context[:code_search]).to eq(nil) expect(header_search_context[:ref]).to eq(nil) end end context 'group data' do let_it_be(:group) { create(:group) } let(:group_metadata) { { issues_path: issues_group_path(group), mr_path: merge_requests_group_path(group) } } let(:scope) { 'issues' } it 'adds the :group, :group_metadata, and :scope correctly to hash' do expect(header_search_context[:group]).to eq({ id: group.id, name: group.name, full_name: group.full_name }) expect(header_search_context[:group_metadata]).to eq(group_metadata) expect(header_search_context[:scope]).to eq(scope) end it 'does not add :project, :project_metadata, :code_search, or :ref' do expect(header_search_context[:project]).to eq(nil) expect(header_search_context[:project_metadata]).to eq(nil) expect(header_search_context[:code_search]).to eq(nil) expect(header_search_context[:ref]).to eq(nil) end end context 'project data' do let_it_be(:project_group) { create(:group) } let_it_be(:project) { create(:project, group: project_group) } let(:project_metadata) { { issues_path: project_issues_path(project), mr_path: project_merge_requests_path(project) } } let(:group_metadata) { { issues_path: issues_group_path(project_group), mr_path: merge_requests_group_path(project_group) } } it 'adds the :group and :group-metadata from the project correctly to hash' do expect(header_search_context[:group]).to eq({ id: project_group.id, name: project_group.name, full_name: project_group.full_name }) expect(header_search_context[:group_metadata]).to eq(group_metadata) end it 'adds the :project and :project-metadata correctly to hash' do expect(header_search_context[:project]).to eq({ id: project.id, name: project.name }) expect(header_search_context[:project_metadata]).to eq(project_metadata) end context 'feature issues is not available' do let(:feature_available) { false } let(:project_metadata) { { mr_path: project_merge_requests_path(project) } } before do allow(project).to receive(:feature_available?).and_call_original allow(project).to receive(:feature_available?).with(:issues, current_user).and_return(feature_available) end it 'adds the :project and :project-metadata correctly to hash' do expect(header_search_context[:project]).to eq({ id: project.id, name: project.name }) expect(header_search_context[:project_metadata]).to eq(project_metadata) end end context 'with scope' do let(:scope) { 'issues' } it 'adds :scope and false :code_search to hash' do expect(header_search_context[:scope]).to eq(scope) expect(header_search_context[:code_search]).to eq(false) end end context 'without scope' do it 'adds code_search true to hash and not :scope' do expect(header_search_context[:scope]).to eq(nil) expect(header_search_context[:code_search]).to eq(true) end end end context 'ref data' do let_it_be(:project) { create(:project) } let(:ref) { 'test-branch' } context 'when user can? download project data' do let(:can_download) { true } it 'adds the :ref correctly to hash' do expect(header_search_context[:ref]).to eq(ref) end end context 'when user cannot download project data' do let(:can_download) { false } it 'does not add the :ref to hash' do expect(header_search_context[:ref]).to eq(nil) end end end context 'snippet' do context 'when searching from snippets' do let(:snippet) { create(:snippet) } it 'adds :for_snippets true correctly to hash' do expect(header_search_context[:for_snippets]).to eq(true) end end context 'when not searching from snippets' do it 'adds :for_snippets nil correctly to hash' do expect(header_search_context[:for_snippets]).to eq(nil) end end end end describe '.search_navigation_json' do using RSpec::Parameterized::TableSyntax context 'with some tab conditions set to false' do example_data_1 = { projects: { label: _("Projects"), condition: true }, blobs: { label: _("Code"), condition: false } } example_data_2 = { projects: { label: _("Projects"), condition: false }, blobs: { label: _("Code"), condition: false } } example_data_3 = { projects: { label: _("Projects"), condition: true }, blobs: { label: _("Code"), condition: true }, epics: { label: _("Epics"), condition: true } } where(:data, :matcher) do example_data_1 | -> { include("projects") } example_data_2 | -> { eq("{}") } example_data_3 | -> { include("projects", "blobs", "epics") } end with_them do it 'renders data correctly' do allow(self).to receive(:current_user).and_return(build(:user)) allow_next_instance_of(Search::Navigation) do |search_nav| allow(search_nav).to receive(:tabs).and_return(data) end expect(search_navigation_json).to instance_exec(&matcher) end end end context 'when all options enabled' do before do allow(self).to receive(:current_user).and_return(build(:user)) allow(search_service).to receive(:show_snippets?).and_return(true) allow_next_instance_of(Search::Navigation) do |search_nav| allow(search_nav).to receive(:tab_enabled_for_project?).and_return(true) allow(search_nav).to receive(:feature_flag_tab_enabled?).and_return(true) end @project = nil end it 'returns items in order' do expect(Gitlab::Json.parse(search_navigation_json).keys).to eq(%w[projects blobs issues merge_requests wiki_blobs commits notes milestones users snippet_titles]) end end end describe '.search_filter_link_json' do using RSpec::Parameterized::TableSyntax context 'data' do where(:scope, :label, :data, :search, :active_scope) do "projects" | "Projects" | { qa_selector: 'projects_tab' } | nil | "projects" "snippet_titles" | "Snippets" | nil | { snippets: "test" } | "code" "projects" | "Projects" | { qa_selector: 'projects_tab' } | nil | "issue" "snippet_titles" | "Snippets" | nil | { snippets: "test" } | "snippet_titles" end with_them do it 'converts correctly' do @timeout = false @scope = active_scope @search_results = double dummy_count = 1000 allow(self).to receive(:search_path).with(any_args).and_return("link test") allow(@search_results).to receive(:formatted_count).with(scope).and_return(dummy_count) allow(self).to receive(:search_count_path).with(any_args).and_return("test count link") current_scope = scope == active_scope expected = { label: label, scope: scope, data: data, link: "link test", active: current_scope } expected[:count] = dummy_count if current_scope expected[:count_link] = "test count link" unless current_scope expect(search_filter_link_json(scope, label, data, search)).to eq(expected) end end end end describe '#wiki_blob_link' do let_it_be(:project) { create :project, :wiki_repo } let(:wiki_blob) do Gitlab::Search::FoundBlob.new({ path: 'test', basename: 'test', ref: 'master', data: 'foo', startline: 2, project: project, project_id: project.id }) end it { expect(wiki_blob_link(wiki_blob)).to eq("/#{project.namespace.path}/#{project.path}/-/wikis/#{wiki_blob.path}") } end end