summaryrefslogtreecommitdiff
path: root/spec/graphql/resolvers
diff options
context:
space:
mode:
Diffstat (limited to 'spec/graphql/resolvers')
-rw-r--r--spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb22
-rw-r--r--spec/graphql/resolvers/alert_management/integrations_resolver_spec.rb38
-rw-r--r--spec/graphql/resolvers/base_resolver_spec.rb184
-rw-r--r--spec/graphql/resolvers/ci/jobs_resolver_spec.rb40
-rw-r--r--spec/graphql/resolvers/ci/runner_setup_resolver_spec.rb104
-rw-r--r--spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb208
-rw-r--r--spec/graphql/resolvers/container_repositories_resolver_spec.rb58
-rw-r--r--spec/graphql/resolvers/design_management/design_resolver_spec.rb15
-rw-r--r--spec/graphql/resolvers/design_management/designs_resolver_spec.rb24
-rw-r--r--spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb7
-rw-r--r--spec/graphql/resolvers/echo_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb8
-rw-r--r--spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/group_members_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb1
-rw-r--r--spec/graphql/resolvers/merge_requests_resolver_spec.rb8
-rw-r--r--spec/graphql/resolvers/metadata_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/project_pipeline_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/projects/services_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/projects/snippets_resolver_spec.rb6
-rw-r--r--spec/graphql/resolvers/projects_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/release_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/releases_resolver_spec.rb49
-rw-r--r--spec/graphql/resolvers/snippets/blobs_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/snippets_resolver_spec.rb10
-rw-r--r--spec/graphql/resolvers/todo_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/tree_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/users/group_count_resolver_spec.rb62
-rw-r--r--spec/graphql/resolvers/users/snippets_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/users_resolver_spec.rb16
34 files changed, 856 insertions, 62 deletions
diff --git a/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb b/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb
index c5637d43382..578d679ade4 100644
--- a/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb
+++ b/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb
@@ -14,7 +14,9 @@ RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsReso
let_it_be(:project_measurement_new) { create(:instance_statistics_measurement, :project_count, recorded_at: 2.days.ago) }
let_it_be(:project_measurement_old) { create(:instance_statistics_measurement, :project_count, recorded_at: 10.days.ago) }
- subject { resolve_measurements({ identifier: 'projects' }, { current_user: current_user }) }
+ let(:arguments) { { identifier: 'projects' } }
+
+ subject { resolve_measurements(arguments, { current_user: current_user }) }
context 'when requesting project count measurements' do
context 'as an admin user' do
@@ -40,6 +42,24 @@ RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsReso
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
+
+ context 'when filtering by recorded_after and recorded_before' do
+ before do
+ arguments[:recorded_after] = 4.days.ago
+ arguments[:recorded_before] = 1.day.ago
+ end
+
+ it { is_expected.to match_array([project_measurement_new]) }
+
+ context 'when "incorrect" values are passed' do
+ before do
+ arguments[:recorded_after] = 1.day.ago
+ arguments[:recorded_before] = 4.days.ago
+ end
+
+ it { is_expected.to be_empty }
+ end
+ end
end
context 'when requesting pipeline counts by pipeline status' do
diff --git a/spec/graphql/resolvers/alert_management/integrations_resolver_spec.rb b/spec/graphql/resolvers/alert_management/integrations_resolver_spec.rb
new file mode 100644
index 00000000000..36e409e0677
--- /dev/null
+++ b/spec/graphql/resolvers/alert_management/integrations_resolver_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::AlertManagement::IntegrationsResolver do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:prometheus_integration) { create(:prometheus_service, project: project) }
+ let_it_be(:active_http_integration) { create(:alert_management_http_integration, project: project) }
+ let_it_be(:inactive_http_integration) { create(:alert_management_http_integration, :inactive, project: project) }
+ let_it_be(:other_proj_integration) { create(:alert_management_http_integration) }
+
+ subject { sync(resolve_http_integrations) }
+
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::AlertManagement::IntegrationType.connection_type)
+ end
+
+ context 'user does not have permission' do
+ it { is_expected.to be_empty }
+ end
+
+ context 'user has permission' do
+ before do
+ project.add_maintainer(current_user)
+ end
+
+ it { is_expected.to contain_exactly(active_http_integration, prometheus_integration) }
+ end
+
+ private
+
+ def resolve_http_integrations(args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: project, ctx: context)
+ end
+end
diff --git a/spec/graphql/resolvers/base_resolver_spec.rb b/spec/graphql/resolvers/base_resolver_spec.rb
index 40dc2370052..e5b9fb57e42 100644
--- a/spec/graphql/resolvers/base_resolver_spec.rb
+++ b/spec/graphql/resolvers/base_resolver_spec.rb
@@ -7,10 +7,13 @@ RSpec.describe Resolvers::BaseResolver do
let(:resolver) do
Class.new(described_class) do
- def resolve(**args)
+ argument :test, ::GraphQL::INT_TYPE, required: false
+ type [::GraphQL::INT_TYPE], null: true
+
+ def resolve(test: 100)
process(object)
- [args, args]
+ [test, test]
end
def process(obj); end
@@ -19,17 +22,75 @@ RSpec.describe Resolvers::BaseResolver do
let(:last_resolver) do
Class.new(described_class) do
+ type [::GraphQL::INT_TYPE], null: true
+
def resolve(**args)
[1, 2]
end
end
end
+ describe '.singular_type' do
+ subject { resolver.singular_type }
+
+ context 'for a connection of scalars' do
+ let(:resolver) do
+ Class.new(described_class) do
+ type ::GraphQL::INT_TYPE.connection_type, null: true
+ end
+ end
+
+ it { is_expected.to eq(::GraphQL::INT_TYPE) }
+ end
+
+ context 'for a connection of objects' do
+ let(:object) do
+ Class.new(::Types::BaseObject) do
+ graphql_name 'Foo'
+ end
+ end
+
+ let(:resolver) do
+ conn = object.connection_type
+
+ Class.new(described_class) do
+ type conn, null: true
+ end
+ end
+
+ it { is_expected.to eq(object) }
+ end
+
+ context 'for a list type' do
+ let(:resolver) do
+ Class.new(described_class) do
+ type [::GraphQL::STRING_TYPE], null: true
+ end
+ end
+
+ it { is_expected.to eq(::GraphQL::STRING_TYPE) }
+ end
+
+ context 'for a scalar type' do
+ let(:resolver) do
+ Class.new(described_class) do
+ type ::GraphQL::BOOLEAN_TYPE, null: true
+ end
+ end
+
+ it { is_expected.to eq(::GraphQL::BOOLEAN_TYPE) }
+ end
+ end
+
describe '.single' do
it 'returns a subclass from the resolver' do
expect(resolver.single.superclass).to eq(resolver)
end
+ it 'has the correct (singular) type' do
+ expect(resolver.single.type).to eq(::GraphQL::INT_TYPE)
+ end
+
it 'returns the same subclass every time' do
expect(resolver.single.object_id).to eq(resolver.single.object_id)
end
@@ -37,15 +98,106 @@ RSpec.describe Resolvers::BaseResolver do
it 'returns a resolver that gives the first result from the original resolver' do
result = resolve(resolver.single, args: { test: 1 })
- expect(result).to eq(test: 1)
+ expect(result).to eq(1)
+ end
+ end
+
+ describe '.when_single' do
+ let(:resolver) do
+ Class.new(described_class) do
+ type [::GraphQL::INT_TYPE], null: true
+
+ when_single do
+ argument :foo, ::GraphQL::INT_TYPE, required: true
+ end
+
+ def resolve(foo: 1)
+ [foo * foo] # rubocop: disable Lint/BinaryOperatorWithIdenticalOperands
+ end
+ end
+ end
+
+ it 'does not apply the block to the resolver' do
+ expect(resolver.field_options).to include(
+ arguments: be_empty
+ )
+ result = resolve(resolver)
+
+ expect(result).to eq([1])
+ end
+
+ it 'applies the block to the single version of the resolver' do
+ expect(resolver.single.field_options).to include(
+ arguments: match('foo' => an_instance_of(::Types::BaseArgument))
+ )
+ result = resolve(resolver.single, args: { foo: 7 })
+
+ expect(result).to eq(49)
+ end
+
+ context 'multiple when_single blocks' do
+ let(:resolver) do
+ Class.new(described_class) do
+ type [::GraphQL::INT_TYPE], null: true
+
+ when_single do
+ argument :foo, ::GraphQL::INT_TYPE, required: true
+ end
+
+ when_single do
+ argument :bar, ::GraphQL::INT_TYPE, required: true
+ end
+
+ def resolve(foo: 1, bar: 2)
+ [foo * bar]
+ end
+ end
+ end
+
+ it 'applies both blocks to the single version of the resolver' do
+ expect(resolver.single.field_options).to include(
+ arguments: match('foo' => ::Types::BaseArgument, 'bar' => ::Types::BaseArgument)
+ )
+ result = resolve(resolver.single, args: { foo: 7, bar: 5 })
+
+ expect(result).to eq(35)
+ end
+ end
+
+ context 'inheritance' do
+ let(:subclass) do
+ Class.new(resolver) do
+ when_single do
+ argument :inc, ::GraphQL::INT_TYPE, required: true
+ end
+
+ def resolve(foo:, inc:)
+ super(foo: foo + inc)
+ end
+ end
+ end
+
+ it 'applies both blocks to the single version of the resolver' do
+ expect(resolver.single.field_options).to include(
+ arguments: match('foo' => ::Types::BaseArgument)
+ )
+ expect(subclass.single.field_options).to include(
+ arguments: match('foo' => ::Types::BaseArgument, 'inc' => ::Types::BaseArgument)
+ )
+ result = resolve(subclass.single, args: { foo: 7, inc: 1 })
+
+ expect(result).to eq(64)
+ end
end
end
context 'when the resolver returns early' do
let(:resolver) do
Class.new(described_class) do
+ type [::GraphQL::STRING_TYPE], null: true
+
def ready?(**args)
- [false, %w(early return)]
+ [false, %w[early return]]
end
def resolve(**args)
@@ -121,28 +273,4 @@ RSpec.describe Resolvers::BaseResolver do
end
end
end
-
- describe '#synchronized_object' do
- let(:object) { double(foo: :the_foo) }
-
- let(:resolver) do
- Class.new(described_class) do
- def resolve(**args)
- [synchronized_object.foo]
- end
- end
- end
-
- it 'handles raw objects' do
- expect(resolve(resolver, obj: object)).to contain_exactly(:the_foo)
- end
-
- it 'handles lazy objects' do
- delayed = BatchLoader::GraphQL.for(1).batch do |_, loader|
- loader.call(1, object)
- end
-
- expect(resolve(resolver, obj: delayed)).to contain_exactly(:the_foo)
- end
- end
end
diff --git a/spec/graphql/resolvers/ci/jobs_resolver_spec.rb b/spec/graphql/resolvers/ci/jobs_resolver_spec.rb
new file mode 100644
index 00000000000..a836c89bd61
--- /dev/null
+++ b/spec/graphql/resolvers/ci/jobs_resolver_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Ci::JobsResolver do
+ include GraphqlHelpers
+
+ let_it_be(:pipeline) { create(:ci_pipeline) }
+
+ before_all do
+ create(:ci_build, name: 'Normal job', pipeline: pipeline)
+ create(:ci_build, :sast, name: 'DAST job', pipeline: pipeline)
+ create(:ci_build, :dast, name: 'SAST job', pipeline: pipeline)
+ create(:ci_build, :container_scanning, name: 'Container scanning job', pipeline: pipeline)
+ end
+
+ describe '#resolve' do
+ context 'when security_report_types is empty' do
+ it "returns all of the pipeline's jobs" do
+ jobs = resolve(described_class, obj: pipeline, args: {}, ctx: {})
+
+ job_names = jobs.map(&:name)
+ expect(job_names).to contain_exactly('Normal job', 'DAST job', 'SAST job', 'Container scanning job')
+ end
+ end
+
+ context 'when security_report_types is present' do
+ it "returns the pipeline's jobs with the given security report types" do
+ report_types = [
+ ::Types::Security::ReportTypeEnum.values['SAST'].value,
+ ::Types::Security::ReportTypeEnum.values['DAST'].value
+ ]
+ jobs = resolve(described_class, obj: pipeline, args: { security_report_types: report_types }, ctx: {})
+
+ job_names = jobs.map(&:name)
+ expect(job_names).to contain_exactly('DAST job', 'SAST job')
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/ci/runner_setup_resolver_spec.rb b/spec/graphql/resolvers/ci/runner_setup_resolver_spec.rb
new file mode 100644
index 00000000000..3d004290d9b
--- /dev/null
+++ b/spec/graphql/resolvers/ci/runner_setup_resolver_spec.rb
@@ -0,0 +1,104 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Ci::RunnerSetupResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let(:user) { create(:user) }
+
+ subject(:resolve_subject) { resolve(described_class, ctx: { current_user: user }, args: { platform: platform, architecture: 'amd64' }.merge(target_param)) }
+
+ context 'with container platforms' do
+ let(:platform) { 'docker' }
+ let(:project) { create(:project) }
+ let(:target_param) { { project_id: project.to_global_id } }
+
+ it 'returns install instructions' do
+ expect(resolve_subject[:install_instructions]).not_to eq(nil)
+ end
+
+ it 'does not return register instructions' do
+ expect(resolve_subject[:register_instructions]).to eq(nil)
+ end
+ end
+
+ context 'with regular platforms' do
+ let(:platform) { 'linux' }
+
+ context 'without target parameter' do
+ let(:target_param) { {} }
+
+ context 'when user is not admin' do
+ it 'returns access error' do
+ expect { resolve_subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when user is admin' do
+ before do
+ user.update!(admin: true)
+ end
+
+ it 'returns install and register instructions' do
+ expect(resolve_subject.keys).to contain_exactly(:install_instructions, :register_instructions)
+ expect(resolve_subject.values).not_to include(nil)
+ end
+ end
+ end
+
+ context 'with project target parameter' do
+ let(:project) { create(:project) }
+ let(:target_param) { { project_id: project.to_global_id } }
+
+ context 'when user has access to admin builds on project' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'returns install and register instructions' do
+ expect(resolve_subject.keys).to contain_exactly(:install_instructions, :register_instructions)
+ expect(resolve_subject.values).not_to include(nil)
+ end
+ end
+
+ context 'when user does not have access to admin builds on project' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns access error' do
+ expect { resolve_subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+
+ context 'with group target parameter' do
+ let(:group) { create(:group) }
+ let(:target_param) { { group_id: group.to_global_id } }
+
+ context 'when user has access to admin builds on group' do
+ before do
+ group.add_owner(user)
+ end
+
+ it 'returns install and register instructions' do
+ expect(resolve_subject.keys).to contain_exactly(:install_instructions, :register_instructions)
+ expect(resolve_subject.values).not_to include(nil)
+ end
+ end
+
+ context 'when user does not have access to admin builds on group' do
+ before do
+ group.add_developer(user)
+ end
+
+ it 'returns access error' do
+ expect { resolve_subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb b/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb
new file mode 100644
index 00000000000..b6fe94a2312
--- /dev/null
+++ b/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb
@@ -0,0 +1,208 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::CachingArrayResolver do
+ include GraphqlHelpers
+
+ let_it_be(:non_admins) { create_list(:user, 4, admin: false) }
+ let(:query_context) { {} }
+ let(:max_page_size) { 10 }
+ let(:field) { double('Field', max_page_size: max_page_size) }
+ let(:schema) { double('Schema', default_max_page_size: 3) }
+
+ let_it_be(:caching_resolver) do
+ mod = described_class
+
+ Class.new(::Resolvers::BaseResolver) do
+ include mod
+
+ def query_input(is_admin:)
+ is_admin
+ end
+
+ def query_for(is_admin)
+ if is_admin.nil?
+ model_class.all
+ else
+ model_class.where(admin: is_admin)
+ end
+ end
+
+ def model_class
+ User # Happens to include FromUnion, and is cheap-ish to create
+ end
+ end
+ end
+
+ describe '#resolve' do
+ context 'there are more than MAX_UNION_SIZE queries' do
+ let_it_be(:max_union) { 3 }
+ let_it_be(:resolver) do
+ mod = described_class
+ max = max_union
+
+ Class.new(::Resolvers::BaseResolver) do
+ include mod
+
+ def query_input(username:)
+ username
+ end
+
+ def query_for(username)
+ if username.nil?
+ model_class.all
+ else
+ model_class.where(username: username)
+ end
+ end
+
+ def model_class
+ User # Happens to include FromUnion, and is cheap-ish to create
+ end
+
+ define_method :max_union_size do
+ max
+ end
+ end
+ end
+
+ it 'executes the queries in multiple batches' do
+ users = create_list(:user, (max_union * 2) + 1)
+ expect(User).to receive(:from_union).twice.and_call_original
+
+ results = users.in_groups_of(2, false).map do |users|
+ resolve(resolver, args: { username: users.map(&:username) }, field: field, schema: schema)
+ end
+
+ expect(results.flat_map(&method(:force))).to match_array(users)
+ end
+ end
+
+ context 'all queries return results' do
+ let_it_be(:admins) { create_list(:admin, 3) }
+
+ it 'batches the queries' do
+ expect do
+ [resolve_users(true), resolve_users(false)].each(&method(:force))
+ end.to issue_same_number_of_queries_as { force(resolve_users(nil)) }
+ end
+
+ it 'finds the correct values' do
+ found_admins = resolve_users(true)
+ found_others = resolve_users(false)
+ admins_again = resolve_users(true)
+ found_all = resolve_users(nil)
+
+ expect(force(found_admins)).to match_array(admins)
+ expect(force(found_others)).to match_array(non_admins)
+ expect(force(admins_again)).to match_array(admins)
+ expect(force(found_all)).to match_array(admins + non_admins)
+ end
+ end
+
+ it 'does not perform a union of a query with itself' do
+ expect(User).to receive(:where).once.and_call_original
+
+ [resolve_users(false), resolve_users(false)].each(&method(:force))
+ end
+
+ context 'one of the queries returns no results' do
+ it 'finds the correct values' do
+ found_admins = resolve_users(true)
+ found_others = resolve_users(false)
+ found_all = resolve_users(nil)
+
+ expect(force(found_admins)).to be_empty
+ expect(force(found_others)).to match_array(non_admins)
+ expect(force(found_all)).to match_array(non_admins)
+ end
+ end
+
+ context 'one of the queries has already been cached' do
+ before do
+ force(resolve_users(nil))
+ end
+
+ it 'avoids further queries' do
+ expect do
+ repeated_find = resolve_users(nil)
+
+ expect(force(repeated_find)).to match_array(non_admins)
+ end.not_to exceed_query_limit(0)
+ end
+ end
+
+ context 'the resolver overrides item_found' do
+ let_it_be(:admins) { create_list(:admin, 2) }
+ let(:query_context) do
+ {
+ found: { true => [], false => [], nil => [] }
+ }
+ end
+
+ let_it_be(:with_item_found) do
+ Class.new(caching_resolver) do
+ def item_found(key, item)
+ context[:found][key] << item
+ end
+ end
+ end
+
+ it 'receives item_found for each key the item mapped to' do
+ found_admins = resolve_users(true, with_item_found)
+ found_all = resolve_users(nil, with_item_found)
+
+ [found_admins, found_all].each(&method(:force))
+
+ expect(query_context[:found]).to match({
+ false => be_empty,
+ true => match_array(admins),
+ nil => match_array(admins + non_admins)
+ })
+ end
+ end
+
+ context 'the max_page_size is lower than the total result size' do
+ let(:max_page_size) { 2 }
+
+ it 'respects the max_page_size, on a per subset basis' do
+ found_all = resolve_users(nil)
+ found_others = resolve_users(false)
+
+ expect(force(found_all).size).to eq(2)
+ expect(force(found_others).size).to eq(2)
+ end
+ end
+
+ context 'the field does not declare max_page_size' do
+ let(:max_page_size) { nil }
+
+ it 'takes the page size from schema.default_max_page_size' do
+ found_all = resolve_users(nil)
+ found_others = resolve_users(false)
+
+ expect(force(found_all).size).to eq(schema.default_max_page_size)
+ expect(force(found_others).size).to eq(schema.default_max_page_size)
+ end
+ end
+
+ specify 'force . resolve === to_a . query_for . query_input' do
+ r = resolver_instance(caching_resolver)
+ args = { is_admin: false }
+
+ naive = r.query_for(r.query_input(**args)).to_a
+
+ expect(force(r.resolve(**args))).to eq(naive)
+ end
+ end
+
+ def resolve_users(is_admin, resolver = caching_resolver)
+ args = { is_admin: is_admin }
+ resolve(resolver, args: args, field: field, ctx: query_context, schema: schema)
+ end
+
+ def force(lazy)
+ ::Gitlab::Graphql::Lazy.force(lazy)
+ end
+end
diff --git a/spec/graphql/resolvers/container_repositories_resolver_spec.rb b/spec/graphql/resolvers/container_repositories_resolver_spec.rb
new file mode 100644
index 00000000000..b888d79626e
--- /dev/null
+++ b/spec/graphql/resolvers/container_repositories_resolver_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::ContainerRepositoriesResolver do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be_with_reload(:project) { create(:project, group: group) }
+ let_it_be(:container_repositories) { create(:container_repository, project: project) }
+
+ let(:args) { {} }
+
+ describe '#resolve' do
+ let(:object) { project }
+
+ subject { resolve(described_class, ctx: { current_user: user }, args: args, obj: object) }
+
+ shared_examples 'returning container repositories' do
+ it { is_expected.to contain_exactly(container_repositories) }
+
+ context 'with a named search' do
+ let_it_be(:named_container_repository) { create(:container_repository, project: project, name: 'Foobar') }
+
+ let(:args) { { name: 'ooba' } }
+
+ it { is_expected.to contain_exactly(named_container_repository) }
+ end
+ end
+
+ context 'with authorized user' do
+ before do
+ group.add_user(user, :maintainer)
+ end
+
+ context 'when the object is a project' do
+ it_behaves_like 'returning container repositories'
+ end
+
+ context 'when the object is a group' do
+ let(:object) { group }
+
+ it_behaves_like 'returning container repositories'
+ end
+
+ context 'when the object is an invalid type' do
+ let(:object) { Object.new }
+
+ it { expect { subject }.to raise_exception('invalid subject_type') }
+ end
+ end
+
+ context 'with unauthorized user' do
+ it { is_expected.to be nil }
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/design_management/design_resolver_spec.rb b/spec/graphql/resolvers/design_management/design_resolver_spec.rb
index 02d7f94612c..e33eaedf167 100644
--- a/spec/graphql/resolvers/design_management/design_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/design_resolver_spec.rb
@@ -6,6 +6,10 @@ RSpec.describe Resolvers::DesignManagement::DesignResolver do
include GraphqlHelpers
include DesignManagementTestHelpers
+ specify do
+ expect(described_class).to have_nullable_graphql_type(::Types::DesignManagement::DesignType)
+ end
+
before do
enable_design_management
end
@@ -57,12 +61,21 @@ RSpec.describe Resolvers::DesignManagement::DesignResolver do
end
context 'the ID belongs to a design on another issue' do
- let(:args) { { id: GitlabSchema.id_from_object(design_on_other_issue).to_s } }
+ let(:args) { { id: global_id_of(design_on_other_issue) } }
it 'returns nothing' do
expect(resolve_design).to be_nil
end
end
+
+ context 'the ID does not belong to a design at all' do
+ let(:args) { { id: global_id_of(issue) } }
+ let(:msg) { /does not represent an instance of DesignManagement::Design/ }
+
+ it 'complains meaningfully' do
+ expect { resolve_design }.to raise_error(msg)
+ end
+ end
end
context 'by filename' do
diff --git a/spec/graphql/resolvers/design_management/designs_resolver_spec.rb b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb
index cfa37d34fd9..28e963c88a9 100644
--- a/spec/graphql/resolvers/design_management/designs_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb
@@ -6,6 +6,10 @@ RSpec.describe Resolvers::DesignManagement::DesignsResolver do
include GraphqlHelpers
include DesignManagementTestHelpers
+ specify do
+ expect(described_class).to have_nullable_graphql_type(::Types::DesignManagement::DesignType.connection_type)
+ end
+
before do
enable_design_management
end
@@ -65,8 +69,24 @@ RSpec.describe Resolvers::DesignManagement::DesignsResolver do
let(:second_version) { create(:design_version) }
let(:second_design) { create(:design, issue: issue, versions: [second_version]) }
+ context 'ids is provided but null' do
+ let(:args) { { ids: nil } }
+
+ it 'behaves as if unfiltered' do
+ expect(resolve_designs).to contain_exactly(first_design, second_design)
+ end
+ end
+
+ context 'ids is provided but empty' do
+ let(:args) { { ids: [] } }
+
+ it 'eliminates all values' do
+ expect(resolve_designs).to be_empty
+ end
+ end
+
context 'the ID is on the current issue' do
- let(:args) { { ids: [GitlabSchema.id_from_object(second_design).to_s] } }
+ let(:args) { { ids: [GitlabSchema.id_from_object(second_design)] } }
it 'resolves to just the relevant design' do
expect(resolve_designs).to contain_exactly(second_design)
@@ -77,7 +97,7 @@ RSpec.describe Resolvers::DesignManagement::DesignsResolver do
let(:third_version) { create(:design_version) }
let(:third_design) { create(:design, issue: create(:issue, project: project), versions: [third_version]) }
- let(:args) { { ids: [GitlabSchema.id_from_object(third_design).to_s] } }
+ let(:args) { { ids: [GitlabSchema.id_from_object(third_design)] } }
it 'ignores it' do
expect(resolve_designs).to be_empty
diff --git a/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb b/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb
index 8ad928e9854..403261fc22a 100644
--- a/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe Resolvers::DesignManagement::VersionInCollectionResolver do
end
context 'we pass an id' do
- let(:params) { { id: global_id_of(first_version) } }
+ let(:params) { { version_id: global_id_of(first_version) } }
it { is_expected.to eq(first_version) }
end
@@ -44,13 +44,14 @@ RSpec.describe Resolvers::DesignManagement::VersionInCollectionResolver do
end
context 'we pass an inconsistent mixture of sha and version id' do
- let(:params) { { sha: first_version.sha, id: global_id_of(create(:design_version)) } }
+ let(:params) { { sha: first_version.sha, version_id: global_id_of(create(:design_version)) } }
it { is_expected.to be_nil }
end
context 'we pass the id of something that is not a design_version' do
- let(:params) { { id: global_id_of(project) } }
+ let(:params) { { version_id: global_id_of(project) } }
+ let(:appropriate_error) { ::GraphQL::CoercionError }
it 'raises an appropriate error' do
expect { result }.to raise_error(appropriate_error)
diff --git a/spec/graphql/resolvers/echo_resolver_spec.rb b/spec/graphql/resolvers/echo_resolver_spec.rb
index 2182ac221f6..4f48e5e0d7a 100644
--- a/spec/graphql/resolvers/echo_resolver_spec.rb
+++ b/spec/graphql/resolvers/echo_resolver_spec.rb
@@ -8,6 +8,10 @@ RSpec.describe Resolvers::EchoResolver do
let(:current_user) { create(:user) }
let(:text) { 'Message test' }
+ specify do
+ expect(described_class).to have_non_null_graphql_type(::GraphQL::STRING_TYPE)
+ end
+
describe '#resolve' do
it 'echoes text and username' do
expect(resolve_echo(text)).to eq %Q("#{current_user.username}" says: #{text})
diff --git a/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb b/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb
index 7e531910184..bf8d2139c82 100644
--- a/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb
+++ b/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb
@@ -10,6 +10,10 @@ RSpec.describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do
let(:issue_details_service) { spy('ErrorTracking::IssueDetailsService') }
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::ErrorTracking::SentryDetailedErrorType)
+ end
+
before do
project.add_developer(current_user)
@@ -61,7 +65,9 @@ RSpec.describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do
context 'blank id' do
let(:args) { { id: '' } }
- it_behaves_like 'it resolves to nil'
+ it 'responds with an error' do
+ expect { resolve_error(args) }.to raise_error(::GraphQL::CoercionError)
+ end
end
end
diff --git a/spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb b/spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb
index 02e0420be2a..20c2bdcd4e1 100644
--- a/spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb
+++ b/spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb
@@ -10,6 +10,10 @@ RSpec.describe Resolvers::ErrorTracking::SentryErrorCollectionResolver do
let(:list_issues_service) { spy('ErrorTracking::ListIssuesService') }
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::ErrorTracking::SentryErrorCollectionType)
+ end
+
before do
project.add_developer(current_user)
diff --git a/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb b/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb
index 554873a6e21..edca11f40d7 100644
--- a/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb
+++ b/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb
@@ -14,6 +14,10 @@ RSpec.describe Resolvers::ErrorTracking::SentryErrorsResolver do
let(:issues) { nil }
let(:pagination) { nil }
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::ErrorTracking::SentryErrorType.connection_type)
+ end
+
describe '#resolve' do
context 'insufficient user permission' do
let(:user) { create(:user) }
diff --git a/spec/graphql/resolvers/group_members_resolver_spec.rb b/spec/graphql/resolvers/group_members_resolver_spec.rb
index bbfea575492..bd0b4870062 100644
--- a/spec/graphql/resolvers/group_members_resolver_spec.rb
+++ b/spec/graphql/resolvers/group_members_resolver_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe Resolvers::GroupMembersResolver do
include GraphqlHelpers
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::GroupMemberType.connection_type)
+ end
+
it_behaves_like 'querying members with a group' do
let_it_be(:resource_member) { create(:group_member, user: user_1, group: group_1) }
let_it_be(:resource) { group_1 }
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index 3a6507f906c..43cbd4d2bdd 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -20,6 +20,10 @@ RSpec.describe Resolvers::IssuesResolver do
let_it_be(:label1) { create(:label, project: project) }
let_it_be(:label2) { create(:label, project: project) }
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::IssueType.connection_type)
+ end
+
context "with a project" do
before do
project.add_developer(current_user)
diff --git a/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb b/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb
index ae3097c1d9e..deb5ff584cf 100644
--- a/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe Resolvers::MergeRequestPipelinesResolver do
sha: merge_request.diff_head_sha
)
end
+
let_it_be(:other_project_pipeline) { create(:ci_pipeline, project: merge_request.source_project, ref: 'other-ref') }
let_it_be(:other_pipeline) { create(:ci_pipeline) }
let(:current_user) { create(:user) }
diff --git a/spec/graphql/resolvers/merge_requests_resolver_spec.rb b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
index aecffc487aa..3a3393a185c 100644
--- a/spec/graphql/resolvers/merge_requests_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
@@ -34,13 +34,13 @@ RSpec.describe Resolvers::MergeRequestsResolver do
context 'no arguments' do
it 'returns all merge requests' do
- result = resolve_mr(project, {})
+ result = resolve_mr(project)
expect(result).to contain_exactly(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 only merge requests that the current user can see' do
- result = resolve_mr(project, {}, user: build(:user))
+ result = resolve_mr(project, user: build(:user))
expect(result).to be_empty
end
@@ -236,10 +236,10 @@ RSpec.describe Resolvers::MergeRequestsResolver do
end
def resolve_mr_single(project, iid)
- resolve_mr(project, { iids: iid }, resolver: described_class.single)
+ resolve_mr(project, resolver: described_class.single, iids: iid)
end
- def resolve_mr(project, args, resolver: described_class, user: current_user)
+ def resolve_mr(project, resolver: described_class, user: current_user, **args)
resolve(resolver, obj: project, args: args, ctx: { current_user: user })
end
end
diff --git a/spec/graphql/resolvers/metadata_resolver_spec.rb b/spec/graphql/resolvers/metadata_resolver_spec.rb
index 20556941de4..f8c01f9d531 100644
--- a/spec/graphql/resolvers/metadata_resolver_spec.rb
+++ b/spec/graphql/resolvers/metadata_resolver_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Resolvers::MetadataResolver do
describe '#resolve' do
it 'returns version and revision' do
- expect(resolve(described_class)).to eq(version: Gitlab::VERSION, revision: Gitlab.revision)
+ expect(resolve(described_class)).to have_attributes(version: Gitlab::VERSION, revision: Gitlab.revision)
end
end
end
diff --git a/spec/graphql/resolvers/project_pipeline_resolver_spec.rb b/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
index a6a86c49373..1950c2ca067 100644
--- a/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
@@ -10,6 +10,10 @@ RSpec.describe Resolvers::ProjectPipelineResolver do
let_it_be(:other_pipeline) { create(:ci_pipeline) }
let(:current_user) { create(:user) }
+ specify do
+ expect(described_class).to have_nullable_graphql_type(::Types::Ci::PipelineType)
+ end
+
def resolve_pipeline(project, args)
resolve(described_class, obj: project, args: args, ctx: { current_user: current_user })
end
diff --git a/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb
index 0775c1c31d1..ad59cb6b95e 100644
--- a/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe Resolvers::Projects::JiraImportsResolver do
include GraphqlHelpers
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::JiraImportType.connection_type)
+ end
+
describe '#resolve' do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :public) }
diff --git a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
index 840aea8b8c4..c375345250d 100644
--- a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe Resolvers::Projects::JiraProjectsResolver do
include GraphqlHelpers
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::Projects::Services::JiraProjectType.connection_type)
+ end
+
describe '#resolve' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/graphql/resolvers/projects/services_resolver_spec.rb b/spec/graphql/resolvers/projects/services_resolver_spec.rb
index 8b6eff9e8b6..a1b631113b2 100644
--- a/spec/graphql/resolvers/projects/services_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/services_resolver_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe Resolvers::Projects::ServicesResolver do
include GraphqlHelpers
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::Projects::ServiceType.connection_type)
+ end
+
describe '#resolve' do
let_it_be(:user) { create(:user) }
diff --git a/spec/graphql/resolvers/projects/snippets_resolver_spec.rb b/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
index b4a5eb8ddb0..6f7feff8fe5 100644
--- a/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
@@ -56,12 +56,6 @@ RSpec.describe Resolvers::Projects::SnippetsResolver do
expect(snippets).to contain_exactly(project_snippet, other_project_snippet)
end
-
- it 'returns an error if the gid is invalid' do
- expect do
- resolve_snippets(args: { ids: 'foo' })
- end.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
- end
end
context 'when no project is provided' do
diff --git a/spec/graphql/resolvers/projects_resolver_spec.rb b/spec/graphql/resolvers/projects_resolver_spec.rb
index 83a26062957..3de54c7e410 100644
--- a/spec/graphql/resolvers/projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects_resolver_spec.rb
@@ -134,8 +134,8 @@ RSpec.describe Resolvers::ProjectsResolver do
is_expected.to eq([named_project3, named_project1, named_project2])
end
- it 'returns projects not in order of similarity to search if flag is off' do
- is_expected.not_to eq([named_project3, named_project1, named_project2])
+ it 'returns projects in any order if flag is off' do
+ is_expected.to match_array([named_project3, named_project1, named_project2])
end
end
end
diff --git a/spec/graphql/resolvers/release_resolver_spec.rb b/spec/graphql/resolvers/release_resolver_spec.rb
index 666d54fbc3c..04765fc68e9 100644
--- a/spec/graphql/resolvers/release_resolver_spec.rb
+++ b/spec/graphql/resolvers/release_resolver_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe Resolvers::ReleaseResolver do
let(:args) { {} }
it 'raises an error' do
- expect { resolve_release }.to raise_error(ArgumentError, "missing keyword: tag_name")
+ expect { resolve_release }.to raise_error(ArgumentError, "missing keyword: :tag_name")
end
end
end
diff --git a/spec/graphql/resolvers/releases_resolver_spec.rb b/spec/graphql/resolvers/releases_resolver_spec.rb
index ee8b33fc748..b9b90686aa7 100644
--- a/spec/graphql/resolvers/releases_resolver_spec.rb
+++ b/spec/graphql/resolvers/releases_resolver_spec.rb
@@ -5,12 +5,19 @@ require 'spec_helper'
RSpec.describe Resolvers::ReleasesResolver do
include GraphqlHelpers
+ let_it_be(:today) { Time.now }
+ let_it_be(:yesterday) { today - 1.day }
+ let_it_be(:tomorrow) { today + 1.day }
+
let_it_be(:project) { create(:project, :private) }
- let_it_be(:release_v1) { create(:release, project: project, tag: 'v1.0.0') }
- let_it_be(:release_v2) { create(:release, project: project, tag: 'v2.0.0') }
+ let_it_be(:release_v1) { create(:release, project: project, tag: 'v1.0.0', released_at: yesterday, created_at: tomorrow) }
+ let_it_be(:release_v2) { create(:release, project: project, tag: 'v2.0.0', released_at: today, created_at: yesterday) }
+ let_it_be(:release_v3) { create(:release, project: project, tag: 'v3.0.0', released_at: tomorrow, created_at: today) }
let_it_be(:developer) { create(:user) }
let_it_be(:public_user) { create(:user) }
+ let(:args) { { sort: :released_at_desc } }
+
before do
project.add_developer(developer)
end
@@ -28,7 +35,41 @@ RSpec.describe Resolvers::ReleasesResolver do
let(:current_user) { developer }
it 'returns all releases associated to the project' do
- expect(resolve_releases).to eq([release_v1, release_v2])
+ expect(resolve_releases).to eq([release_v3, release_v2, release_v1])
+ end
+
+ describe 'sorting behavior' do
+ context 'with sort: :released_at_desc' do
+ let(:args) { { sort: :released_at_desc } }
+
+ it 'returns the releases ordered by released_at in descending order' do
+ expect(resolve_releases).to eq([release_v3, release_v2, release_v1])
+ end
+ end
+
+ context 'with sort: :released_at_asc' do
+ let(:args) { { sort: :released_at_asc } }
+
+ it 'returns the releases ordered by released_at in ascending order' do
+ expect(resolve_releases).to eq([release_v1, release_v2, release_v3])
+ end
+ end
+
+ context 'with sort: :created_desc' do
+ let(:args) { { sort: :created_desc } }
+
+ it 'returns the releases ordered by created_at in descending order' do
+ expect(resolve_releases).to eq([release_v1, release_v3, release_v2])
+ end
+ end
+
+ context 'with sort: :created_asc' do
+ let(:args) { { sort: :created_asc } }
+
+ it 'returns the releases ordered by created_at in ascending order' do
+ expect(resolve_releases).to eq([release_v2, release_v3, release_v1])
+ end
+ end
end
end
end
@@ -37,6 +78,6 @@ RSpec.describe Resolvers::ReleasesResolver do
def resolve_releases
context = { current_user: current_user }
- resolve(described_class, obj: project, args: {}, ctx: context)
+ resolve(described_class, obj: project, args: args, ctx: context)
end
end
diff --git a/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb b/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb
index fdbd87c32be..16e69f662c0 100644
--- a/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb
+++ b/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe Resolvers::Snippets::BlobsResolver do
include GraphqlHelpers
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::Snippets::BlobType.connection_type)
+ end
+
describe '#resolve' do
let_it_be(:current_user) { create(:user) }
let_it_be(:snippet) { create(:personal_snippet, :private, :repository, author: current_user) }
diff --git a/spec/graphql/resolvers/snippets_resolver_spec.rb b/spec/graphql/resolvers/snippets_resolver_spec.rb
index 180be8e8624..a58d9c5ac3a 100644
--- a/spec/graphql/resolvers/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/snippets_resolver_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe Resolvers::SnippetsResolver do
context 'when using filters' do
context 'by author id' do
it 'returns the snippets' do
- snippets = resolve_snippets(args: { author_id: current_user.to_global_id })
+ snippets = resolve_snippets(args: { author_id: global_id_of(current_user) })
expect(snippets).to contain_exactly(personal_snippet, project_snippet)
end
@@ -44,7 +44,7 @@ RSpec.describe Resolvers::SnippetsResolver do
it 'returns an error if the param id is invalid' do
expect do
resolve_snippets(args: { author_id: 'foo' })
- end.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ end.to raise_error(GraphQL::CoercionError)
end
end
@@ -65,7 +65,7 @@ RSpec.describe Resolvers::SnippetsResolver do
it 'returns an error if the param id is invalid' do
expect do
resolve_snippets(args: { project_id: 'foo' })
- end.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ end.to raise_error(GraphQL::CoercionError)
end
end
@@ -99,14 +99,14 @@ RSpec.describe Resolvers::SnippetsResolver do
expect(snippets).to contain_exactly(personal_snippet, project_snippet)
end
- it 'returns an error if the gid is invalid' do
+ it 'returns an error if the id cannot be coerced' do
args = {
ids: [personal_snippet.to_global_id, 'foo']
}
expect do
resolve_snippets(args: args)
- end.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ end.to raise_error(GraphQL::CoercionError, '"foo" is not a valid Global ID')
end
it 'returns an error if both project and author are provided' do
diff --git a/spec/graphql/resolvers/todo_resolver_spec.rb b/spec/graphql/resolvers/todo_resolver_spec.rb
index 83e3140b676..c764f389c16 100644
--- a/spec/graphql/resolvers/todo_resolver_spec.rb
+++ b/spec/graphql/resolvers/todo_resolver_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe Resolvers::TodoResolver do
include GraphqlHelpers
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::TodoType.connection_type)
+ end
+
describe '#resolve' do
let_it_be(:current_user) { create(:user) }
let_it_be(:author1) { create(:user) }
diff --git a/spec/graphql/resolvers/tree_resolver_spec.rb b/spec/graphql/resolvers/tree_resolver_spec.rb
index 7818c25fe47..9eafd272771 100644
--- a/spec/graphql/resolvers/tree_resolver_spec.rb
+++ b/spec/graphql/resolvers/tree_resolver_spec.rb
@@ -7,6 +7,10 @@ RSpec.describe Resolvers::TreeResolver do
let(:repository) { create(:project, :repository).repository }
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::Tree::TreeType)
+ end
+
describe '#resolve' do
it 'resolves to a tree' do
result = resolve_repository({ ref: "master" })
diff --git a/spec/graphql/resolvers/users/group_count_resolver_spec.rb b/spec/graphql/resolvers/users/group_count_resolver_spec.rb
new file mode 100644
index 00000000000..47160a33646
--- /dev/null
+++ b/spec/graphql/resolvers/users/group_count_resolver_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Users::GroupCountResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:user1) { create(:user) }
+ let_it_be(:user2) { create(:user) }
+ let_it_be(:group1) { create(:group) }
+ let_it_be(:group2) { create(:group) }
+ let_it_be(:project) { create(:project, group: create(:group)) }
+ let_it_be(:group_member1) { create(:group_member, source: group1, user_id: user1.id, access_level: Gitlab::Access::OWNER) }
+ let_it_be(:project_member1) { create(:project_member, source: project, user_id: user1.id, access_level: Gitlab::Access::DEVELOPER) }
+ let_it_be(:group_member2) { create(:group_member, source: group2, user_id: user2.id, access_level: Gitlab::Access::DEVELOPER) }
+
+ it 'resolves group count for users' do
+ current_user = user1
+
+ result = batch_sync do
+ [user1, user2].map { |user| resolve_group_count(user, current_user) }
+ end
+
+ expect(result).to eq([2, nil])
+ end
+
+ context 'permissions' do
+ context 'when current_user is an admin', :enable_admin_mode do
+ let_it_be(:admin) { create(:admin) }
+
+ it do
+ result = batch_sync do
+ [user1, user2].map { |user| resolve_group_count(user, admin) }
+ end
+
+ expect(result).to eq([2, 1])
+ end
+ end
+
+ context 'when current_user does not have access to the requested resource' do
+ it do
+ result = batch_sync { resolve_group_count(user1, user2) }
+
+ expect(result).to be nil
+ end
+ end
+
+ context 'when current_user does not exist' do
+ it do
+ result = batch_sync { resolve_group_count(user1, nil) }
+
+ expect(result).to be nil
+ end
+ end
+ end
+ end
+
+ def resolve_group_count(user, current_user)
+ resolve(described_class, obj: user, ctx: { current_user: current_user })
+ end
+end
diff --git a/spec/graphql/resolvers/users/snippets_resolver_spec.rb b/spec/graphql/resolvers/users/snippets_resolver_spec.rb
index 497b6b11b46..9ccbebc59e6 100644
--- a/spec/graphql/resolvers/users/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/users/snippets_resolver_spec.rb
@@ -73,7 +73,7 @@ RSpec.describe Resolvers::Users::SnippetsResolver do
expect do
resolve_snippets(args: args)
- end.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ end.to raise_error(GraphQL::CoercionError)
end
end
end
diff --git a/spec/graphql/resolvers/users_resolver_spec.rb b/spec/graphql/resolvers/users_resolver_spec.rb
index e3d595e0790..1aa24055a89 100644
--- a/spec/graphql/resolvers/users_resolver_spec.rb
+++ b/spec/graphql/resolvers/users_resolver_spec.rb
@@ -5,8 +5,12 @@ require 'spec_helper'
RSpec.describe Resolvers::UsersResolver do
include GraphqlHelpers
- let_it_be(:user1) { create(:user) }
- let_it_be(:user2) { create(:user) }
+ let_it_be(:user1) { create(:user, name: "SomePerson") }
+ let_it_be(:user2) { create(:user, username: "someone123784") }
+
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::UserType.connection_type)
+ end
describe '#resolve' do
it 'raises an error when read_users_list is not authorized' do
@@ -43,6 +47,14 @@ RSpec.describe Resolvers::UsersResolver do
).to contain_exactly(user1, user2)
end
end
+
+ context 'when a search term is passed' do
+ it 'returns all users who match', :aggregate_failures do
+ expect(resolve_users(search: "some")).to contain_exactly(user1, user2)
+ expect(resolve_users(search: "123784")).to contain_exactly(user2)
+ expect(resolve_users(search: "someperson")).to contain_exactly(user1)
+ end
+ end
end
def resolve_users(args = {})