diff options
Diffstat (limited to 'spec/graphql/resolvers')
8 files changed, 299 insertions, 115 deletions
diff --git a/spec/graphql/resolvers/concerns/resolves_groups_spec.rb b/spec/graphql/resolvers/concerns/resolves_groups_spec.rb new file mode 100644 index 00000000000..bfbbae29e92 --- /dev/null +++ b/spec/graphql/resolvers/concerns/resolves_groups_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ResolvesGroups do + include GraphqlHelpers + include AfterNextHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:groups) { create_pair(:group) } + + let_it_be(:resolver) do + Class.new(Resolvers::BaseResolver) do + include ResolvesGroups + type Types::GroupType, null: true + end + end + + let_it_be(:query_type) do + query_factory do |query| + query.field :groups, + Types::GroupType.connection_type, + null: true, + resolver: resolver + end + end + + let_it_be(:lookahead_fields) do + <<~FIELDS + contacts { nodes { id } } + containerRepositoriesCount + customEmoji { nodes { id } } + fullPath + organizations { nodes { id } } + path + dependencyProxyBlobCount + dependencyProxyBlobs { nodes { fileName } } + dependencyProxyImageCount + dependencyProxyImageTtlPolicy { enabled } + dependencyProxySetting { enabled } + FIELDS + end + + it 'avoids N+1 queries on the fields marked with lookahead' do + group_ids = groups.map(&:id) + + allow_next(resolver).to receive(:resolve_groups).and_return(Group.id_in(group_ids)) + # Prevent authorization queries from affecting the test. + allow(Ability).to receive(:allowed?).and_return(true) + + single_group_query = ActiveRecord::QueryRecorder.new do + data = query_groups(limit: 1) + expect(data.size).to eq(1) + end + + multi_group_query = -> { + data = query_groups(limit: 2) + expect(data.size).to eq(2) + } + + expect { multi_group_query.call }.not_to exceed_query_limit(single_group_query) + end + + def query_groups(limit:) + query_string = "{ groups(first: #{limit}) { nodes { id #{lookahead_fields} } } }" + + data = execute_query(query_type, graphql: query_string) + + graphql_dig_at(data, :data, :groups, :nodes) + end +end diff --git a/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb b/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb index 865e892b12d..3fcfa967452 100644 --- a/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb +++ b/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb @@ -20,23 +20,37 @@ RSpec.describe ResolvesPipelines do let_it_be(:project) { create(:project, :private) } let_it_be(:pipeline) { create(:ci_pipeline, project: project) } let_it_be(:failed_pipeline) { create(:ci_pipeline, :failed, project: project) } + let_it_be(:success_pipeline) { create(:ci_pipeline, :success, project: project) } let_it_be(:ref_pipeline) { create(:ci_pipeline, project: project, ref: 'awesome-feature') } let_it_be(:sha_pipeline) { create(:ci_pipeline, project: project, sha: 'deadbeef') } + let_it_be(:all_pipelines) do + [ + pipeline, + failed_pipeline, + success_pipeline, + ref_pipeline, + sha_pipeline + ] + end before do project.add_developer(current_user) end - it { is_expected.to have_graphql_arguments(:status, :ref, :sha, :source) } + it { is_expected.to have_graphql_arguments(:status, :scope, :ref, :sha, :source) } it 'finds all pipelines' do - expect(resolve_pipelines).to contain_exactly(pipeline, failed_pipeline, ref_pipeline, sha_pipeline) + expect(resolve_pipelines).to contain_exactly(*all_pipelines) end it 'allows filtering by status' do expect(resolve_pipelines(status: 'failed')).to contain_exactly(failed_pipeline) end + it 'allows filtering by scope' do + expect(resolve_pipelines(scope: 'finished')).to contain_exactly(failed_pipeline, success_pipeline) + end + it 'allows filtering by ref' do expect(resolve_pipelines(ref: 'awesome-feature')).to contain_exactly(ref_pipeline) end @@ -54,7 +68,7 @@ RSpec.describe ResolvesPipelines do end it 'does not filter by source' do - expect(resolve_pipelines(source: 'web')).to contain_exactly(pipeline, failed_pipeline, ref_pipeline, sha_pipeline, source_pipeline) + expect(resolve_pipelines(source: 'web')).to contain_exactly(*all_pipelines, source_pipeline) end end @@ -64,7 +78,7 @@ RSpec.describe ResolvesPipelines do end it 'returns all the pipelines' do - expect(resolve_pipelines).to contain_exactly(pipeline, failed_pipeline, ref_pipeline, sha_pipeline, source_pipeline) + expect(resolve_pipelines).to contain_exactly(*all_pipelines, source_pipeline) end end end diff --git a/spec/graphql/resolvers/group_issues_resolver_spec.rb b/spec/graphql/resolvers/group_issues_resolver_spec.rb index 463cdca699b..e17429560ac 100644 --- a/spec/graphql/resolvers/group_issues_resolver_spec.rb +++ b/spec/graphql/resolvers/group_issues_resolver_spec.rb @@ -29,15 +29,72 @@ RSpec.describe Resolvers::GroupIssuesResolver do describe '#resolve' do it 'finds all group issues' do - result = resolve(described_class, obj: group, ctx: { current_user: current_user }) - - expect(result).to contain_exactly(issue1, issue2, issue3) + expect(resolve_issues).to contain_exactly(issue1, issue2, issue3) end it 'finds all group and subgroup issues' do - result = resolve(described_class, obj: group, args: { include_subgroups: true }, ctx: { current_user: current_user }) + result = resolve_issues(include_subgroups: true) expect(result).to contain_exactly(issue1, issue2, issue3, subissue1, subissue2, subissue3) end + + it 'returns issues without the specified issue_type' do + result = resolve_issues(not: { types: ['issue'] }) + + expect(result).to contain_exactly(issue1) + end + + context 'confidential issues' do + let_it_be(:confidential_issue1) { create(:issue, project: project, confidential: true) } + let_it_be(:confidential_issue2) { create(:issue, project: other_project, confidential: true) } + + context "when user is allowed to view confidential issues" do + it 'returns all viewable issues by default' do + expect(resolve_issues).to contain_exactly(issue1, issue2, issue3, confidential_issue1, confidential_issue2) + end + + context 'filtering for confidential issues' do + it 'returns only the non-confidential issues for the group when filter is set to false' do + expect(resolve_issues({ confidential: false })).to contain_exactly(issue1, issue2, issue3) + end + + it "returns only the confidential issues for the group when filter is set to true" do + expect(resolve_issues({ confidential: true })).to contain_exactly(confidential_issue1, confidential_issue2) + end + end + end + + context "when user is not allowed to see confidential issues" do + before do + group.add_guest(current_user) + end + + it 'returns all viewable issues by default' do + expect(resolve_issues).to contain_exactly(issue1, issue2, issue3) + end + + context 'filtering for confidential issues' do + it 'does not return the confidential issues when filter is set to false' do + expect(resolve_issues({ confidential: false })).to contain_exactly(issue1, issue2, issue3) + end + + it 'does not return the confidential issues when filter is set to true' do + expect(resolve_issues({ confidential: true })).to be_empty + end + end + end + end + + context 'release_tag filter' do + it 'returns an error when trying to filter by negated release_tag' do + expect do + resolve_issues(not: { release_tag: ['v1.0'] }) + end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'releaseTag filter is not allowed when parent is a group.') + end + end + end + + def resolve_issues(args = {}, context = { current_user: current_user }) + resolve(described_class, obj: group, args: args, ctx: context) end end diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb index 9897e697009..3c892214aaf 100644 --- a/spec/graphql/resolvers/issues_resolver_spec.rb +++ b/spec/graphql/resolvers/issues_resolver_spec.rb @@ -26,14 +26,7 @@ RSpec.describe Resolvers::IssuesResolver do expect(described_class).to have_nullable_graphql_type(Types::IssueType.connection_type) end - shared_context 'filtering for confidential issues' do - let_it_be(:confidential_issue1) { create(:issue, project: project, confidential: true) } - let_it_be(:confidential_issue2) { create(:issue, project: other_project, confidential: true) } - end - context "with a project" do - let(:obj) { project } - before_all do project.add_developer(current_user) project.add_reporter(reporter) @@ -112,6 +105,54 @@ RSpec.describe Resolvers::IssuesResolver do end end + describe 'filter by release' do + let_it_be(:milestone1) { create(:milestone, project: project, start_date: 1.day.from_now, title: 'Version 1') } + let_it_be(:milestone2) { create(:milestone, project: project, start_date: 1.day.from_now, title: 'Version 2') } + let_it_be(:milestone3) { create(:milestone, project: project, start_date: 1.day.from_now, title: 'Version 3') } + let_it_be(:release1) { create(:release, tag: 'v1.0', milestones: [milestone1], project: project) } + let_it_be(:release2) { create(:release, tag: 'v2.0', milestones: [milestone2], project: project) } + let_it_be(:release3) { create(:release, tag: 'v3.0', milestones: [milestone3], project: project) } + let_it_be(:release_issue1) { create(:issue, project: project, milestone: milestone1) } + let_it_be(:release_issue2) { create(:issue, project: project, milestone: milestone2) } + let_it_be(:release_issue3) { create(:issue, project: project, milestone: milestone3) } + + describe 'filter by release_tag' do + it 'returns all issues associated with the specified tags' do + expect(resolve_issues(release_tag: [release1.tag, release3.tag])).to contain_exactly(release_issue1, release_issue3) + end + + context 'when release_tag_wildcard_id is also provided' do + it 'raises a mutually eclusive argument error' do + expect do + resolve_issues(release_tag: [release1.tag], release_tag_wildcard_id: 'ANY') + end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'only one of [releaseTag, releaseTagWildcardId] arguments is allowed at the same time.') + end + end + end + + describe 'filter by negated release_tag' do + it 'returns all issues not associated with the specified tags' do + expect(resolve_issues(not: { release_tag: [release1.tag, release3.tag] })).to contain_exactly(release_issue2) + end + end + + describe 'filter by release_tag_wildcard_id' do + subject { resolve_issues(release_tag_wildcard_id: wildcard_id) } + + context 'when filtering by ANY' do + let(:wildcard_id) { 'ANY' } + + it { is_expected.to contain_exactly(release_issue1, release_issue2, release_issue3) } + end + + context 'when filtering by NONE' do + let(:wildcard_id) { 'NONE' } + + it { is_expected.to contain_exactly(issue1, issue2) } + end + end + end + it 'filters by two assignees' do assignee2 = create(:user) issue2.update!(assignees: [assignee, assignee2]) @@ -230,7 +271,8 @@ RSpec.describe Resolvers::IssuesResolver do end context 'confidential issues' do - include_context 'filtering for confidential issues' + let_it_be(:confidential_issue1) { create(:issue, project: project, confidential: true) } + let_it_be(:confidential_issue2) { create(:issue, project: other_project, confidential: true) } context "when user is allowed to view confidential issues" do it 'returns all viewable issues by default' do @@ -561,64 +603,6 @@ RSpec.describe Resolvers::IssuesResolver do end end - context "with a group" do - let(:obj) { group } - - before do - group.add_developer(current_user) - end - - describe '#resolve' do - it 'finds all group issues' do - expect(resolve_issues).to contain_exactly(issue1, issue2, issue3) - end - - it 'returns issues without the specified issue_type' do - expect(resolve_issues({ not: { types: ['issue'] } })).to contain_exactly(issue1) - end - - context "confidential issues" do - include_context 'filtering for confidential issues' - - context "when user is allowed to view confidential issues" do - it 'returns all viewable issues by default' do - expect(resolve_issues).to contain_exactly(issue1, issue2, issue3, confidential_issue1, confidential_issue2) - end - - context 'filtering for confidential issues' do - it 'returns only the non-confidential issues for the group when filter is set to false' do - expect(resolve_issues({ confidential: false })).to contain_exactly(issue1, issue2, issue3) - end - - it "returns only the confidential issues for the group when filter is set to true" do - expect(resolve_issues({ confidential: true })).to contain_exactly(confidential_issue1, confidential_issue2) - end - end - end - - context "when user is not allowed to see confidential issues" do - before do - group.add_guest(current_user) - end - - it 'returns all viewable issues by default' do - expect(resolve_issues).to contain_exactly(issue1, issue2, issue3) - end - - context 'filtering for confidential issues' do - it 'does not return the confidential issues when filter is set to false' do - expect(resolve_issues({ confidential: false })).to contain_exactly(issue1, issue2, issue3) - end - - it 'does not return the confidential issues when filter is set to true' do - expect(resolve_issues({ confidential: true })).to be_empty - end - end - end - end - end - end - context "when passing a non existent, batch loaded project" do let!(:project) do BatchLoader::GraphQL.for("non-existent-path").batch do |_fake_paths, loader, _| @@ -626,8 +610,6 @@ RSpec.describe Resolvers::IssuesResolver do end end - let(:obj) { project } - it "returns nil without breaking" do expect(resolve_issues(iids: ["don't", "break"])).to be_empty end @@ -648,6 +630,6 @@ RSpec.describe Resolvers::IssuesResolver do end def resolve_issues(args = {}, context = { current_user: current_user }) - resolve(described_class, obj: obj, args: args, ctx: context) + resolve(described_class, obj: project, args: args, ctx: context) end end diff --git a/spec/graphql/resolvers/merge_requests_resolver_spec.rb b/spec/graphql/resolvers/merge_requests_resolver_spec.rb index a897acf7eba..a931b0a3f77 100644 --- a/spec/graphql/resolvers/merge_requests_resolver_spec.rb +++ b/spec/graphql/resolvers/merge_requests_resolver_spec.rb @@ -218,6 +218,54 @@ RSpec.describe Resolvers::MergeRequestsResolver do end end + context 'with created_after and created_before arguments' do + before do + merge_request_1.update!(created_at: 4.days.ago) + end + + let(:all_mrs) do + [merge_request_1, merge_request_2, merge_request_3, merge_request_4, merge_request_5, merge_request_6, merge_request_with_milestone] + end + + it 'returns merge requests created within a given period' do + result = resolve_mr(project, created_after: 5.days.ago, created_before: 2.days.ago) + + expect(result).to contain_exactly( + merge_request_1 + ) + end + + it 'returns some values filtered with created_before' do + result = resolve_mr(project, created_before: 1.day.ago) + + expect(result).to contain_exactly(merge_request_1) + end + + it 'returns some values filtered with created_after' do + result = resolve_mr(project, created_after: 3.days.ago) + + expect(result).to match_array(all_mrs - [merge_request_1]) + end + + it 'does not return anything for dates (even in the future) not matching any MRs' do + result = resolve_mr(project, created_after: 5.days.from_now) + + expect(result).to be_empty + end + + it 'does not return anything for dates not matching any MRs' do + result = resolve_mr(project, created_before: 15.days.ago) + + expect(result).to be_empty + end + + it 'does not return any values for an impossible set' do + result = resolve_mr(project, created_after: 5.days.ago, created_before: 6.days.ago) + + expect(result).to be_empty + end + end + context 'with milestone argument' do it 'filters merge requests by milestone title' do result = resolve_mr(project, milestone_title: milestone.title) diff --git a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb index 75b9be7dfe7..c6d8c518fb7 100644 --- a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb +++ b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb @@ -90,7 +90,10 @@ RSpec.describe Resolvers::Projects::JiraProjectsResolver do end it 'raises failure error' do - expect { resolve_jira_projects }.to raise_error('An error occurred while requesting data from Jira: Some failure. Check your Jira integration configuration and try again.') + config_docs_link_url = Rails.application.routes.url_helpers.help_page_path('integration/jira/configure') + docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: config_docs_link_url } + error_message = 'An error occurred while requesting data from Jira: Some failure. Check your %{docs_link_start}Jira integration configuration</a> and try again.' % { docs_link_start: docs_link_start } + expect { resolve_jira_projects }.to raise_error(error_message) end end end diff --git a/spec/graphql/resolvers/timelog_resolver_spec.rb b/spec/graphql/resolvers/timelog_resolver_spec.rb index f45f528fe7e..9b3f555071e 100644 --- a/spec/graphql/resolvers/timelog_resolver_spec.rb +++ b/spec/graphql/resolvers/timelog_resolver_spec.rb @@ -11,6 +11,8 @@ RSpec.describe Resolvers::TimelogResolver do let_it_be(:issue) { create(:issue, project: project) } let_it_be(:error_class) { Gitlab::Graphql::Errors::ArgumentError } + let(:timelogs) { resolve_timelogs(**args) } + specify do expect(described_class).to have_non_null_graphql_type(::Types::TimelogType.connection_type) end @@ -24,8 +26,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_time: 6.days.ago, end_time: 2.days.ago.noon } } it 'finds all timelogs within given dates' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog1) end @@ -33,8 +33,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { {} } it 'finds all timelogs' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog1, timelog2, timelog3) end end @@ -43,8 +41,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_time: 2.days.ago.noon } } it 'finds timelogs after the start_time' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog2) end end @@ -53,8 +49,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { end_time: 2.days.ago.noon } } it 'finds timelogs before the end_time' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog1, timelog3) end end @@ -63,8 +57,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_time: 6.days.ago, end_date: 2.days.ago } } it 'finds timelogs until the end of day of end_date' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog1, timelog2) end end @@ -73,8 +65,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_date: 6.days.ago, end_time: 2.days.ago.noon } } it 'finds all timelogs within start_date and end_time' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog1) end end @@ -96,7 +86,7 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_time: 6.days.ago, start_date: 6.days.ago } } it 'returns correct error' do - expect { resolve_timelogs(**args) } + expect { timelogs } .to raise_error(error_class, /Provide either a start date or time, but not both/) end end @@ -105,7 +95,7 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { end_time: 2.days.ago, end_date: 2.days.ago } } it 'returns correct error' do - expect { resolve_timelogs(**args) } + expect { timelogs } .to raise_error(error_class, /Provide either an end date or time, but not both/) end end @@ -114,14 +104,14 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_time: 2.days.ago, end_time: 6.days.ago } } it 'returns correct error' do - expect { resolve_timelogs(**args) } + expect { timelogs } .to raise_error(error_class, /Start argument must be before End argument/) end end end end - shared_examples "with a group" do + shared_examples 'with a group' do let_it_be(:short_time_ago) { 5.days.ago.beginning_of_day } let_it_be(:medium_time_ago) { 15.days.ago.beginning_of_day } @@ -141,8 +131,6 @@ RSpec.describe Resolvers::TimelogResolver do end it 'finds all timelogs within given dates' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog1) end @@ -150,8 +138,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_date: short_time_ago } } it 'finds timelogs until the end of day of end_date' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog1, timelog2) end end @@ -160,8 +146,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { end_date: medium_time_ago } } it 'finds timelogs until the end of day of end_date' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog3) end end @@ -170,8 +154,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_time: short_time_ago, end_date: short_time_ago } } it 'finds timelogs until the end of day of end_date' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog1, timelog2) end end @@ -180,8 +162,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_date: short_time_ago, end_time: short_time_ago.noon } } it 'finds all timelogs within start_date and end_time' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog1) end end @@ -191,7 +171,7 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_time: short_time_ago, start_date: short_time_ago } } it 'returns correct error' do - expect { resolve_timelogs(**args) } + expect { timelogs } .to raise_error(error_class, /Provide either a start date or time, but not both/) end end @@ -200,7 +180,7 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { end_time: short_time_ago, end_date: short_time_ago } } it 'returns correct error' do - expect { resolve_timelogs(**args) } + expect { timelogs } .to raise_error(error_class, /Provide either an end date or time, but not both/) end end @@ -209,14 +189,14 @@ RSpec.describe Resolvers::TimelogResolver do let(:args) { { start_time: short_time_ago, end_time: medium_time_ago } } it 'returns correct error' do - expect { resolve_timelogs(**args) } + expect { timelogs } .to raise_error(error_class, /Start argument must be before End argument/) end end end end - shared_examples "with a user" do + shared_examples 'with a user' do let_it_be(:short_time_ago) { 5.days.ago.beginning_of_day } let_it_be(:medium_time_ago) { 15.days.ago.beginning_of_day } @@ -228,20 +208,18 @@ RSpec.describe Resolvers::TimelogResolver do let_it_be(:timelog3) { create(:merge_request_timelog, merge_request: merge_request, user: current_user) } it 'blah' do - timelogs = resolve_timelogs(**args) - expect(timelogs).to contain_exactly(timelog1, timelog3) end end - context "on a project" do + context 'on a project' do let(:object) { project } let(:extra_args) { {} } it_behaves_like 'with a project' end - context "with a project filter" do + context 'with a project filter' do let(:object) { nil } let(:extra_args) { { project_id: project.to_global_id } } @@ -285,8 +263,6 @@ RSpec.describe Resolvers::TimelogResolver do let(:extra_args) { {} } it 'pagination returns `default_max_page_size` and sets `has_next_page` true' do - timelogs = resolve_timelogs(**args) - expect(timelogs.items.count).to be(100) expect(timelogs.has_next_page).to be(true) end @@ -298,7 +274,7 @@ RSpec.describe Resolvers::TimelogResolver do let(:extra_args) { {} } it 'returns correct error' do - expect { resolve_timelogs(**args) } + expect { timelogs } .to raise_error(error_class, /Provide at least one argument/) end end diff --git a/spec/graphql/resolvers/topics_resolver_spec.rb b/spec/graphql/resolvers/topics_resolver_spec.rb new file mode 100644 index 00000000000..3ff1dabc927 --- /dev/null +++ b/spec/graphql/resolvers/topics_resolver_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::TopicsResolver do + include GraphqlHelpers + + describe '#resolve' do + let!(:topic1) { create(:topic, name: 'GitLab', total_projects_count: 1) } + let!(:topic2) { create(:topic, name: 'git', total_projects_count: 2) } + let!(:topic3) { create(:topic, name: 'topic3', total_projects_count: 3) } + + it 'finds all topics' do + expect(resolve_topics).to eq([topic3, topic2, topic1]) + end + + context 'with search' do + it 'searches environment by name' do + expect(resolve_topics(search: 'git')).to eq([topic2, topic1]) + end + + context 'when the search term does not match any topic' do + it 'is empty' do + expect(resolve_topics(search: 'nonsense')).to be_empty + end + end + end + end + + def resolve_topics(args = {}) + resolve(described_class, args: args) + end +end |