diff options
Diffstat (limited to 'spec/graphql')
39 files changed, 758 insertions, 105 deletions
diff --git a/spec/graphql/mutations/base_mutation_spec.rb b/spec/graphql/mutations/base_mutation_spec.rb index 6b366b0c234..a73d914f48f 100644 --- a/spec/graphql/mutations/base_mutation_spec.rb +++ b/spec/graphql/mutations/base_mutation_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe ::Mutations::BaseMutation do +RSpec.describe ::Mutations::BaseMutation, feature_category: :api do include GraphqlHelpers describe 'argument nullability' do diff --git a/spec/graphql/mutations/design_management/delete_spec.rb b/spec/graphql/mutations/design_management/delete_spec.rb index a76943b9ff8..9a2efb61e55 100644 --- a/spec/graphql/mutations/design_management/delete_spec.rb +++ b/spec/graphql/mutations/design_management/delete_spec.rb @@ -90,12 +90,12 @@ RSpec.describe Mutations::DesignManagement::Delete do allow(Gitlab::Tracking).to receive(:event) # rubocop:disable RSpec/ExpectGitlabTracking filenames.each(&:present?) # ignore setup - # Queries: as of 2022-06-15 + # Queries: as of 2022-08-30 # ------------- # 01. routing query - # 02. find project by id - # 03. project.project_features - # 04. find namespace by id and type + # 02. policy query: find namespace by type and id + # 03. policy query: find namespace by id + # 04. policy query: project.project_feature # 05,06. project.authorizations for user (same query twice) # 07. find issue by iid # 08. find project by id @@ -109,21 +109,22 @@ RSpec.describe Mutations::DesignManagement::Delete do # 16, 17 project.authorizations for user (same query as 5) # 18. find design_management_repository for project # 19. find route by id and source_type - # 20. find plan for standard context # ------------- our queries are below: - # 21. start transaction 1 - # 22. start transaction 2 - # 23. find version by sha and issue - # 24. exists version with sha and issue? - # 25. leave transaction 2 - # 26. create version with sha and issue - # 27. create design-version links - # 28. validate version.actions.present? - # 29. validate version.issue.present? - # 30. validate version.sha is unique - # 31. leave transaction 1 + # 20. start transaction + # 21. create version with sha and issue + # 22. create design-version links + # 23. validate version.actions.present? + # 24. validate version.sha is unique + # 25. validate version.issue.present? + # 26. leave transaction + # 27. find project by id (same query as 8) + # 28. find namespace by id (same query as 9) + # 29. find project by id (same query as 8) + # 30. find project by id (same query as 8) + # 31. create event + # 32. find plan for standard context # - expect { run_mutation }.not_to exceed_query_limit(31) + expect { run_mutation }.not_to exceed_query_limit(32) end end diff --git a/spec/graphql/mutations/work_items/linked_items/base_spec.rb b/spec/graphql/mutations/work_items/linked_items/base_spec.rb index 7061c37abd3..bc52aee443e 100644 --- a/spec/graphql/mutations/work_items/linked_items/base_spec.rb +++ b/spec/graphql/mutations/work_items/linked_items/base_spec.rb @@ -12,6 +12,7 @@ RSpec.describe Mutations::WorkItems::LinkedItems::Base, feature_category: :group it 'raises a NotImplementedError error if the update_links method is called on the base class' do mutation = described_class.new(context: { current_user: user }, object: nil, field: nil) - expect { mutation.resolve(id: work_item.to_gid) }.to raise_error(NotImplementedError) + expect { mutation.resolve(id: work_item.to_gid) } + .to raise_error(NotImplementedError, "#{described_class} does not implement update_links") end end diff --git a/spec/graphql/resolvers/base_resolver_spec.rb b/spec/graphql/resolvers/base_resolver_spec.rb index d80a61fd318..27c62da31c3 100644 --- a/spec/graphql/resolvers/base_resolver_spec.rb +++ b/spec/graphql/resolvers/base_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::BaseResolver do +RSpec.describe Resolvers::BaseResolver, feature_category: :api do include GraphqlHelpers let(:resolver) do diff --git a/spec/graphql/resolvers/blame_resolver_spec.rb b/spec/graphql/resolvers/blame_resolver_spec.rb new file mode 100644 index 00000000000..a3344132928 --- /dev/null +++ b/spec/graphql/resolvers/blame_resolver_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::BlameResolver, feature_category: :source_code_management do + include GraphqlHelpers + + describe '#resolve' do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :repository) } + + let(:path) { 'files/ruby/popen.rb' } + let(:commit) { project.commit('master') } + let(:blob) { project.repository.blob_at(commit.id, path) } + let(:args) { { from_line: 1, to_line: 2 } } + + subject(:resolve_blame) { resolve(described_class, obj: blob, args: args, ctx: { current_user: user }) } + + context 'when unauthorized' do + it 'generates an error' do + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do + resolve_blame + end + end + end + + context 'when authorized' do + before_all do + project.add_developer(user) + end + + context 'when feature is disabled' do + before do + stub_feature_flags(graphql_git_blame: false) + end + + it 'returns nothing' do + expect(subject).to be_nil + end + end + + shared_examples 'argument error' do + it 'raises an ArgumentError' do + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, + '`from_line` and `to_line` must be greater than or equal to 1') do + resolve_blame + end + end + end + + context 'when feature is enabled' do + context 'when from_line is below 1' do + let(:args) { { from_line: 0, to_line: 2 } } + + it_behaves_like 'argument error' + end + + context 'when to_line is below 1' do + let(:args) { { from_line: 1, to_line: 0 } } + + it_behaves_like 'argument error' + end + + context 'when to_line less than from_line' do + let(:args) { { from_line: 3, to_line: 1 } } + + it 'returns blame object' do + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, + '`to_line` must be greater than or equal to `from_line`') do + resolve_blame + end + end + end + + it 'returns blame object' do + expect(resolve_blame).to be_an_instance_of(Gitlab::Blame) + end + end + end + end +end diff --git a/spec/graphql/resolvers/branch_commit_resolver_spec.rb b/spec/graphql/resolvers/branch_commit_resolver_spec.rb index 3d5702539fa..f901306a355 100644 --- a/spec/graphql/resolvers/branch_commit_resolver_spec.rb +++ b/spec/graphql/resolvers/branch_commit_resolver_spec.rb @@ -32,7 +32,7 @@ RSpec.describe Resolvers::BranchCommitResolver do commit_a = repository.commits('master', limit: 1).last commit_b = repository.commits('spooky-stuff', limit: 1).last - commits = batch_sync(max_queries: 1) do + commits = batch_sync(max_queries: 2) do [ resolve(described_class, obj: branch), resolve(described_class, obj: repository.find_branch('spooky-stuff')) diff --git a/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb b/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb index fddc73fadfe..6b9e3a484b1 100644 --- a/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb @@ -5,37 +5,114 @@ require 'spec_helper' RSpec.describe Resolvers::Ci::AllJobsResolver, feature_category: :continuous_integration do include GraphqlHelpers - let_it_be(:successful_job) { create(:ci_build, :success, name: 'Job One') } - let_it_be(:successful_job_two) { create(:ci_build, :success, name: 'Job Two') } - let_it_be(:failed_job) { create(:ci_build, :failed, name: 'Job Three') } - let_it_be(:pending_job) { create(:ci_build, :pending, name: 'Job Three') } + let_it_be(:instance_runner) { create(:ci_runner, :instance) } + let_it_be(:successful_job) { create(:ci_build, :success, name: 'successful_job') } + let_it_be(:successful_job_two) { create(:ci_build, :success, name: 'successful_job_two') } + let_it_be(:failed_job) { create(:ci_build, :failed, name: 'failed_job') } + let_it_be(:pending_job) { create(:ci_build, :pending, name: 'pending_job') } let(:args) { {} } - subject { resolve_jobs(args) } - describe '#resolve' do - context 'with admin' do - let(:current_user) { create(:admin) } + subject(:request) { resolve_jobs(args) } + + context 'when current user is an admin' do + let_it_be(:current_user) { create(:admin) } shared_examples 'executes as admin' do - context 'with statuses argument' do - let(:args) { { statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS')] } } + context "with argument `statuses`" do + using RSpec::Parameterized::TableSyntax + + where(:statuses, :expected_jobs) do + nil | lazy { [successful_job, successful_job_two, failed_job, pending_job] } + %w[SUCCESS] | lazy { [successful_job, successful_job_two] } + %w[SUCCESS FAILED] | lazy { [successful_job, successful_job_two, failed_job] } + %w[CANCELED] | lazy { [] } + end - it { is_expected.to contain_exactly(successful_job, successful_job_two) } + with_them do + let(:args) do + { statuses: statuses&.map { |status| Types::Ci::JobStatusEnum.coerce_isolated_input(status) } } + end + + it { is_expected.to contain_exactly(*expected_jobs) } + end end - context 'with multiple statuses' do - let(:args) do - { statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS'), - Types::Ci::JobStatusEnum.coerce_isolated_input('FAILED')] } + context "with argument `runner_types`" do + let_it_be(:successful_job_with_instance_runner) do + create(:ci_build, :success, name: 'successful_job_with_instance_runner', runner: instance_runner) end - it { is_expected.to contain_exactly(successful_job, successful_job_two, failed_job) } + context 'with feature flag :admin_jobs_filter_runner_type enabled' do + using RSpec::Parameterized::TableSyntax + + where(:runner_types, :expected_jobs) do + nil | lazy do + [ + successful_job, + successful_job_two, + failed_job, + pending_job, + successful_job_with_instance_runner + ] + end + %w[INSTANCE_TYPE] | lazy { [successful_job_with_instance_runner] } + %w[INSTANCE_TYPE GROUP_TYPE] | lazy { [successful_job_with_instance_runner] } + %w[PROJECT_TYPE] | lazy { [] } + end + + with_them do + let(:args) do + { + runner_types: runner_types&.map { |type| Types::Ci::RunnerTypeEnum.coerce_isolated_input(type) } + } + end + + it { is_expected.to match_array(expected_jobs) } + end + end end - context 'without statuses argument' do - it { is_expected.to contain_exactly(successful_job, successful_job_two, failed_job, pending_job) } + context "with argument combination" do + let_it_be(:successful_job_with_instance_runner) do + create( + :ci_build, + :success, + name: 'successful_job_with_instance_runner', + runner: instance_runner + ) + end + + let_it_be(:running_job_with_group_runner) do + create(:ci_build, :running, name: 'running_job_with_instance_runner', runner: create(:ci_runner, :group)) + end + + context 'with feature flag :admin_jobs_filter_runner_type enabled' do + using RSpec::Parameterized::TableSyntax + + where(:statuses, :runner_types, :expected_jobs) do + %w[SUCCESS] | %w[INSTANCE_TYPE] | lazy { [successful_job_with_instance_runner] } + %w[CANCELED] | %w[INSTANCE_TYPE] | lazy { [] } + %w[SUCCESS RUNNING] | %w[INSTANCE_TYPE GROUP_TYPE] | lazy do + [ + successful_job_with_instance_runner, + running_job_with_group_runner + ] + end + end + + with_them do + let(:args) do + { + statuses: statuses&.map { |status| Types::Ci::JobStatusEnum.coerce_isolated_input(status) }, + runner_types: runner_types&.map { |type| Types::Ci::RunnerTypeEnum.coerce_isolated_input(type) } + } + end + + it { is_expected.to contain_exactly(*expected_jobs) } + end + end end end @@ -55,7 +132,9 @@ RSpec.describe Resolvers::Ci::AllJobsResolver, feature_category: :continuous_int end context 'with unauthorized user' do - let(:current_user) { nil } + let_it_be(:unauth_user) { create(:user) } + + let(:current_user) { unauth_user } it { is_expected.to be_empty } end diff --git a/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb b/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb index ff343f3f43d..fedae5c86a8 100644 --- a/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl include GraphqlHelpers describe '#resolve' do - subject do + subject(:resolve_scope) do resolve(described_class, obj: obj, ctx: { current_user: user }, args: args, arg_style: :internal) end @@ -18,8 +18,10 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl # First, we can do a couple of basic real tests to verify common cases. That ensures that the code works. context 'when user cannot see runners' do - it 'returns no runners' do - expect(subject.items.to_a).to eq([]) + it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do + resolve_scope + end end end @@ -29,14 +31,16 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl end it 'returns all the runners' do - expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner) + expect(resolve_scope.items.to_a).to contain_exactly( + inactive_project_runner, offline_project_runner, group_runner, subgroup_runner + ) end context 'with membership direct' do let(:args) { { membership: :direct } } it 'returns only direct runners' do - expect(subject.items.to_a).to contain_exactly(group_runner) + expect(resolve_scope.items.to_a).to contain_exactly(group_runner) end end end @@ -46,7 +50,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl let(:obj) { nil } it 'raises an error' do - expect { subject }.to raise_error('Expected group missing') + expect { resolve_scope }.to raise_error('Expected group missing') end end @@ -54,7 +58,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl let(:obj) { build(:project) } it 'raises an error' do - expect { subject }.to raise_error('Expected group missing') + expect { resolve_scope }.to raise_error('Expected group missing') end end @@ -90,7 +94,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl allow(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder) allow(finder).to receive(:execute).once.and_return([:execute_return_value]) - expect(subject.items.to_a).to eq([:execute_return_value]) + expect(resolve_scope.items.to_a).to eq([:execute_return_value]) end end end diff --git a/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb b/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb index 83435db2ea7..55a98106baf 100644 --- a/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_ include GraphqlHelpers describe '#resolve' do - subject do + subject(:resolve_scope) do resolve(described_class, obj: obj, ctx: { current_user: user }, args: args, arg_style: :internal) end @@ -17,8 +17,10 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_ let(:args) { {} } context 'when user cannot see runners' do - it 'returns no runners' do - expect(subject.items.to_a).to eq([]) + it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do + resolve_scope + end end end @@ -30,7 +32,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_ let(:available_runners) { [inactive_project_runner, offline_project_runner, group_runner, instance_runner] } it 'returns all runners available to the project' do - expect(subject.items.to_a).to match_array(available_runners) + expect(resolve_scope.items.to_a).to match_array(available_runners) end end @@ -38,7 +40,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_ let(:obj) { nil } it 'raises an error' do - expect { subject }.to raise_error('Expected project missing') + expect { resolve_scope }.to raise_error('Expected project missing') end end @@ -46,7 +48,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_ let(:obj) { build(:group) } it 'raises an error' do - expect { subject }.to raise_error('Expected project missing') + expect { resolve_scope }.to raise_error('Expected project missing') end end @@ -79,7 +81,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_ params: expected_params).once.and_return(finder) allow(finder).to receive(:execute).once.and_return([:execute_return_value]) - expect(subject.items.to_a).to eq([:execute_return_value]) + expect(resolve_scope.items.to_a).to contain_exactly(:execute_return_value) end end end diff --git a/spec/graphql/resolvers/ci/runners_resolver_spec.rb b/spec/graphql/resolvers/ci/runners_resolver_spec.rb index 02fc7d28255..35831579799 100644 --- a/spec/graphql/resolvers/ci/runners_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/runners_resolver_spec.rb @@ -20,8 +20,10 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d context 'when user cannot see runners' do let(:user) { build(:user) } - it 'returns no runners' do - expect(subject.items.to_a).to eq([]) + it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do + resolve_scope + end end end @@ -30,20 +32,26 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d context 'when admin mode setting is disabled', :do_not_mock_admin_mode_setting do it 'returns all the runners' do - expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner) + expect(resolve_scope.items.to_a).to contain_exactly( + inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner + ) end end context 'when admin mode setting is enabled' do context 'when in admin mode', :enable_admin_mode do it 'returns all the runners' do - expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner) + expect(resolve_scope.items.to_a).to contain_exactly( + inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner + ) end end context 'when not in admin mode' do - it 'returns no runners' do - expect(subject.items.to_a).to eq([]) + it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do + resolve_scope + end end end end @@ -54,7 +62,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d let(:obj) { build(:project) } it 'raises an error' do - expect { subject }.to raise_error(a_string_including('Unexpected parent type')) + expect { resolve_scope }.to raise_error(a_string_including('Unexpected parent type')) end end @@ -93,7 +101,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder) allow(finder).to receive(:execute).once.and_return([:execute_return_value]) - expect(subject.items.to_a).to eq([:execute_return_value]) + expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value end end @@ -116,7 +124,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder) allow(finder).to receive(:execute).once.and_return([:execute_return_value]) - expect(subject.items.to_a).to eq([:execute_return_value]) + expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value end end @@ -136,7 +144,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder) allow(finder).to receive(:execute).once.and_return([:execute_return_value]) - expect(subject.items.to_a).to eq([:execute_return_value]) + expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value end end @@ -153,7 +161,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder) allow(finder).to receive(:execute).once.and_return([:execute_return_value]) - expect(subject.items.to_a).to eq([:execute_return_value]) + expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value end end end diff --git a/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb b/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb index 75e0a816086..a4b957ef8e9 100644 --- a/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb +++ b/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb @@ -24,22 +24,8 @@ RSpec.describe Resolvers::Metrics::Dashboards::AnnotationResolver, feature_categ environment.project.add_developer(current_user) end - before do - stub_feature_flags(remove_monitor_metrics: false) - end - context 'with annotation records' do - context 'when metrics dashboard feature is unavailable' do - before do - stub_feature_flags(remove_monitor_metrics: true) - end - - it 'returns nothing' do - expect(resolve_annotations).to be_nil - end - end - - it 'returns [] all the time' do + it 'returns empty all the time' do expect(resolve_annotations).to be_empty end end diff --git a/spec/graphql/resolvers/work_items_resolver_spec.rb b/spec/graphql/resolvers/work_items_resolver_spec.rb index 6da62e3adb7..c856f990e7a 100644 --- a/spec/graphql/resolvers/work_items_resolver_spec.rb +++ b/spec/graphql/resolvers/work_items_resolver_spec.rb @@ -46,11 +46,6 @@ RSpec.describe Resolvers::WorkItemsResolver do expect(resolve_items).to contain_exactly(item1, item2) end - it 'filters by state' do - expect(resolve_items(state: 'opened')).to contain_exactly(item1) - expect(resolve_items(state: 'closed')).to contain_exactly(item2) - end - context 'when searching items' do it_behaves_like 'graphql query for searching issuables' do let_it_be(:parent) { project } diff --git a/spec/graphql/types/base_argument_spec.rb b/spec/graphql/types/base_argument_spec.rb index 8f5f2e08799..0ce6aa3667d 100644 --- a/spec/graphql/types/base_argument_spec.rb +++ b/spec/graphql/types/base_argument_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Types::BaseArgument do +RSpec.describe Types::BaseArgument, feature_category: :api do let_it_be(:field) do Types::BaseField.new(name: 'field', type: String, null: true) end diff --git a/spec/graphql/types/base_edge_spec.rb b/spec/graphql/types/base_edge_spec.rb index b02ccbaffef..0cc0c838fac 100644 --- a/spec/graphql/types/base_edge_spec.rb +++ b/spec/graphql/types/base_edge_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Types::BaseEdge do +RSpec.describe Types::BaseEdge, feature_category: :api do include GraphqlHelpers let_it_be(:test_schema) do diff --git a/spec/graphql/types/base_enum_spec.rb b/spec/graphql/types/base_enum_spec.rb index 65a345052c7..db8fb877390 100644 --- a/spec/graphql/types/base_enum_spec.rb +++ b/spec/graphql/types/base_enum_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Types::BaseEnum do +RSpec.describe Types::BaseEnum, feature_category: :api do describe '.from_rails_enum' do let(:enum_type) { Class.new(described_class) } let(:template) { "The name is '%{name}', James %{name}." } diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb index 9f8a8717efb..831d36950db 100644 --- a/spec/graphql/types/base_field_spec.rb +++ b/spec/graphql/types/base_field_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Types::BaseField do +RSpec.describe Types::BaseField, feature_category: :api do describe 'authorized?' do let(:object) { double } let(:current_user) { nil } diff --git a/spec/graphql/types/base_object_spec.rb b/spec/graphql/types/base_object_spec.rb index 3c42c708187..af0639e84d3 100644 --- a/spec/graphql/types/base_object_spec.rb +++ b/spec/graphql/types/base_object_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Types::BaseObject do +RSpec.describe Types::BaseObject, feature_category: :api do include GraphqlHelpers describe 'scoping items' do diff --git a/spec/graphql/types/blame/blame_type_spec.rb b/spec/graphql/types/blame/blame_type_spec.rb new file mode 100644 index 00000000000..15846130edb --- /dev/null +++ b/spec/graphql/types/blame/blame_type_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::Blame::BlameType, feature_category: :source_code_management do + include GraphqlHelpers + + specify { expect(described_class.graphql_name).to eq('Blame') } + + specify do + expect(described_class).to have_graphql_fields( + :first_line, + :groups + ).at_least + end +end diff --git a/spec/graphql/types/blame/commit_data_type_spec.rb b/spec/graphql/types/blame/commit_data_type_spec.rb new file mode 100644 index 00000000000..432f09bf8f7 --- /dev/null +++ b/spec/graphql/types/blame/commit_data_type_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::Blame::CommitDataType, + feature_category: :source_code_management do + include GraphqlHelpers + + specify { expect(described_class.graphql_name).to eq('CommitData') } + + specify do + expect(described_class).to have_graphql_fields( + :age_map_class, + :author_avatar, + :commit_author_link, + :commit_link, + :project_blame_link, + :time_ago_tooltip + ).at_least + end +end diff --git a/spec/graphql/types/blame/groups_type_spec.rb b/spec/graphql/types/blame/groups_type_spec.rb new file mode 100644 index 00000000000..9e870e1cdc0 --- /dev/null +++ b/spec/graphql/types/blame/groups_type_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::Blame::GroupsType, feature_category: :source_code_management do + include GraphqlHelpers + + specify { expect(described_class.graphql_name).to eq('Groups') } + + specify do + expect(described_class).to have_graphql_fields( + :commit, + :commit_data, + :lineno, + :lines, + :span + ).at_least + end +end diff --git a/spec/graphql/types/ci/job_base_field_spec.rb b/spec/graphql/types/ci/job_base_field_spec.rb new file mode 100644 index 00000000000..2d283ce854d --- /dev/null +++ b/spec/graphql/types/ci/job_base_field_spec.rb @@ -0,0 +1,143 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::Ci::JobBaseField, feature_category: :runner_fleet do + describe 'authorized?' do + let_it_be(:current_user) { create(:user) } + + let(:object) { double } + let(:ctx) { { current_user: current_user, current_field: current_field } } + let(:current_field) { instance_double(described_class, original_name: current_field_name.to_sym) } + let(:args) { {} } + + subject(:field) do + described_class.new(name: current_field_name, type: GraphQL::Types::String, null: true, **args) + end + + context 'when :job_field_authorization is specified' do + let(:ctx) { { current_user: current_user, current_field: current_field, job_field_authorization: :foo } } + + context 'with public field' do + using RSpec::Parameterized::TableSyntax + + where(:current_field_name) do + %i[allow_failure duration id kind status created_at finished_at queued_at queued_duration updated_at runner] + end + + with_them do + it 'returns true without authorizing' do + is_expected.to be_authorized(object, nil, ctx) + end + end + end + + context 'with private field' do + let(:current_field_name) { 'short_sha' } + + context 'when permission is not allowed' do + it 'returns false' do + expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(false) + + is_expected.not_to be_authorized(object, nil, ctx) + end + end + + context 'when permission is allowed' do + it 'returns true' do + expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(true) + + is_expected.to be_authorized(object, nil, ctx) + end + end + end + end + + context 'when :job_field_authorization is not specified' do + let(:current_field_name) { 'status' } + + it 'defaults to true' do + is_expected.to be_authorized(object, nil, ctx) + end + + context 'when field is authorized' do + let(:args) { { authorize: :foo } } + + it 'tests the field authorization' do + expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(false) + + expect(field).not_to be_authorized(object, nil, ctx) + end + + it 'tests the field authorization, if provided, when it succeeds' do + expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(true) + + expect(field).to be_authorized(object, nil, ctx) + end + end + + context 'with field resolver' do + let(:resolver) { Class.new } + let(:args) { { resolver_class: resolver } } + + it 'only tests the resolver authorization if it authorizes_object?' do + is_expected.to be_authorized(object, nil, ctx) + end + + context 'when resolver authorizes object' do + let(:resolver) do + Class.new do + include Gitlab::Graphql::Authorize::AuthorizeResource + + authorizes_object! + end + end + + it 'tests the resolver authorization, if provided' do + expect(resolver).to receive(:authorized?).with(object, ctx).and_return(false) + + expect(field).not_to be_authorized(object, nil, ctx) + end + + context 'when field is authorized' do + let(:args) { { authorize: :foo, resolver_class: resolver } } + + it 'tests field authorization before resolver authorization, when field auth fails' do + expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(false) + expect(resolver).not_to receive(:authorized?) + + expect(field).not_to be_authorized(object, nil, ctx) + end + + it 'tests field authorization before resolver authorization, when field auth succeeds' do + expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(true) + expect(resolver).to receive(:authorized?).with(object, ctx).and_return(false) + + expect(field).not_to be_authorized(object, nil, ctx) + end + end + end + end + end + end + + describe '#resolve' do + context 'when late_extensions is given' do + it 'registers the late extensions after the regular extensions' do + extension_class = Class.new(GraphQL::Schema::Field::ConnectionExtension) + field = described_class.new(name: 'private_field', type: GraphQL::Types::String.connection_type, + null: true, late_extensions: [extension_class]) + + expect(field.extensions.last.class).to be(extension_class) + end + end + end + + include_examples 'Gitlab-style deprecations' do + def subject(args = {}) + base_args = { name: 'private_field', type: GraphQL::Types::String, null: true } + + described_class.new(**base_args.merge(args)) + end + end +end diff --git a/spec/graphql/types/ci/job_kind_enum_spec.rb b/spec/graphql/types/ci/job_kind_enum_spec.rb index b48d20b71e2..a09cd89ec8b 100644 --- a/spec/graphql/types/ci/job_kind_enum_spec.rb +++ b/spec/graphql/types/ci/job_kind_enum_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['CiJobKind'] do it 'exposes some job type values' do expect(described_class.values.keys).to match_array( - (%w[BRIDGE BUILD]) + %w[BRIDGE BUILD] ) end end diff --git a/spec/graphql/types/ci/job_trace_type_spec.rb b/spec/graphql/types/ci/job_trace_type_spec.rb index 71803aa9ece..69123445b8b 100644 --- a/spec/graphql/types/ci/job_trace_type_spec.rb +++ b/spec/graphql/types/ci/job_trace_type_spec.rb @@ -13,15 +13,187 @@ RSpec.describe GitlabSchema.types['CiJobTrace'], feature_category: :continuous_i expect(described_class).to have_graphql_fields(*expected_fields) end - it 'shows the correct trace contents' do - job.trace.set('BUILD TRACE') + describe 'htmlSummary' do + subject(:resolved_field) { resolve_field(:html_summary, job.trace, args: args) } - expect_next_instance_of(Gitlab::Ci::Trace) do |trace| - expect(trace).to receive(:html).with(last_lines: 10).and_call_original + context 'when trace contains few lines' do + before do + job.trace.set('BUILD TRACE') + end + + context 'when last_lines is set to 10' do + let(:args) { { last_lines: 10 } } + + it 'shows the correct trace contents' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 10, max_size: 16384).and_call_original + end + + is_expected.to eq('<span>BUILD TRACE</span>') + end + end + end + + context 'when trace contains many lines' do + before do + job.trace.set((1..200).map { |i| "Line #{i}" }.join("\n")) + end + + def expected_html_trace_contents(line_count) + "<span>#{((200 - (line_count - 1))..200).map { |i| "Line #{i}" }.join('<br/>')}</span>" + end + + context 'when last_lines is not set' do + let(:args) { {} } + + it 'shows the last 10 lines of trace contents' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 10, max_size: 16384).and_call_original + end + + is_expected.to eq expected_html_trace_contents(10) + end + end + + context 'when last_lines is set to a negative number' do + let(:args) { { last_lines: -10 } } + + it 'shows the last line of trace contents' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 1, max_size: 16384).and_call_original + end + + is_expected.to eq expected_html_trace_contents(1) + end + end + + context 'when last_lines is set to 10' do + let(:args) { { last_lines: 10 } } + + it 'shows the correct trace contents' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 10, max_size: 16384).and_call_original + end + + is_expected.to eq expected_html_trace_contents(10) + end + end + + context 'when last_lines is set to 150' do + let(:args) { { last_lines: 150 } } + + it 'shows the last 100 lines of trace contents' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 100, max_size: 16384).and_call_original + end + + is_expected.to eq expected_html_trace_contents(100) + end + end + end + + context 'when trace contains long lines' do + before do + # Creates lines of "aaaaaaaa...aaaaaaaa" + job.trace.set((1..20).map { (1..1024).map { "a" }.join("") }.join("\n")) + end + + context 'when last_lines is lower than 16KB' do + let(:args) { {} } + + it 'shows the whole lines' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 10, max_size: 16384).and_call_original + end + + is_expected.to eq "<span>#{(1..10).map { (1..1024).map { 'a' }.join('') }.join('<br/>')}</span>" + end + end + + context 'when last_lines is higher than 16KB' do + let(:args) { { last_lines: 20 } } + + it 'shows only the latest byte' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 20, max_size: 16384).and_call_original + end + + is_expected.to eq "<span>#{(1..1009).map { 'a' }.join('')}<br/>" \ + "#{(1..15).map { (1..1024).map { 'a' }.join('') }.join('<br/>')}</span>" + end + end + + context 'when FF graphql_job_trace_html_summary_max_size is disabled' do + before do + stub_feature_flags(graphql_job_trace_html_summary_max_size: false) + end + + let(:args) { { last_lines: 20 } } + + it 'does not limit the read size from the raw trace' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 20, max_size: nil).and_call_original + end + + is_expected.to eq "<span>#{(1..20).map { (1..1024).map { 'a' }.join('') }.join('<br/>')}</span>" + end + end + + context 'when trace is cut in middle of a line' do + let(:args) { {} } + + before do + stub_const('Types::Ci::JobTraceType::MAX_SIZE_B', 1536) + end + + it 'shows only the latest byte' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 10, max_size: 1536).and_call_original + end + + is_expected.to eq "<span>#{(1..511).map { 'a' }.join('')}<br/>#{(1..1024).map { 'a' }.join('')}</span>" + end + end + + context 'when trace is cut at end of a line' do + let(:args) { {} } + + before do + stub_const('Types::Ci::JobTraceType::MAX_SIZE_B', 2050) + end + + it 'shows only the latest byte' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 10, max_size: 2050).and_call_original + end + + is_expected.to eq "<span><br/>#{(1..2).map { (1..1024).map { 'a' }.join('') }.join('<br/>')}</span>" + end + end end - resolved_field = resolve_field(:html_summary, job.trace) + context 'when trace contains multi-bytes UTF-8' do + before do + # Creates lines of 4 pound symbol, pound symbol is 2 byte wise in UTF-8 + # Append an "a" (1 byte character) at the end to cut in the middle of UTF-8 + job.trace.set((1..20).map { (1..4).map { "£" }.join("") }.join("\n")) + end + + context 'when cut in the middle of a codepoint' do + before do + stub_const('Types::Ci::JobTraceType::MAX_SIZE_B', 5) + end + + let(:args) { {} } - expect(resolved_field).to eq("<span>BUILD TRACE</span>") + it 'shows a single "invalid utf-8" symbol' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 10, max_size: 5).and_call_original + end + + is_expected.to eq "<span>�££</span>" + end + end + end end end diff --git a/spec/graphql/types/ci/job_type_spec.rb b/spec/graphql/types/ci/job_type_spec.rb index f31c0d5255c..a69c6f37ee1 100644 --- a/spec/graphql/types/ci/job_type_spec.rb +++ b/spec/graphql/types/ci/job_type_spec.rb @@ -32,6 +32,7 @@ RSpec.describe Types::Ci::JobType, feature_category: :continuous_integration do needs pipeline playable + previousStageJobs previousStageJobsOrNeeds project queued_at diff --git a/spec/graphql/types/issue_type_spec.rb b/spec/graphql/types/issue_type_spec.rb index 6c4e68fba6b..d4d0eff9adb 100644 --- a/spec/graphql/types/issue_type_spec.rb +++ b/spec/graphql/types/issue_type_spec.rb @@ -21,7 +21,7 @@ RSpec.describe GitlabSchema.types['Issue'] do confidential hidden discussion_locked upvotes downvotes merge_requests_count user_notes_count user_discussions_count web_path web_url relative_position emails_disabled emails_enabled subscribed time_estimate total_time_spent human_time_estimate human_total_time_spent closed_at created_at updated_at task_completion_status design_collection alert_management_alert alert_management_alerts severity current_user_todos moved moved_to - closed_as_duplicate_of create_note_email timelogs project_id customer_relations_contacts escalation_status] + closed_as_duplicate_of create_note_email timelogs project_id customer_relations_contacts escalation_status external_author] fields.each do |field_name| expect(described_class).to have_graphql_field(field_name) diff --git a/spec/graphql/types/label_type_spec.rb b/spec/graphql/types/label_type_spec.rb index 427b5d2dcef..d68945b01e6 100644 --- a/spec/graphql/types/label_type_spec.rb +++ b/spec/graphql/types/label_type_spec.rb @@ -9,6 +9,7 @@ RSpec.describe GitlabSchema.types['Label'] do :description_html, :title, :color, + :lock_on_merge, :text_color, :created_at, :updated_at diff --git a/spec/graphql/types/merge_request_type_spec.rb b/spec/graphql/types/merge_request_type_spec.rb index bd271da55a9..9742908edf9 100644 --- a/spec/graphql/types/merge_request_type_spec.rb +++ b/spec/graphql/types/merge_request_type_spec.rb @@ -36,7 +36,7 @@ RSpec.describe GitlabSchema.types['MergeRequest'], feature_category: :code_revie commit_count current_user_todos conflicts auto_merge_enabled approved_by source_branch_protected squash_on_merge available_auto_merge_strategies has_ci mergeable commits committers commits_without_merge_commits squash security_auto_fix default_squash_commit_message - auto_merge_strategy merge_user award_emoji prepared_at + auto_merge_strategy merge_user award_emoji prepared_at codequality_reports_comparer supports_lock_on_merge ] expect(described_class).to have_graphql_fields(*expected_fields).at_least diff --git a/spec/graphql/types/organizations/group_sort_enum_spec.rb b/spec/graphql/types/organizations/group_sort_enum_spec.rb new file mode 100644 index 00000000000..57915d95c45 --- /dev/null +++ b/spec/graphql/types/organizations/group_sort_enum_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['OrganizationGroupSort'], feature_category: :cell do + let(:sort_values) do + %w[ + ID_ASC + ID_DESC + NAME_ASC + NAME_DESC + PATH_ASC + PATH_DESC + UPDATED_AT_ASC + UPDATED_AT_DESC + CREATED_AT_ASC + CREATED_AT_DESC + ] + end + + specify { expect(described_class.graphql_name).to eq('OrganizationGroupSort') } + + it 'exposes all the organization groups sort values' do + expect(described_class.values.keys).to include(*sort_values) + end +end diff --git a/spec/graphql/types/organizations/organization_type_spec.rb b/spec/graphql/types/organizations/organization_type_spec.rb new file mode 100644 index 00000000000..26d7c10a715 --- /dev/null +++ b/spec/graphql/types/organizations/organization_type_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['Organization'], feature_category: :cell do + let(:expected_fields) { %w[groups id name organization_users path] } + + specify { expect(described_class.graphql_name).to eq('Organization') } + specify { expect(described_class).to require_graphql_authorizations(:read_organization) } + specify { expect(described_class).to have_graphql_fields(*expected_fields) } +end diff --git a/spec/graphql/types/organizations/organization_user_type_spec.rb b/spec/graphql/types/organizations/organization_user_type_spec.rb new file mode 100644 index 00000000000..876080b0f15 --- /dev/null +++ b/spec/graphql/types/organizations/organization_user_type_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['OrganizationUser'], feature_category: :cell do + let(:expected_fields) { %w[badges id user] } + + specify { expect(described_class.graphql_name).to eq('OrganizationUser') } + specify { expect(described_class).to require_graphql_authorizations(:read_organization_user) } + specify { expect(described_class).to have_graphql_fields(*expected_fields) } +end diff --git a/spec/graphql/types/permission_types/work_item_spec.rb b/spec/graphql/types/permission_types/work_item_spec.rb index 3ee42e2e3ad..cdbf94304de 100644 --- a/spec/graphql/types/permission_types/work_item_spec.rb +++ b/spec/graphql/types/permission_types/work_item_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Types::PermissionTypes::WorkItem do it do expected_permissions = [ :read_work_item, :update_work_item, :delete_work_item, :admin_work_item, - :admin_parent_link, :set_work_item_metadata, :create_note + :admin_parent_link, :set_work_item_metadata, :create_note, :admin_work_item_link ] expected_permissions.each do |permission| diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index cd9a0642ae6..a20a4767bb5 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -892,22 +892,25 @@ RSpec.describe GitlabSchema.types['Project'] do subject { GitlabSchema.execute(query, context: { current_user: user }).as_json } - before do + before_all do fork_reporter.add_reporter(user) fork_developer.add_developer(user) fork_group_developer.group.add_developer(user) + fork_private.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) end it 'contains all forks' do - expect(forks.count).to eq(5) + expect(forks.count).to eq(4) end context 'with minimum_access_level DEVELOPER' do let(:minimum_access_level) { '(minimumAccessLevel: DEVELOPER)' } it 'contains forks with developer access' do - expect(forks).to contain_exactly(a_hash_including('fullPath' => fork_developer.full_path), -a_hash_including('fullPath' => fork_group_developer.full_path)) + expect(forks).to contain_exactly( + a_hash_including('fullPath' => fork_developer.full_path), + a_hash_including('fullPath' => fork_group_developer.full_path) + ) end context 'when current user is not set' do diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb index 100ecc94f35..8bda738751d 100644 --- a/spec/graphql/types/query_type_spec.rb +++ b/spec/graphql/types/query_type_spec.rb @@ -23,6 +23,16 @@ RSpec.describe GitlabSchema.types['Query'], feature_category: :shared do end end + describe 'organization field' do + subject { described_class.fields['organization'] } + + it 'finds organization by path' do + is_expected.to have_graphql_arguments(:id) + is_expected.to have_graphql_type(Types::Organizations::OrganizationType) + is_expected.to have_graphql_resolver(Resolvers::Organizations::OrganizationResolver) + end + end + describe 'project field' do subject { described_class.fields['project'] } diff --git a/spec/graphql/types/repository/blob_type_spec.rb b/spec/graphql/types/repository/blob_type_spec.rb index 9537fca7322..104093bd909 100644 --- a/spec/graphql/types/repository/blob_type_spec.rb +++ b/spec/graphql/types/repository/blob_type_spec.rb @@ -30,6 +30,7 @@ RSpec.describe Types::Repository::BlobType, feature_category: :source_code_manag :gitpod_blob_url, :find_file_path, :blame_path, + :blame, :history_path, :permalink_path, :environment_formatted_external_url, diff --git a/spec/graphql/types/security/codequality_reports_comparer/degradation_type_spec.rb b/spec/graphql/types/security/codequality_reports_comparer/degradation_type_spec.rb new file mode 100644 index 00000000000..9ae1b3fcf94 --- /dev/null +++ b/spec/graphql/types/security/codequality_reports_comparer/degradation_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['CodequalityReportsComparerReportDegradation'], feature_category: :code_quality do + specify { expect(described_class.graphql_name).to eq('CodequalityReportsComparerReportDegradation') } + + it 'has expected fields' do + expected_fields = %i[description fingerprint severity file_path line web_url engine_name] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/security/codequality_reports_comparer/report_type_spec.rb b/spec/graphql/types/security/codequality_reports_comparer/report_type_spec.rb new file mode 100644 index 00000000000..a1788126f1b --- /dev/null +++ b/spec/graphql/types/security/codequality_reports_comparer/report_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['CodequalityReportsComparerReport'], feature_category: :code_quality do + specify { expect(described_class.graphql_name).to eq('CodequalityReportsComparerReport') } + + it 'has expected fields' do + expected_fields = %i[status new_errors resolved_errors existing_errors summary] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/security/codequality_reports_comparer/status_enum_spec.rb b/spec/graphql/types/security/codequality_reports_comparer/status_enum_spec.rb new file mode 100644 index 00000000000..6e5bdd1e91d --- /dev/null +++ b/spec/graphql/types/security/codequality_reports_comparer/status_enum_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['CodequalityReportsComparerReportStatus'], feature_category: :code_quality do + specify { expect(described_class.graphql_name).to eq('CodequalityReportsComparerReportStatus') } + + it 'exposes all codequality report status values' do + expect(described_class.values.keys).to contain_exactly('SUCCESS', 'FAILED', 'NOT_FOUND') + end +end diff --git a/spec/graphql/types/security/codequality_reports_comparer/summary_type_spec.rb b/spec/graphql/types/security/codequality_reports_comparer/summary_type_spec.rb new file mode 100644 index 00000000000..41de93b27ad --- /dev/null +++ b/spec/graphql/types/security/codequality_reports_comparer/summary_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['CodequalityReportsComparerReportSummary'], feature_category: :code_quality do + specify { expect(described_class.graphql_name).to eq('CodequalityReportsComparerReportSummary') } + + it 'has expected fields' do + expected_fields = %i[total resolved errored] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/security/codequality_reports_comparer_type_spec.rb b/spec/graphql/types/security/codequality_reports_comparer_type_spec.rb new file mode 100644 index 00000000000..02f7a9d6925 --- /dev/null +++ b/spec/graphql/types/security/codequality_reports_comparer_type_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['CodequalityReportsComparer'], feature_category: :code_quality do + specify { expect(described_class.graphql_name).to eq('CodequalityReportsComparer') } + + it 'has expected fields' do + expect(described_class).to have_graphql_fields(:report) + end +end |