diff options
Diffstat (limited to 'spec/graphql/types')
35 files changed, 413 insertions, 170 deletions
diff --git a/spec/graphql/types/alert_management/domain_filter_enum_spec.rb b/spec/graphql/types/alert_management/domain_filter_enum_spec.rb index 2111a33b8b4..9e8d7589352 100644 --- a/spec/graphql/types/alert_management/domain_filter_enum_spec.rb +++ b/spec/graphql/types/alert_management/domain_filter_enum_spec.rb @@ -6,6 +6,6 @@ RSpec.describe GitlabSchema.types['AlertManagementDomainFilter'] do specify { expect(described_class.graphql_name).to eq('AlertManagementDomainFilter') } it 'exposes all the severity values' do - expect(described_class.values.keys).to include(*%w[threat_monitoring operations]) + expect(described_class.values.keys).to include(*%w[operations threat_monitoring]) end end diff --git a/spec/graphql/types/ci/config/config_type_spec.rb b/spec/graphql/types/ci/config/config_type_spec.rb index 0012ae9f51f..78dd5afc1d8 100644 --- a/spec/graphql/types/ci/config/config_type_spec.rb +++ b/spec/graphql/types/ci/config/config_type_spec.rb @@ -8,6 +8,7 @@ RSpec.describe Types::Ci::Config::ConfigType do it 'exposes the expected fields' do expected_fields = %i[ errors + includes mergedYaml stages status diff --git a/spec/graphql/types/ci/config/include_type_enum_spec.rb b/spec/graphql/types/ci/config/include_type_enum_spec.rb new file mode 100644 index 00000000000..a88316ae6f2 --- /dev/null +++ b/spec/graphql/types/ci/config/include_type_enum_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['CiConfigIncludeType'] do + it { expect(described_class.graphql_name).to eq('CiConfigIncludeType') } + + it 'exposes all the existing include types' do + expect(described_class.values.keys).to match_array(%w[remote local file template]) + end +end diff --git a/spec/graphql/types/ci/config/include_type_spec.rb b/spec/graphql/types/ci/config/include_type_spec.rb new file mode 100644 index 00000000000..971e185ccd9 --- /dev/null +++ b/spec/graphql/types/ci/config/include_type_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::Ci::Config::IncludeType do + specify { expect(described_class.graphql_name).to eq('CiConfigInclude') } + + it 'exposes the expected fields' do + expected_fields = %i[ + context_project + context_sha + extra + location + blob + raw + type + ] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/ci/runner_type_spec.rb b/spec/graphql/types/ci/runner_type_spec.rb index 7697cd0ef79..26ac7a4da8d 100644 --- a/spec/graphql/types/ci/runner_type_spec.rb +++ b/spec/graphql/types/ci/runner_type_spec.rb @@ -11,8 +11,8 @@ RSpec.describe GitlabSchema.types['CiRunner'] do expected_fields = %w[ id description created_at contacted_at maximum_timeout access_level active paused status version short_sha revision locked run_untagged ip_address runner_type tag_list - project_count job_count admin_url edit_admin_url user_permissions executor_name - groups projects jobs token_expires_at + project_count job_count admin_url edit_admin_url user_permissions executor_name architecture_name platform_name + maintenance_note groups projects jobs token_expires_at ] expect(described_class).to include_graphql_fields(*expected_fields) diff --git a/spec/graphql/types/ci/runner_upgrade_status_type_enum_spec.rb b/spec/graphql/types/ci/runner_upgrade_status_type_enum_spec.rb new file mode 100644 index 00000000000..81a852471b9 --- /dev/null +++ b/spec/graphql/types/ci/runner_upgrade_status_type_enum_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::Ci::RunnerUpgradeStatusTypeEnum do + specify { expect(described_class.graphql_name).to eq('CiRunnerUpgradeStatusType') } + + it 'exposes all upgrade status values' do + expect(described_class.values.keys).to eq( + ['UNKNOWN'] + ::Gitlab::Ci::RunnerUpgradeCheck::STATUSES.map { |sym, _| sym.to_s.upcase } + ) + end +end diff --git a/spec/graphql/types/color_type_spec.rb b/spec/graphql/types/color_type_spec.rb new file mode 100644 index 00000000000..57c26e12b51 --- /dev/null +++ b/spec/graphql/types/color_type_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::ColorType do + let(:hex) { '#663399' } + let(:color_name) { 'rebeccapurple' } + let(:color) { ::Gitlab::Color.of(hex) } + let(:named_color) { ::Gitlab::Color.of(color_name) } + + specify { expect(described_class.graphql_name).to eq('Color') } + + it 'coerces Color object into hex string' do + expect(described_class.coerce_isolated_result(color)).to eq(hex) + end + + it 'coerces an hex string into Color object' do + expect(described_class.coerce_isolated_input(hex)).to eq(color) + end + + it 'coerces an named Color into hex string' do + expect(described_class.coerce_isolated_result(named_color)).to eq(hex) + end + + it 'coerces an named color into Color object' do + expect(described_class.coerce_isolated_input(color_name)).to eq(named_color) + end + + it 'rejects invalid input' do + expect { described_class.coerce_isolated_input('not valid') } + .to raise_error(GraphQL::CoercionError) + end + + it 'rejects nil' do + expect { described_class.coerce_isolated_input(nil) } + .to raise_error(GraphQL::CoercionError) + end +end diff --git a/spec/graphql/types/container_expiration_policy_type_spec.rb b/spec/graphql/types/container_expiration_policy_type_spec.rb index 9e9ddaf1cb0..95c2be9dfcc 100644 --- a/spec/graphql/types/container_expiration_policy_type_spec.rb +++ b/spec/graphql/types/container_expiration_policy_type_spec.rb @@ -7,7 +7,7 @@ RSpec.describe GitlabSchema.types['ContainerExpirationPolicy'] do specify { expect(described_class.description).to eq('A tag expiration policy designed to keep only the images that matter most') } - specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) } + specify { expect(described_class).to require_graphql_authorizations(:admin_container_image) } describe 'older_than field' do subject { described_class.fields['olderThan'] } diff --git a/spec/graphql/types/container_repository_details_type_spec.rb b/spec/graphql/types/container_repository_details_type_spec.rb index d94516c6fce..62e72089e09 100644 --- a/spec/graphql/types/container_repository_details_type_spec.rb +++ b/spec/graphql/types/container_repository_details_type_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['ContainerRepositoryDetails'] do fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete expiration_policy_cleanup_status tags size - project migration_state] + project migration_state last_cleanup_deleted_tags_count] it { expect(described_class.graphql_name).to eq('ContainerRepositoryDetails') } diff --git a/spec/graphql/types/container_repository_type_spec.rb b/spec/graphql/types/container_repository_type_spec.rb index 9815449dd68..bc92fa24050 100644 --- a/spec/graphql/types/container_repository_type_spec.rb +++ b/spec/graphql/types/container_repository_type_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['ContainerRepository'] do fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete expiration_policy_cleanup_status project - migration_state] + migration_state last_cleanup_deleted_tags_count] it { expect(described_class.graphql_name).to eq('ContainerRepository') } diff --git a/spec/graphql/types/current_user_todos_type_spec.rb b/spec/graphql/types/current_user_todos_type_spec.rb index a0015e96788..4ce97e1c006 100644 --- a/spec/graphql/types/current_user_todos_type_spec.rb +++ b/spec/graphql/types/current_user_todos_type_spec.rb @@ -3,7 +3,214 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['CurrentUserTodos'] do + include GraphqlHelpers + specify { expect(described_class.graphql_name).to eq('CurrentUserTodos') } specify { expect(described_class).to have_graphql_fields(:current_user_todos).only } + + # Request store is necessary to prevent duplicate max-member-access lookups + describe '.current_user_todos', :request_store, :aggregate_failures do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :repository) } + let_it_be(:issue_a) { create(:issue, project: project) } + let_it_be(:issue_b) { create(:issue, project: project) } + + let_it_be(:todo_a) { create(:todo, :pending, user: user, project: project, target: issue_a) } + let_it_be(:todo_b) { create(:todo, :done, user: user, project: project, target: issue_a) } + let_it_be(:todo_c) { create(:todo, :pending, user: user, project: project, target: issue_b) } + let_it_be(:todo_d) { create(:todo, :done, user: user, project: project, target: issue_b) } + + let_it_be(:merge_request) { create(:merge_request, source_project: project) } + let_it_be(:todo_e) { create(:todo, :pending, user: user, project: project, target: merge_request) } + + let(:object_type) do + fresh_object_type('HasTodos').tap { _1.implements(Types::CurrentUserTodos) } + end + + let(:id_enum) do + Class.new(Types::BaseEnum) do + graphql_name 'AorB' + + value 'A' + value 'B' + end + end + + let(:query_type) do + i_a = issue_a + i_b = issue_b + issue_id = id_enum + mr = merge_request + + q = fresh_object_type('Query') + + q.field :issue, null: false, type: object_type do + argument :id, type: issue_id, required: true + end + + q.field :mr, null: false, type: object_type + + q.define_method(:issue) do |id:| + case id + when 'A' + i_a + when 'B' + i_b + end + end + + q.define_method(:mr) { mr } + + q + end + + let(:todo_fragment) do + <<-GQL + fragment todos on HasTodos { + todos: currentUserTodos { + nodes { id } + } + } + GQL + end + + let(:base_query) do + <<-GQL + query { + issue(id: A) { ... todos } + } + #{todo_fragment} + GQL + end + + let(:query_without_state_arguments) do + <<-GQL + query { + a: issue(id: A) { + ... todos + } + b: issue(id: B) { + ... todos + } + c: mr { + ... todos + } + d: mr { + ... todos + } + e: issue(id: A) { + ... todos + } + } + + #{todo_fragment} + GQL + end + + let(:with_state_arguments) do + <<-GQL + query { + a: issue(id: A) { + todos: currentUserTodos(state: pending) { nodes { id } } + } + b: issue(id: B) { + todos: currentUserTodos(state: done) { nodes { id } } + } + c: mr { + ... todos + } + } + + #{todo_fragment} + GQL + end + + before_all do + project.add_developer(user) + end + + it 'batches todo lookups, linear in the number of target types/state arguments' do + # The baseline is 4 queries: + # + # When we batch queries, we see the following three groups of queries: + # # user authorization + # 1. SELECT "users".* FROM "users" + # INNER JOIN "project_authorizations" + # ON "users"."id" = "project_authorizations"."user_id" + # WHERE "project_authorizations"."project_id" = project_id + # AND "project_authorizations"."access_level" = 50 + # 2. SELECT MAX("project_authorizations"."access_level") AS maximum_access_level, + # "project_authorizations"."user_id" AS project_authorizations_user_id + # FROM "project_authorizations" + # WHERE "project_authorizations"."project_id" = project_id + # AND "project_authorizations"."user_id" = user_id + # GROUP BY "project_authorizations"."user_id" + # + # # find todos for issues + # 1. SELECT "todos".* FROM "todos" + # WHERE "todos"."user_id" = user_id + # AND ("todos"."state" IN ('done','pending')) + # AND "todos"."target_id" IN (issue_a, issue_b) + # AND "todos"."target_type" = 'Issue' ORDER BY "todos"."id" DESC + # + # # find todos for merge_requests + # 1. SELECT "todos".* FROM "todos" WHERE "todos"."user_id" = user_id + # AND ("todos"."state" IN ('done','pending')) + # AND "todos"."target_id" = merge_request + # AND "todos"."target_type" = 'MergeRequest' ORDER BY "todos"."id" DESC + baseline = ActiveRecord::QueryRecorder.new do + execute_query(query_type, graphql: base_query) + end + + expect do + execute_query(query_type, graphql: query_without_state_arguments) + end.not_to exceed_query_limit(baseline) # at present this is 3 + + expect do + execute_query(query_type, graphql: with_state_arguments) + end.not_to exceed_query_limit(baseline.count + 1) + end + + it 'returns correct data' do + result = execute_query(query_type, + graphql: query_without_state_arguments, + raise_on_error: true).to_h + + expect(result.dig('data', 'a', 'todos', 'nodes')).to contain_exactly( + a_graphql_entity_for(todo_a), + a_graphql_entity_for(todo_b) + ) + expect(result.dig('data', 'b', 'todos', 'nodes')).to contain_exactly( + a_graphql_entity_for(todo_c), + a_graphql_entity_for(todo_d) + ) + expect(result.dig('data', 'c', 'todos', 'nodes')).to contain_exactly( + a_graphql_entity_for(todo_e) + ) + expect(result.dig('data', 'd', 'todos', 'nodes')).to contain_exactly( + a_graphql_entity_for(todo_e) + ) + expect(result.dig('data', 'e', 'todos', 'nodes')).to contain_exactly( + a_graphql_entity_for(todo_a), + a_graphql_entity_for(todo_b) + ) + end + + it 'returns correct data, when state arguments are supplied' do + result = execute_query(query_type, + raise_on_error: true, + graphql: with_state_arguments).to_h + + expect(result.dig('data', 'a', 'todos', 'nodes')).to contain_exactly( + a_graphql_entity_for(todo_a) + ) + expect(result.dig('data', 'b', 'todos', 'nodes')).to contain_exactly( + a_graphql_entity_for(todo_d) + ) + expect(result.dig('data', 'c', 'todos', 'nodes')).to contain_exactly( + a_graphql_entity_for(todo_e) + ) + end + end end diff --git a/spec/graphql/types/customer_relations/contact_type_spec.rb b/spec/graphql/types/customer_relations/contact_type_spec.rb index bb447f405b6..965cc4b60e6 100644 --- a/spec/graphql/types/customer_relations/contact_type_spec.rb +++ b/spec/graphql/types/customer_relations/contact_type_spec.rb @@ -3,7 +3,20 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['CustomerRelationsContact'] do - let(:fields) { %i[id organization first_name last_name phone email description created_at updated_at] } + let(:fields) do + %w[ + id + organization + first_name + last_name + phone + email + description + active + created_at + updated_at + ] + end it { expect(described_class.graphql_name).to eq('CustomerRelationsContact') } it { expect(described_class).to have_graphql_fields(fields) } diff --git a/spec/graphql/types/customer_relations/organization_type_spec.rb b/spec/graphql/types/customer_relations/organization_type_spec.rb index 93844df1239..ae1f41ca098 100644 --- a/spec/graphql/types/customer_relations/organization_type_spec.rb +++ b/spec/graphql/types/customer_relations/organization_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['CustomerRelationsOrganization'] do - let(:fields) { %i[id name default_rate description created_at updated_at] } + let(:fields) { %i[id name default_rate description active created_at updated_at] } it { expect(described_class.graphql_name).to eq('CustomerRelationsOrganization') } it { expect(described_class).to have_graphql_fields(fields) } diff --git a/spec/graphql/types/dependency_proxy/group_setting_type_spec.rb b/spec/graphql/types/dependency_proxy/group_setting_type_spec.rb index 7c6d7b8aece..cd648cf4b4d 100644 --- a/spec/graphql/types/dependency_proxy/group_setting_type_spec.rb +++ b/spec/graphql/types/dependency_proxy/group_setting_type_spec.rb @@ -10,4 +10,10 @@ RSpec.describe GitlabSchema.types['DependencyProxySetting'] do expect(described_class).to include_graphql_fields(*expected_fields) end + + it { expect(described_class).to require_graphql_authorizations(:admin_dependency_proxy) } + + it { expect(described_class.graphql_name).to eq('DependencyProxySetting') } + + it { expect(described_class.description).to eq('Group-level Dependency Proxy settings') } end diff --git a/spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb b/spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb index 46347e0434f..af0f91a844e 100644 --- a/spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb +++ b/spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb @@ -7,7 +7,7 @@ RSpec.describe GitlabSchema.types['DependencyProxyImageTtlGroupPolicy'] do it { expect(described_class.description).to eq('Group-level Dependency Proxy TTL policy settings') } - it { expect(described_class).to require_graphql_authorizations(:read_dependency_proxy) } + it { expect(described_class).to require_graphql_authorizations(:admin_dependency_proxy) } it 'includes dependency proxy image ttl policy fields' do expected_fields = %w[enabled ttl created_at updated_at] diff --git a/spec/graphql/types/duration_type_spec.rb b/spec/graphql/types/duration_type_spec.rb index 5b88819f157..4199e6cc41b 100644 --- a/spec/graphql/types/duration_type_spec.rb +++ b/spec/graphql/types/duration_type_spec.rb @@ -17,11 +17,6 @@ RSpec.describe GitlabSchema.types['Duration'] do expect(described_class.coerce_isolated_input(0.5)).to eq(0.5) end - it 'rejects invalid input' do - expect { described_class.coerce_isolated_input('not valid') } - .to raise_error(GraphQL::CoercionError) - end - it 'rejects nil' do expect { described_class.coerce_isolated_input(nil) } .to raise_error(GraphQL::CoercionError) diff --git a/spec/graphql/types/global_id_type_spec.rb b/spec/graphql/types/global_id_type_spec.rb index 8df92c818fc..a57db9234f1 100644 --- a/spec/graphql/types/global_id_type_spec.rb +++ b/spec/graphql/types/global_id_type_spec.rb @@ -246,131 +246,6 @@ RSpec.describe Types::GlobalIDType do end end - describe 'compatibility' do - def query(doc, vars) - GraphQL::Query.new(schema, document: doc, context: {}, variables: vars) - end - - def run_query(gql_query, vars) - query(GraphQL.parse(gql_query), vars).result - end - - all_types = [::GraphQL::Types::ID, ::Types::GlobalIDType, ::Types::GlobalIDType[::Project]] - - shared_examples 'a working query' do - # Simplified schema to test compatibility - let!(:schema) do - # capture values so they can be closed over - arg_type = argument_type - res_type = result_type - - project = Class.new(GraphQL::Schema::Object) do - graphql_name 'Project' - field :name, String, null: false - field :id, res_type, null: false, resolver_method: :global_id - - def global_id - object.to_global_id - end - end - - Class.new(GraphQL::Schema) do - query(Class.new(GraphQL::Schema::Object) do - graphql_name 'Query' - - field :project_by_id, project, null: true do - argument :id, arg_type, required: true - end - - # This is needed so that all types are always registered as input types - field :echo, String, null: true do - argument :id, ::GraphQL::Types::ID, required: false - argument :gid, ::Types::GlobalIDType, required: false - argument :pid, ::Types::GlobalIDType[::Project], required: false - end - - def project_by_id(id:) - gid = ::Types::GlobalIDType[::Project].coerce_isolated_input(id) - gid.model_class.find(gid.model_id) - end - - def echo(id: nil, gid: nil, pid: nil) - "id: #{id}, gid: #{gid}, pid: #{pid}" - end - end) - end - end - - it 'works' do - res = run_query(document, 'projectId' => project.to_global_id.to_s) - - expect(res['errors']).to be_blank - expect(res.dig('data', 'project', 'name')).to eq(project.name) - expect(res.dig('data', 'project', 'id')).to eq(project.to_global_id.to_s) - end - end - - context 'when the client declares the argument as ID the actual argument can be any type' do - let(:document) do - <<-GRAPHQL - query($projectId: ID!){ - project: projectById(id: $projectId) { - name, id - } - } - GRAPHQL - end - - where(:result_type, :argument_type) do - all_types.flat_map { |arg_type| all_types.zip([arg_type].cycle) } - end - - with_them do - it_behaves_like 'a working query' - end - end - - context 'when the client passes the argument as GlobalID' do - let(:document) do - <<-GRAPHQL - query($projectId: GlobalID!) { - project: projectById(id: $projectId) { - name, id - } - } - GRAPHQL - end - - let(:argument_type) { ::Types::GlobalIDType } - - where(:result_type) { all_types } - - with_them do - it_behaves_like 'a working query' - end - end - - context 'when the client passes the argument as ProjectID' do - let(:document) do - <<-GRAPHQL - query($projectId: ProjectID!) { - project: projectById(id: $projectId) { - name, id - } - } - GRAPHQL - end - - let(:argument_type) { ::Types::GlobalIDType[::Project] } - - where(:result_type) { all_types } - - with_them do - it_behaves_like 'a working query' - end - end - end - describe '.model_name_to_graphql_name' do it 'returns a graphql name for the given model name' do expect(described_class.model_name_to_graphql_name('DesignManagement::Design')).to eq('DesignManagementDesignID') diff --git a/spec/graphql/types/incident_management/timeline_event_type_spec.rb b/spec/graphql/types/incident_management/timeline_event_type_spec.rb new file mode 100644 index 00000000000..5a6bc461f20 --- /dev/null +++ b/spec/graphql/types/incident_management/timeline_event_type_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['TimelineEventType'] do + specify { expect(described_class.graphql_name).to eq('TimelineEventType') } + + specify { expect(described_class).to require_graphql_authorizations(:read_incident_management_timeline_event) } + + it 'exposes the expected fields' do + expected_fields = %i[ + id + author + updated_by_user + incident + note + note_html + promoted_from_note + editable + action + occurred_at + created_at + updated_at + ] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/merge_request_type_spec.rb b/spec/graphql/types/merge_request_type_spec.rb index e9e92bbdc85..7ab254238fb 100644 --- a/spec/graphql/types/merge_request_type_spec.rb +++ b/spec/graphql/types/merge_request_type_spec.rb @@ -34,7 +34,7 @@ RSpec.describe GitlabSchema.types['MergeRequest'] do milestone assignees reviewers participants subscribed labels discussion_locked time_estimate total_time_spent human_time_estimate human_total_time_spent reference author merged_at commit_count current_user_todos conflicts auto_merge_enabled approved_by source_branch_protected - default_merge_commit_message_with_description squash_on_merge available_auto_merge_strategies + 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 ] diff --git a/spec/graphql/types/mutation_type_spec.rb b/spec/graphql/types/mutation_type_spec.rb index 1fc46f2d511..95d835c88cf 100644 --- a/spec/graphql/types/mutation_type_spec.rb +++ b/spec/graphql/types/mutation_type_spec.rb @@ -7,14 +7,6 @@ RSpec.describe Types::MutationType do expect(described_class).to have_graphql_mutation(Mutations::MergeRequests::SetDraft) end - describe 'deprecated mutations' do - describe 'clusterAgentTokenDelete' do - let(:field) { get_field('clusterAgentTokenDelete') } - - it { expect(field.deprecation_reason).to eq('Tokens must be revoked with ClusterAgentTokenRevoke. Deprecated in 14.7.') } - end - end - def get_field(name) described_class.fields[GraphqlHelpers.fieldnamerize(name)] end diff --git a/spec/graphql/types/namespace/package_settings_type_spec.rb b/spec/graphql/types/namespace/package_settings_type_spec.rb index b9592d230ca..f63a0a7010f 100644 --- a/spec/graphql/types/namespace/package_settings_type_spec.rb +++ b/spec/graphql/types/namespace/package_settings_type_spec.rb @@ -7,7 +7,7 @@ RSpec.describe GitlabSchema.types['PackageSettings'] do specify { expect(described_class.description).to eq('Namespace-level Package Registry settings') } - specify { expect(described_class).to require_graphql_authorizations(:read_package_settings) } + specify { expect(described_class).to require_graphql_authorizations(:admin_package) } describe 'maven_duplicate_exception_regex field' do subject { described_class.fields['mavenDuplicateExceptionRegex'] } diff --git a/spec/graphql/types/packages/package_base_type_spec.rb b/spec/graphql/types/packages/package_base_type_spec.rb new file mode 100644 index 00000000000..7156f22c513 --- /dev/null +++ b/spec/graphql/types/packages/package_base_type_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['PackageBase'] do + specify { expect(described_class.description).to eq('Represents a package in the Package Registry') } + + specify { expect(described_class).to require_graphql_authorizations(:read_package) } + + it 'includes all expected fields' do + expected_fields = %w[ + id name version package_type + created_at updated_at + project + tags metadata + status can_destroy + ] + + expect(described_class).to include_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/packages/package_details_type_spec.rb b/spec/graphql/types/packages/package_details_type_spec.rb index ceeb000ff85..d5688fc64c5 100644 --- a/spec/graphql/types/packages/package_details_type_spec.rb +++ b/spec/graphql/types/packages/package_details_type_spec.rb @@ -3,6 +3,10 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['PackageDetailsType'] do + specify { expect(described_class.description).to eq('Represents a package details in the Package Registry') } + + specify { expect(described_class).to require_graphql_authorizations(:read_package) } + it 'includes all the package fields' do expected_fields = %w[ id name version created_at updated_at package_type tags project @@ -13,13 +17,4 @@ RSpec.describe GitlabSchema.types['PackageDetailsType'] do expect(described_class).to include_graphql_fields(*expected_fields) end - - it 'overrides the pipelines field' do - field = described_class.fields['pipelines'] - - expect(field).to have_graphql_type(Types::Ci::PipelineType.connection_type) - expect(field).to have_graphql_extension(Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension) - expect(field).to have_graphql_resolver(Resolvers::PackagePipelinesResolver) - expect(field).not_to be_connection - end end diff --git a/spec/graphql/types/packages/package_type_spec.rb b/spec/graphql/types/packages/package_type_spec.rb index 3267c765dc7..df8135ed87e 100644 --- a/spec/graphql/types/packages/package_type_spec.rb +++ b/spec/graphql/types/packages/package_type_spec.rb @@ -3,12 +3,16 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['Package'] do - it 'includes all the package fields' do + specify { expect(described_class.description).to eq('Represents a package with pipelines in the Package Registry') } + + specify { expect(described_class).to require_graphql_authorizations(:read_package) } + + it 'includes all the package fields and pipelines' do expected_fields = %w[ id name version package_type created_at updated_at project - tags pipelines metadata versions + tags pipelines metadata status can_destroy ] diff --git a/spec/graphql/types/permission_types/work_item_spec.rb b/spec/graphql/types/permission_types/work_item_spec.rb new file mode 100644 index 00000000000..e604ce5d6e0 --- /dev/null +++ b/spec/graphql/types/permission_types/work_item_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::PermissionTypes::WorkItem do + it do + expected_permissions = [ + :read_work_item, :update_work_item, :delete_work_item + ] + + expected_permissions.each do |permission| + expect(described_class).to have_graphql_field(permission) + end + end +end diff --git a/spec/graphql/types/project_statistics_type_spec.rb b/spec/graphql/types/project_statistics_type_spec.rb index f515907b6a8..a958a5150aa 100644 --- a/spec/graphql/types/project_statistics_type_spec.rb +++ b/spec/graphql/types/project_statistics_type_spec.rb @@ -6,6 +6,7 @@ RSpec.describe GitlabSchema.types['ProjectStatistics'] do it 'has all the required fields' do expect(described_class).to have_graphql_fields(:storage_size, :repository_size, :lfs_objects_size, :build_artifacts_size, :packages_size, :commit_count, - :wiki_size, :snippets_size, :pipeline_artifacts_size, :uploads_size) + :wiki_size, :snippets_size, :pipeline_artifacts_size, + :uploads_size, :container_registry_size) end end diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index 7433d465b38..a08bd717c72 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -29,6 +29,7 @@ RSpec.describe GitlabSchema.types['Project'] do grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments environment boards jira_import_status jira_imports services releases release alert_management_alerts alert_management_alert alert_management_alert_status_counts + incident_management_timeline_event incident_management_timeline_events container_expiration_policy service_desk_enabled service_desk_address issue_status_counts terraform_states alert_management_integrations container_repositories container_repositories_count diff --git a/spec/graphql/types/projects/topic_type_spec.rb b/spec/graphql/types/projects/topic_type_spec.rb index 01c19e111be..318307fa6f4 100644 --- a/spec/graphql/types/projects/topic_type_spec.rb +++ b/spec/graphql/types/projects/topic_type_spec.rb @@ -9,6 +9,7 @@ RSpec.describe Types::Projects::TopicType do expect(described_class).to have_graphql_fields( :id, :name, + :title, :description, :description_html, :avatar_url diff --git a/spec/graphql/types/range_input_type_spec.rb b/spec/graphql/types/range_input_type_spec.rb index dbfcf4a41c7..239f4e4ba15 100644 --- a/spec/graphql/types/range_input_type_spec.rb +++ b/spec/graphql/types/range_input_type_spec.rb @@ -12,7 +12,7 @@ RSpec.describe ::Types::RangeInputType do input = { start: 1, end: 10 } output = { start: 1, end: 10 } - expect(type.coerce_isolated_input(input)).to eq(output) + expect(type.coerce_isolated_input(input).to_h).to eq(output) end it 'rejects inverted ranges' do @@ -28,7 +28,7 @@ RSpec.describe ::Types::RangeInputType do values: {}, object: nil ) - instance = described_class[of_integer].new(context: context, defaults_used: [], ruby_kwargs: {}) + instance = described_class[of_integer].new({}, context: context, defaults_used: [], ruby_kwargs: {}) expect(instance).to be_a_kind_of(described_class) expect(instance).to be_a_kind_of(described_class[of_integer]) diff --git a/spec/graphql/types/root_storage_statistics_type_spec.rb b/spec/graphql/types/root_storage_statistics_type_spec.rb index 7818be6ee02..07c8378e7a6 100644 --- a/spec/graphql/types/root_storage_statistics_type_spec.rb +++ b/spec/graphql/types/root_storage_statistics_type_spec.rb @@ -8,7 +8,8 @@ RSpec.describe GitlabSchema.types['RootStorageStatistics'] do it 'has all the required fields' do expect(described_class).to have_graphql_fields(:storage_size, :repository_size, :lfs_objects_size, :build_artifacts_size, :packages_size, :wiki_size, :snippets_size, - :pipeline_artifacts_size, :uploads_size, :dependency_proxy_size) + :pipeline_artifacts_size, :uploads_size, :dependency_proxy_size, + :container_registry_size) end specify { expect(described_class).to require_graphql_authorizations(:read_statistics) } diff --git a/spec/graphql/types/terraform/state_version_type_spec.rb b/spec/graphql/types/terraform/state_version_type_spec.rb index b015a2045da..6a17d932d03 100644 --- a/spec/graphql/types/terraform/state_version_type_spec.rb +++ b/spec/graphql/types/terraform/state_version_type_spec.rb @@ -52,8 +52,8 @@ RSpec.describe GitlabSchema.types['TerraformStateVersion'] do shared_examples 'returning latest version' do it 'returns latest version of terraform state' do - expect(execute.dig('data', 'project', 'terraformState', 'latestVersion', 'id')).to eq( - global_id_of(terraform_state.latest_version) + expect(execute.dig('data', 'project', 'terraformState', 'latestVersion')).to match a_graphql_entity_for( + terraform_state.latest_version ) end end diff --git a/spec/graphql/types/timeframe_type_spec.rb b/spec/graphql/types/timeframe_type_spec.rb index dfde3242897..288124ad24b 100644 --- a/spec/graphql/types/timeframe_type_spec.rb +++ b/spec/graphql/types/timeframe_type_spec.rb @@ -7,7 +7,7 @@ RSpec.describe GitlabSchema.types['Timeframe'] do let(:output) { { start: Date.parse(input[:start]), end: Date.parse(input[:end]) } } it 'coerces ISO-dates into Time objects' do - expect(described_class.coerce_isolated_input(input)).to eq(output) + expect(described_class.coerce_isolated_input(input).to_h).to eq(output) end it 'rejects invalid input' do @@ -20,7 +20,7 @@ RSpec.describe GitlabSchema.types['Timeframe'] do it 'accepts times as input' do with_time = input.merge(start: '2018-06-04T13:48:14Z') - expect(described_class.coerce_isolated_input(with_time)).to eq(output) + expect(described_class.coerce_isolated_input(with_time).to_h).to eq(output) end it 'requires both ends of the range' do diff --git a/spec/graphql/types/timelog_type_spec.rb b/spec/graphql/types/timelog_type_spec.rb index dc1b1e2253e..c897a25d10d 100644 --- a/spec/graphql/types/timelog_type_spec.rb +++ b/spec/graphql/types/timelog_type_spec.rb @@ -3,11 +3,12 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['Timelog'] do - let(:fields) { %i[spent_at time_spent user issue merge_request note summary] } + let_it_be(:fields) { %i[id spent_at time_spent user issue merge_request note summary userPermissions] } it { expect(described_class.graphql_name).to eq('Timelog') } it { expect(described_class).to have_graphql_fields(fields) } it { expect(described_class).to require_graphql_authorizations(:read_issue) } + it { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Timelog) } describe 'user field' do subject { described_class.fields['user'] } diff --git a/spec/graphql/types/user_merge_request_interaction_type_spec.rb b/spec/graphql/types/user_merge_request_interaction_type_spec.rb index 1eaaa0c23d0..4782a1faf8d 100644 --- a/spec/graphql/types/user_merge_request_interaction_type_spec.rb +++ b/spec/graphql/types/user_merge_request_interaction_type_spec.rb @@ -76,6 +76,7 @@ RSpec.describe GitlabSchema.types['UserMergeRequestInteraction'] do context 'when the user has been asked to review the MR' do before do merge_request.reviewers << user + merge_request.find_reviewer(user).update!(state: :attention_requested) end it { is_expected.to eq(Types::MergeRequestReviewStateEnum.values['ATTENTION_REQUESTED'].value) } diff --git a/spec/graphql/types/work_item_type_spec.rb b/spec/graphql/types/work_item_type_spec.rb index 6a5b4a0882e..a0480506156 100644 --- a/spec/graphql/types/work_item_type_spec.rb +++ b/spec/graphql/types/work_item_type_spec.rb @@ -7,8 +7,10 @@ RSpec.describe GitlabSchema.types['WorkItem'] do specify { expect(described_class).to require_graphql_authorizations(:read_work_item) } + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::WorkItem) } + it 'has specific fields' do - fields = %i[description description_html id iid lock_version state title title_html work_item_type] + fields = %i[description description_html id iid lock_version state title title_html userPermissions work_item_type] fields.each do |field_name| expect(described_class).to have_graphql_fields(*fields) |