summaryrefslogtreecommitdiff
path: root/spec/graphql
diff options
context:
space:
mode:
Diffstat (limited to 'spec/graphql')
-rw-r--r--spec/graphql/mutations/base_mutation_spec.rb2
-rw-r--r--spec/graphql/mutations/boards/update_spec.rb8
-rw-r--r--spec/graphql/mutations/ci/runner/delete_spec.rb8
-rw-r--r--spec/graphql/mutations/ci/runner/update_spec.rb8
-rw-r--r--spec/graphql/mutations/clusters/agent_tokens/create_spec.rb8
-rw-r--r--spec/graphql/mutations/clusters/agent_tokens/delete_spec.rb52
-rw-r--r--spec/graphql/mutations/clusters/agent_tokens/revoke_spec.rb10
-rw-r--r--spec/graphql/mutations/clusters/agents/delete_spec.rb9
-rw-r--r--spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb2
-rw-r--r--spec/graphql/mutations/container_expiration_policies/update_spec.rb6
-rw-r--r--spec/graphql/mutations/container_repositories/destroy_spec.rb8
-rw-r--r--spec/graphql/mutations/container_repositories/destroy_tags_spec.rb8
-rw-r--r--spec/graphql/mutations/customer_relations/contacts/create_spec.rb6
-rw-r--r--spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb2
-rw-r--r--spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb4
-rw-r--r--spec/graphql/mutations/discussions/toggle_resolve_spec.rb17
-rw-r--r--spec/graphql/mutations/environments/canary_ingress/update_spec.rb10
-rw-r--r--spec/graphql/mutations/incident_management/timeline_event/create_spec.rb51
-rw-r--r--spec/graphql/mutations/incident_management/timeline_event/destroy_spec.rb66
-rw-r--r--spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb85
-rw-r--r--spec/graphql/mutations/incident_management/timeline_event/update_spec.rb100
-rw-r--r--spec/graphql/mutations/issues/set_due_date_spec.rb2
-rw-r--r--spec/graphql/mutations/merge_requests/accept_spec.rb3
-rw-r--r--spec/graphql/mutations/merge_requests/create_spec.rb4
-rw-r--r--spec/graphql/mutations/namespace/package_settings/update_spec.rb6
-rw-r--r--spec/graphql/mutations/release_asset_links/delete_spec.rb12
-rw-r--r--spec/graphql/mutations/release_asset_links/update_spec.rb12
-rw-r--r--spec/graphql/mutations/timelogs/delete_spec.rb93
-rw-r--r--spec/graphql/mutations/todos/create_spec.rb15
-rw-r--r--spec/graphql/mutations/todos/mark_done_spec.rb9
-rw-r--r--spec/graphql/mutations/todos/restore_many_spec.rb7
-rw-r--r--spec/graphql/mutations/todos/restore_spec.rb9
-rw-r--r--spec/graphql/resolvers/alert_management/alert_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/ci/config_resolver_spec.rb7
-rw-r--r--spec/graphql/resolvers/concerns/resolves_ids_spec.rb19
-rw-r--r--spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/design_management/design_resolver_spec.rb13
-rw-r--r--spec/graphql/resolvers/design_management/designs_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb9
-rw-r--r--spec/graphql/resolvers/design_management/versions_resolver_spec.rb11
-rw-r--r--spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb50
-rw-r--r--spec/graphql/resolvers/error_tracking/sentry_error_collection_resolver_spec.rb17
-rw-r--r--spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb31
-rw-r--r--spec/graphql/resolvers/incident_management/timeline_events_resolver_spec.rb70
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb34
-rw-r--r--spec/graphql/resolvers/package_pipelines_resolver_spec.rb147
-rw-r--r--spec/graphql/resolvers/projects/snippets_resolver_spec.rb6
-rw-r--r--spec/graphql/resolvers/snippets_resolver_spec.rb22
-rw-r--r--spec/graphql/resolvers/timelog_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/users/snippets_resolver_spec.rb10
-rw-r--r--spec/graphql/resolvers/work_item_resolver_spec.rb2
-rw-r--r--spec/graphql/subscriptions/issuable_updated_spec.rb8
-rw-r--r--spec/graphql/types/alert_management/domain_filter_enum_spec.rb2
-rw-r--r--spec/graphql/types/ci/config/config_type_spec.rb1
-rw-r--r--spec/graphql/types/ci/config/include_type_enum_spec.rb11
-rw-r--r--spec/graphql/types/ci/config/include_type_spec.rb21
-rw-r--r--spec/graphql/types/ci/runner_type_spec.rb4
-rw-r--r--spec/graphql/types/ci/runner_upgrade_status_type_enum_spec.rb13
-rw-r--r--spec/graphql/types/color_type_spec.rb38
-rw-r--r--spec/graphql/types/container_expiration_policy_type_spec.rb2
-rw-r--r--spec/graphql/types/container_repository_details_type_spec.rb2
-rw-r--r--spec/graphql/types/container_repository_type_spec.rb2
-rw-r--r--spec/graphql/types/current_user_todos_type_spec.rb207
-rw-r--r--spec/graphql/types/customer_relations/contact_type_spec.rb15
-rw-r--r--spec/graphql/types/customer_relations/organization_type_spec.rb2
-rw-r--r--spec/graphql/types/dependency_proxy/group_setting_type_spec.rb6
-rw-r--r--spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb2
-rw-r--r--spec/graphql/types/duration_type_spec.rb5
-rw-r--r--spec/graphql/types/global_id_type_spec.rb125
-rw-r--r--spec/graphql/types/incident_management/timeline_event_type_spec.rb28
-rw-r--r--spec/graphql/types/merge_request_type_spec.rb2
-rw-r--r--spec/graphql/types/mutation_type_spec.rb8
-rw-r--r--spec/graphql/types/namespace/package_settings_type_spec.rb2
-rw-r--r--spec/graphql/types/packages/package_base_type_spec.rb21
-rw-r--r--spec/graphql/types/packages/package_details_type_spec.rb13
-rw-r--r--spec/graphql/types/packages/package_type_spec.rb8
-rw-r--r--spec/graphql/types/permission_types/work_item_spec.rb15
-rw-r--r--spec/graphql/types/project_statistics_type_spec.rb3
-rw-r--r--spec/graphql/types/project_type_spec.rb1
-rw-r--r--spec/graphql/types/projects/topic_type_spec.rb1
-rw-r--r--spec/graphql/types/range_input_type_spec.rb4
-rw-r--r--spec/graphql/types/root_storage_statistics_type_spec.rb3
-rw-r--r--spec/graphql/types/terraform/state_version_type_spec.rb4
-rw-r--r--spec/graphql/types/timeframe_type_spec.rb4
-rw-r--r--spec/graphql/types/timelog_type_spec.rb3
-rw-r--r--spec/graphql/types/user_merge_request_interaction_type_spec.rb1
-rw-r--r--spec/graphql/types/work_item_type_spec.rb4
87 files changed, 1147 insertions, 546 deletions
diff --git a/spec/graphql/mutations/base_mutation_spec.rb b/spec/graphql/mutations/base_mutation_spec.rb
index 7939fadb37b..6b366b0c234 100644
--- a/spec/graphql/mutations/base_mutation_spec.rb
+++ b/spec/graphql/mutations/base_mutation_spec.rb
@@ -15,6 +15,7 @@ RSpec.describe ::Mutations::BaseMutation do
context 'when argument is nullable and required' do
let(:mutation_class) do
Class.new(described_class) do
+ graphql_name 'BaseMutation'
argument :foo, GraphQL::Types::String, required: :nullable
end
end
@@ -35,6 +36,7 @@ RSpec.describe ::Mutations::BaseMutation do
context 'when argument is required and NOT nullable' do
let(:mutation_class) do
Class.new(described_class) do
+ graphql_name 'BaseMutation'
argument :foo, GraphQL::Types::String, required: true
end
end
diff --git a/spec/graphql/mutations/boards/update_spec.rb b/spec/graphql/mutations/boards/update_spec.rb
index da3dfeecd4d..4785bc94624 100644
--- a/spec/graphql/mutations/boards/update_spec.rb
+++ b/spec/graphql/mutations/boards/update_spec.rb
@@ -29,14 +29,6 @@ RSpec.describe Mutations::Boards::Update do
end
end
- context 'with invalid params' do
- it 'raises an error' do
- mutation_params[:id] = project.to_global_id
-
- expect { subject }.to raise_error(::GraphQL::CoercionError)
- end
- end
-
context 'when user can update board' do
before do
board.resource_parent.add_reporter(user)
diff --git a/spec/graphql/mutations/ci/runner/delete_spec.rb b/spec/graphql/mutations/ci/runner/delete_spec.rb
index ee640b21918..06d360430f8 100644
--- a/spec/graphql/mutations/ci/runner/delete_spec.rb
+++ b/spec/graphql/mutations/ci/runner/delete_spec.rb
@@ -44,14 +44,6 @@ RSpec.describe Mutations::Ci::Runner::Delete do
end
end
- context 'with invalid params' do
- let(:mutation_params) { { id: "invalid-id" } }
-
- it 'raises an error' do
- expect { subject }.to raise_error(::GraphQL::CoercionError)
- end
- end
-
context 'when required arguments are missing' do
let(:mutation_params) { {} }
diff --git a/spec/graphql/mutations/ci/runner/update_spec.rb b/spec/graphql/mutations/ci/runner/update_spec.rb
index 0b3489d37dc..75e9b57e60a 100644
--- a/spec/graphql/mutations/ci/runner/update_spec.rb
+++ b/spec/graphql/mutations/ci/runner/update_spec.rb
@@ -33,14 +33,6 @@ RSpec.describe Mutations::Ci::Runner::Update do
end
end
- context 'with invalid params' do
- it 'raises an error' do
- mutation_params[:id] = "invalid-id"
-
- expect { subject }.to raise_error(::GraphQL::CoercionError)
- end
- end
-
context 'when required arguments are missing' do
let(:mutation_params) { {} }
diff --git a/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb b/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb
index fc025c8e3d3..45d421509d0 100644
--- a/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb
+++ b/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb
@@ -48,14 +48,6 @@ RSpec.describe Mutations::Clusters::AgentTokens::Create do
expect(token.description).to eq(description)
expect(token.name).to eq(name)
end
-
- context 'invalid params' do
- subject { mutation.resolve(cluster_agent_id: cluster_agent.id) }
-
- it 'generates an error message when id invalid', :aggregate_failures do
- expect { subject }.to raise_error(::GraphQL::CoercionError)
- end
- end
end
end
end
diff --git a/spec/graphql/mutations/clusters/agent_tokens/delete_spec.rb b/spec/graphql/mutations/clusters/agent_tokens/delete_spec.rb
deleted file mode 100644
index 5cdbc0f6d72..00000000000
--- a/spec/graphql/mutations/clusters/agent_tokens/delete_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Mutations::Clusters::AgentTokens::Delete do
- let(:token) { create(:cluster_agent_token) }
- let(:user) { create(:user) }
-
- let(:mutation) do
- described_class.new(
- object: double,
- context: { current_user: user },
- field: double
- )
- end
-
- it { expect(described_class.graphql_name).to eq('ClusterAgentTokenDelete') }
- it { expect(described_class).to require_graphql_authorizations(:admin_cluster) }
-
- describe '#resolve' do
- let(:global_id) { token.to_global_id }
-
- subject { mutation.resolve(id: global_id) }
-
- context 'without user permissions' do
- it 'fails to delete the cluster agent', :aggregate_failures do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
- expect { token.reload }.not_to raise_error
- end
- end
-
- context 'with user permissions' do
- before do
- token.agent.project.add_maintainer(user)
- end
-
- it 'deletes a cluster agent', :aggregate_failures do
- expect { subject }.to change { ::Clusters::AgentToken.count }.by(-1)
- expect { token.reload }.to raise_error(ActiveRecord::RecordNotFound)
- end
- end
-
- context 'with invalid params' do
- let(:global_id) { token.id }
-
- it 'raises an error if the cluster agent id is invalid', :aggregate_failures do
- expect { subject }.to raise_error(::GraphQL::CoercionError)
- expect { token.reload }.not_to raise_error
- end
- end
- end
-end
diff --git a/spec/graphql/mutations/clusters/agent_tokens/revoke_spec.rb b/spec/graphql/mutations/clusters/agent_tokens/revoke_spec.rb
index f5f4c0cefad..1dd4eece246 100644
--- a/spec/graphql/mutations/clusters/agent_tokens/revoke_spec.rb
+++ b/spec/graphql/mutations/clusters/agent_tokens/revoke_spec.rb
@@ -40,16 +40,6 @@ RSpec.describe Mutations::Clusters::AgentTokens::Revoke do
expect(token.reload).to be_revoked
end
-
- context 'supplied ID is invalid' do
- let(:global_id) { token.id }
-
- it 'raises a coercion error' do
- expect { subject }.to raise_error(::GraphQL::CoercionError)
-
- expect(token.reload).not_to be_revoked
- end
- end
end
end
end
diff --git a/spec/graphql/mutations/clusters/agents/delete_spec.rb b/spec/graphql/mutations/clusters/agents/delete_spec.rb
index 0aabf53391a..e0ecff5fe44 100644
--- a/spec/graphql/mutations/clusters/agents/delete_spec.rb
+++ b/spec/graphql/mutations/clusters/agents/delete_spec.rb
@@ -38,14 +38,5 @@ RSpec.describe Mutations::Clusters::Agents::Delete do
expect { cluster_agent.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
-
- context 'with invalid params' do
- subject { mutation.resolve(id: cluster_agent.id) }
-
- it 'raises an error if the cluster agent id is invalid', :aggregate_failures do
- expect { subject }.to raise_error(::GraphQL::CoercionError)
- expect { cluster_agent.reload }.not_to raise_error
- end
- end
end
end
diff --git a/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb b/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb
index 37e0fd611e4..451f6d1fe06 100644
--- a/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb
+++ b/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Mutations::FindsByGid do
end
end
- let(:query) { double('Query', schema: GitlabSchema) }
+ let(:query) { query_double(schema: GitlabSchema) }
let(:context) { GraphQL::Query::Context.new(query: query, object: nil, values: { current_user: user }) }
let(:user) { create(:user) }
let(:gid) { user.to_global_id }
diff --git a/spec/graphql/mutations/container_expiration_policies/update_spec.rb b/spec/graphql/mutations/container_expiration_policies/update_spec.rb
index e22fb951172..e070336ef76 100644
--- a/spec/graphql/mutations/container_expiration_policies/update_spec.rb
+++ b/spec/graphql/mutations/container_expiration_policies/update_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Mutations::ContainerExpirationPolicies::Update do
let(:container_expiration_policy) { project.container_expiration_policy }
let(:params) { { project_path: project.full_path, cadence: '3month', keep_n: 100, older_than: '14d' } }
- specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) }
+ specify { expect(described_class).to require_graphql_authorizations(:admin_container_image) }
describe '#resolve' do
subject { described_class.new(object: project, context: { current_user: user }, field: nil).resolve(**params) }
@@ -76,7 +76,7 @@ RSpec.describe Mutations::ContainerExpirationPolicies::Update do
context 'with existing container expiration policy' do
where(:user_role, :shared_examples_name) do
:maintainer | 'updating the container expiration policy'
- :developer | 'updating the container expiration policy'
+ :developer | 'denying access to container expiration policy'
:reporter | 'denying access to container expiration policy'
:guest | 'denying access to container expiration policy'
:anonymous | 'denying access to container expiration policy'
@@ -96,7 +96,7 @@ RSpec.describe Mutations::ContainerExpirationPolicies::Update do
where(:user_role, :shared_examples_name) do
:maintainer | 'creating the container expiration policy'
- :developer | 'creating the container expiration policy'
+ :developer | 'denying access to container expiration policy'
:reporter | 'denying access to container expiration policy'
:guest | 'denying access to container expiration policy'
:anonymous | 'denying access to container expiration policy'
diff --git a/spec/graphql/mutations/container_repositories/destroy_spec.rb b/spec/graphql/mutations/container_repositories/destroy_spec.rb
index 3903196a511..97da7846339 100644
--- a/spec/graphql/mutations/container_repositories/destroy_spec.rb
+++ b/spec/graphql/mutations/container_repositories/destroy_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Mutations::ContainerRepositories::Destroy do
let_it_be(:user) { create(:user) }
let(:project) { container_repository.project }
- let(:id) { container_repository.to_global_id.to_s }
+ let(:id) { container_repository.to_global_id }
specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) }
@@ -57,11 +57,5 @@ RSpec.describe Mutations::ContainerRepositories::Destroy do
it_behaves_like params[:shared_examples_name]
end
end
-
- context 'with invalid id' do
- let(:id) { 'gid://gitlab/ContainerRepository/5555' }
-
- it_behaves_like 'denying access to container respository'
- end
end
end
diff --git a/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb b/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb
index f22d9ffe753..3e5f28ee244 100644
--- a/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb
+++ b/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb
@@ -3,10 +3,12 @@
require 'spec_helper'
RSpec.describe Mutations::ContainerRepositories::DestroyTags do
+ include GraphqlHelpers
+
include_context 'container repository delete tags service shared context'
using RSpec::Parameterized::TableSyntax
- let(:id) { repository.to_global_id.to_s }
+ let(:id) { repository.to_global_id }
specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) }
@@ -67,8 +69,8 @@ RSpec.describe Mutations::ContainerRepositories::DestroyTags do
end
end
- context 'with invalid id' do
- let(:id) { 'gid://gitlab/ContainerRepository/5555' }
+ context 'with non-existing id' do
+ let(:id) { global_id_of(id: non_existing_record_id, model_name: 'ContainerRepository') }
it_behaves_like 'denying access to container respository'
end
diff --git a/spec/graphql/mutations/customer_relations/contacts/create_spec.rb b/spec/graphql/mutations/customer_relations/contacts/create_spec.rb
index d17d11305b1..dafc7b4c367 100644
--- a/spec/graphql/mutations/customer_relations/contacts/create_spec.rb
+++ b/spec/graphql/mutations/customer_relations/contacts/create_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::CustomerRelations::Contacts::Create do
+ include GraphqlHelpers
+
let_it_be(:user) { create(:user) }
let(:group) { create(:group, :crm_enabled) }
@@ -78,9 +80,9 @@ RSpec.describe Mutations::CustomerRelations::Contacts::Create do
end
end
- context 'when organization_id is invalid' do
+ context 'when organization does not exist' do
before do
- valid_params[:organization_id] = "gid://gitlab/CustomerRelations::Organization/#{non_existing_record_id}"
+ valid_params[:organization_id] = global_id_of(model_name: 'CustomerRelations::Organization', id: non_existing_record_id)
end
it 'returns the relevant error' do
diff --git a/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb b/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
index 35d3224d5ba..ae368e4d37e 100644
--- a/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
+++ b/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
@@ -37,7 +37,7 @@ RSpec.describe Mutations::DependencyProxy::GroupSettings::Update do
where(:user_role, :shared_examples_name) do
:maintainer | 'updating the dependency proxy group settings'
- :developer | 'updating the dependency proxy group settings'
+ :developer | 'denying access to dependency proxy group settings'
:reporter | 'denying access to dependency proxy group settings'
:guest | 'denying access to dependency proxy group settings'
:anonymous | 'denying access to dependency proxy group settings'
diff --git a/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb b/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
index 792e87f0d25..1e5059d7ef7 100644
--- a/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
+++ b/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe Mutations::DependencyProxy::ImageTtlGroupPolicy::Update do
where(:user_role, :shared_examples_name) do
:maintainer | 'updating the dependency proxy image ttl policy'
- :developer | 'updating the dependency proxy image ttl policy'
+ :developer | 'denying access to dependency proxy image ttl policy'
:reporter | 'denying access to dependency proxy image ttl policy'
:guest | 'denying access to dependency proxy image ttl policy'
:anonymous | 'denying access to dependency proxy image ttl policy'
@@ -92,7 +92,7 @@ RSpec.describe Mutations::DependencyProxy::ImageTtlGroupPolicy::Update do
where(:user_role, :shared_examples_name) do
:maintainer | 'creating the dependency proxy image ttl policy'
- :developer | 'creating the dependency proxy image ttl policy'
+ :developer | 'denying access to dependency proxy image ttl policy'
:reporter | 'denying access to dependency proxy image ttl policy'
:guest | 'denying access to dependency proxy image ttl policy'
:anonymous | 'denying access to dependency proxy image ttl policy'
diff --git a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb
index 2041b86d6e7..3f7347798e5 100644
--- a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb
+++ b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::Discussions::ToggleResolve do
+ include GraphqlHelpers
+
subject(:mutation) do
described_class.new(object: nil, context: { current_user: user }, field: nil)
end
@@ -15,7 +17,7 @@ RSpec.describe Mutations::Discussions::ToggleResolve do
mutation.resolve(id: id_arg, resolve: resolve_arg)
end
- let(:id_arg) { discussion.to_global_id.to_s }
+ let(:id_arg) { global_id_of(discussion) }
let(:resolve_arg) { true }
let(:mutated_discussion) { subject[:discussion] }
let(:errors) { subject[:errors] }
@@ -36,7 +38,7 @@ RSpec.describe Mutations::Discussions::ToggleResolve do
let_it_be(:user) { create(:user, developer_projects: [project]) }
context 'when discussion cannot be found' do
- let(:id_arg) { "#{discussion.to_global_id}foo" }
+ let(:id_arg) { global_id_of(id: non_existing_record_id, model_name: discussion.class.name) }
it 'raises an error' do
expect { subject }.to raise_error(
@@ -46,17 +48,6 @@ RSpec.describe Mutations::Discussions::ToggleResolve do
end
end
- context 'when discussion is not a Discussion' do
- let(:discussion) { create(:note, noteable: noteable, project: project) }
-
- it 'raises an error' do
- expect { subject }.to raise_error(
- GraphQL::CoercionError,
- "\"#{discussion.to_global_id}\" does not represent an instance of Discussion"
- )
- end
- end
-
shared_examples 'returns a resolved discussion without errors' do
it 'returns a resolved discussion' do
expect(mutated_discussion).to be_resolved
diff --git a/spec/graphql/mutations/environments/canary_ingress/update_spec.rb b/spec/graphql/mutations/environments/canary_ingress/update_spec.rb
index fdf9cbaf25b..b93fb36a8ff 100644
--- a/spec/graphql/mutations/environments/canary_ingress/update_spec.rb
+++ b/spec/graphql/mutations/environments/canary_ingress/update_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Mutations::Environments::CanaryIngress::Update do
describe '#resolve' do
subject { mutation.resolve(id: environment_id, weight: weight) }
- let(:environment_id) { environment.to_global_id.to_s }
+ let(:environment_id) { environment.to_global_id }
let(:weight) { 50 }
let(:update_service) { double('update_service') }
@@ -62,14 +62,6 @@ RSpec.describe Mutations::Environments::CanaryIngress::Update do
end
end
- context 'when environment is not found' do
- let(:environment_id) { non_existing_record_id.to_s }
-
- it 'raises an error' do
- expect { subject }.to raise_error(GraphQL::CoercionError)
- end
- end
-
context 'when user is reporter who does not have permission to access the environment' do
let(:user) { reporter }
diff --git a/spec/graphql/mutations/incident_management/timeline_event/create_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/create_spec.rb
new file mode 100644
index 00000000000..63faecad5d5
--- /dev/null
+++ b/spec/graphql/mutations/incident_management/timeline_event/create_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::IncidentManagement::TimelineEvent::Create do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+
+ let(:args) { { note: 'note', occurred_at: Time.current } }
+
+ specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event) }
+
+ describe '#resolve' do
+ subject(:resolve) { mutation_for(project, current_user).resolve(incident_id: incident.to_global_id, **args) }
+
+ context 'when a user has permissions to create a timeline event' do
+ let(:expected_timeline_event) do
+ instance_double(
+ 'IncidentManagement::TimelineEvent',
+ note: args[:note],
+ occurred_at: args[:occurred_at].to_s,
+ incident: incident,
+ author: current_user,
+ promoted_from_note: nil
+ )
+ end
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ it_behaves_like 'creating an incident timeline event'
+
+ context 'when TimelineEvents::CreateService responds with an error' do
+ let(:args) { {} }
+
+ it_behaves_like 'responding with an incident timeline errors',
+ errors: ["Occurred at can't be blank, Note can't be blank, and Note html can't be blank"]
+ end
+ end
+
+ it_behaves_like 'failing to create an incident timeline event'
+ end
+
+ private
+
+ def mutation_for(project, user)
+ described_class.new(object: project, context: { current_user: user }, field: nil)
+ end
+end
diff --git a/spec/graphql/mutations/incident_management/timeline_event/destroy_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/destroy_spec.rb
new file mode 100644
index 00000000000..4dd7b2ccb14
--- /dev/null
+++ b/spec/graphql/mutations/incident_management/timeline_event/destroy_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::IncidentManagement::TimelineEvent::Destroy do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+
+ let(:timeline_event) { create(:incident_management_timeline_event, incident: incident, project: project) }
+ let(:args) { { id: timeline_event.to_global_id } }
+
+ specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event) }
+
+ describe '#resolve' do
+ subject(:resolve) { mutation_for(project, current_user).resolve(**args) }
+
+ context 'when a user has permissions to delete timeline event' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ context 'when TimelineEvents::DestroyService responds with success' do
+ it 'returns the timeline event with no errors' do
+ expect(resolve).to eq(
+ timeline_event: timeline_event,
+ errors: []
+ )
+ end
+ end
+
+ context 'when TimelineEvents::DestroyService responds with an error' do
+ before do
+ allow_next_instance_of(::IncidentManagement::TimelineEvents::DestroyService) do |service|
+ allow(service)
+ .to receive(:execute)
+ .and_return(ServiceResponse.error(payload: { timeline_event: nil }, message: 'An error has occurred'))
+ end
+ end
+
+ it 'returns errors' do
+ expect(resolve).to eq(
+ timeline_event: nil,
+ errors: ['An error has occurred']
+ )
+ end
+ end
+ end
+
+ context 'when a user has no permissions to delete timeline event' do
+ before do
+ project.add_guest(current_user)
+ end
+
+ it 'raises an error' do
+ expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+
+ private
+
+ def mutation_for(project, user)
+ described_class.new(object: project, context: { current_user: user }, field: nil)
+ end
+end
diff --git a/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
new file mode 100644
index 00000000000..598ee496cf1
--- /dev/null
+++ b/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::IncidentManagement::TimelineEvent::PromoteFromNote do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:comment) { create(:note, project: project, noteable: incident) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:issue_comment) { create(:note, project: project, noteable: issue) }
+ let_it_be(:alert) { create(:alert_management_alert, project: project) }
+ let_it_be(:alert_comment) { create(:note, project: project, noteable: alert) }
+
+ let(:args) { { note_id: comment.to_global_id.to_s } }
+
+ specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event) }
+
+ describe '#resolve' do
+ subject(:resolve) { mutation_for(project, current_user).resolve(**args) }
+
+ context 'when a user has permissions to create timeline event' do
+ let(:expected_timeline_event) do
+ instance_double(
+ 'IncidentManagement::TimelineEvent',
+ note: comment.note,
+ occurred_at: comment.created_at.to_s,
+ incident: incident,
+ author: current_user,
+ promoted_from_note: comment
+ )
+ end
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ it_behaves_like 'creating an incident timeline event'
+
+ context 'when TimelineEvents::CreateService responds with an error' do
+ before do
+ allow_next_instance_of(::IncidentManagement::TimelineEvents::CreateService) do |service|
+ allow(service).to receive(:execute).and_return(
+ ServiceResponse.error(payload: { timeline_event: nil }, message: 'Some error')
+ )
+ end
+ end
+
+ it_behaves_like 'responding with an incident timeline errors', errors: ['Some error']
+ end
+ end
+
+ context 'when note does not exist' do
+ let(:args) { { note_id: 'gid://gitlab/Note/0' } }
+
+ it 'raises an error' do
+ expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when note does not belong to an incident' do
+ let(:args) { { note_id: issue_comment.to_global_id.to_s } }
+
+ it 'raises an error' do
+ expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when note belongs to anything else but issuable' do
+ let(:args) { { note_id: alert_comment.to_global_id.to_s } }
+
+ it 'raises an error' do
+ expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ it_behaves_like 'failing to create an incident timeline event'
+ end
+
+ private
+
+ def mutation_for(project, user)
+ described_class.new(object: project, context: { current_user: user }, field: nil)
+ end
+end
diff --git a/spec/graphql/mutations/incident_management/timeline_event/update_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/update_spec.rb
new file mode 100644
index 00000000000..8296e5c6c15
--- /dev/null
+++ b/spec/graphql/mutations/incident_management/timeline_event/update_spec.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::IncidentManagement::TimelineEvent::Update do
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be_with_reload(:timeline_event) do
+ create(:incident_management_timeline_event, project: project, incident: incident)
+ end
+
+ let(:args) do
+ {
+ id: timeline_event_id,
+ note: note,
+ occurred_at: occurred_at
+ }
+ end
+
+ let(:note) { 'Updated Note' }
+ let(:timeline_event_id) { GitlabSchema.id_from_object(timeline_event).to_s }
+ let(:occurred_at) { 1.minute.ago }
+
+ before do
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ end
+
+ describe '#resolve' do
+ let(:current_user) { developer }
+
+ subject(:resolve) { mutation_for(current_user).resolve(**args) }
+
+ shared_examples 'failed update with a top-level access error' do |error|
+ specify do
+ expect { resolve }.to raise_error(
+ Gitlab::Graphql::Errors::ResourceNotAvailable,
+ error || Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR
+ )
+ end
+ end
+
+ context 'when user has permissions to update the timeline event' do
+ context 'when timeline event exists' do
+ it 'updates the timeline event' do
+ expect { resolve }.to change { timeline_event.reload.note }.to(note)
+ .and change { timeline_event.reload.occurred_at.to_s }.to(occurred_at.to_s)
+ end
+
+ it 'returns updated timeline event' do
+ expect(resolve).to eq(
+ timeline_event: timeline_event.reload,
+ errors: []
+ )
+ end
+
+ context 'when there is a validation error' do
+ let(:occurred_at) { 'invalid date' }
+
+ it 'does not update the timeline event' do
+ expect { resolve }.not_to change { timeline_event.reload.updated_at }
+ end
+
+ it 'responds with error' do
+ expect(resolve).to eq(
+ timeline_event: nil,
+ errors: ["Occurred at can't be blank"]
+ )
+ end
+ end
+ end
+
+ context 'when timeline event cannot be found' do
+ let(:timeline_event_id) do
+ Gitlab::GlobalId.build(
+ nil,
+ model_name: ::IncidentManagement::TimelineEvent.name,
+ id: non_existing_record_id
+ ).to_s
+ end
+
+ it_behaves_like 'failed update with a top-level access error'
+ end
+ end
+
+ context 'when user does not have permissions to update the timeline event' do
+ let(:current_user) { reporter }
+
+ it_behaves_like 'failed update with a top-level access error'
+ end
+ end
+
+ private
+
+ def mutation_for(user)
+ described_class.new(object: nil, context: { current_user: user }, field: nil)
+ end
+end
diff --git a/spec/graphql/mutations/issues/set_due_date_spec.rb b/spec/graphql/mutations/issues/set_due_date_spec.rb
index 263122e5d5f..83edd670695 100644
--- a/spec/graphql/mutations/issues/set_due_date_spec.rb
+++ b/spec/graphql/mutations/issues/set_due_date_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Mutations::Issues::SetDueDate do
it 'returns the issue with updated due date', :aggregate_failures do
expect(mutated_issue).to eq(issue)
- expect(mutated_issue.due_date).to eq(Date.today + 2.days)
+ expect(mutated_issue.due_date).to eq(due_date.to_date)
expect(subject[:errors]).to be_empty
end
diff --git a/spec/graphql/mutations/merge_requests/accept_spec.rb b/spec/graphql/mutations/merge_requests/accept_spec.rb
index c97c78ec206..c99b1d988c5 100644
--- a/spec/graphql/mutations/merge_requests/accept_spec.rb
+++ b/spec/graphql/mutations/merge_requests/accept_spec.rb
@@ -3,6 +3,7 @@
require 'spec_helper'
RSpec.describe Mutations::MergeRequests::Accept do
+ include GraphqlHelpers
include AfterNextHelpers
subject(:mutation) { described_class.new(context: context, object: nil, field: nil) }
@@ -12,7 +13,7 @@ RSpec.describe Mutations::MergeRequests::Accept do
let(:project) { create(:project, :public, :repository) }
let(:context) do
GraphQL::Query::Context.new(
- query: double('query', schema: GitlabSchema),
+ query: query_double(schema: GitlabSchema),
values: { current_user: user },
object: nil
)
diff --git a/spec/graphql/mutations/merge_requests/create_spec.rb b/spec/graphql/mutations/merge_requests/create_spec.rb
index 83af1e3f1b3..e1edb60e4ff 100644
--- a/spec/graphql/mutations/merge_requests/create_spec.rb
+++ b/spec/graphql/mutations/merge_requests/create_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::MergeRequests::Create do
+ include GraphqlHelpers
+
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
let_it_be(:project) { create(:project, :public, :repository) }
@@ -10,7 +12,7 @@ RSpec.describe Mutations::MergeRequests::Create do
let(:context) do
GraphQL::Query::Context.new(
- query: double('query', schema: nil),
+ query: query_double(schema: nil),
values: { current_user: user },
object: nil
)
diff --git a/spec/graphql/mutations/namespace/package_settings/update_spec.rb b/spec/graphql/mutations/namespace/package_settings/update_spec.rb
index 978c81fadfa..631e02ff3dc 100644
--- a/spec/graphql/mutations/namespace/package_settings/update_spec.rb
+++ b/spec/graphql/mutations/namespace/package_settings/update_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Mutations::Namespace::PackageSettings::Update do
let(:params) { { namespace_path: namespace.full_path } }
- specify { expect(described_class).to require_graphql_authorizations(:create_package_settings) }
+ specify { expect(described_class).to require_graphql_authorizations(:admin_package) }
describe '#resolve' do
subject { described_class.new(object: namespace, context: { current_user: user }, field: nil).resolve(**params) }
@@ -68,7 +68,7 @@ RSpec.describe Mutations::Namespace::PackageSettings::Update do
where(:user_role, :shared_examples_name) do
:maintainer | 'updating the namespace package setting'
- :developer | 'updating the namespace package setting'
+ :developer | 'denying access to namespace package setting'
:reporter | 'denying access to namespace package setting'
:guest | 'denying access to namespace package setting'
:anonymous | 'denying access to namespace package setting'
@@ -88,7 +88,7 @@ RSpec.describe Mutations::Namespace::PackageSettings::Update do
where(:user_role, :shared_examples_name) do
:maintainer | 'creating the namespace package setting'
- :developer | 'creating the namespace package setting'
+ :developer | 'denying access to namespace package setting'
:reporter | 'denying access to namespace package setting'
:guest | 'denying access to namespace package setting'
:anonymous | 'denying access to namespace package setting'
diff --git a/spec/graphql/mutations/release_asset_links/delete_spec.rb b/spec/graphql/mutations/release_asset_links/delete_spec.rb
index cda292f2ffa..cca7bd2ba38 100644
--- a/spec/graphql/mutations/release_asset_links/delete_spec.rb
+++ b/spec/graphql/mutations/release_asset_links/delete_spec.rb
@@ -52,18 +52,12 @@ RSpec.describe Mutations::ReleaseAssetLinks::Delete do
end
context "when the link doesn't exist" do
- let(:mutation_arguments) { super().merge(id: "gid://gitlab/Releases::Link/#{non_existing_record_id}") }
-
- it 'raises an error' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ let(:mutation_arguments) do
+ super().merge(id: global_id_of(id: non_existing_record_id, model_name: release_link.class.name))
end
- end
-
- context "when the provided ID is invalid" do
- let(:mutation_arguments) { super().merge(id: 'not-a-valid-gid') }
it 'raises an error' do
- expect { subject }.to raise_error(::GraphQL::CoercionError)
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
diff --git a/spec/graphql/mutations/release_asset_links/update_spec.rb b/spec/graphql/mutations/release_asset_links/update_spec.rb
index 64648687336..e119cf9cc77 100644
--- a/spec/graphql/mutations/release_asset_links/update_spec.rb
+++ b/spec/graphql/mutations/release_asset_links/update_spec.rb
@@ -186,18 +186,12 @@ RSpec.describe Mutations::ReleaseAssetLinks::Update do
end
context "when the link doesn't exist" do
- let(:mutation_arguments) { super().merge(id: "gid://gitlab/Releases::Link/#{non_existing_record_id}") }
-
- it 'raises an error' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ let(:mutation_arguments) do
+ super().merge(id: global_id_of(id: non_existing_record_id, model_name: "Releases::Link"))
end
- end
-
- context "when the provided ID is invalid" do
- let(:mutation_arguments) { super().merge(id: 'not-a-valid-gid') }
it 'raises an error' do
- expect { subject }.to raise_error(::GraphQL::CoercionError)
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
diff --git a/spec/graphql/mutations/timelogs/delete_spec.rb b/spec/graphql/mutations/timelogs/delete_spec.rb
new file mode 100644
index 00000000000..f4a258e0f78
--- /dev/null
+++ b/spec/graphql/mutations/timelogs/delete_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Timelogs::Delete do
+ include GraphqlHelpers
+
+ let_it_be(:author) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:administrator) { create(:user, :admin) }
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be_with_reload(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800) }
+
+ let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
+ let(:timelog_id) { global_id_of(timelog) }
+ let(:mutation_arguments) { { id: timelog_id } }
+
+ describe '#resolve' do
+ subject(:resolve) do
+ mutation.resolve(**mutation_arguments)
+ end
+
+ context 'when the timelog id is not valid' do
+ let(:current_user) { author }
+ let(:timelog_id) { global_id_of(model_name: 'Timelog', id: non_existing_record_id) }
+
+ it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when the current user is not the timelog\'s author, not a maintainer and not an admin' do
+ let(:current_user) { create(:user) }
+
+ it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when the current user is the timelog\'s author' do
+ let(:current_user) { author }
+
+ it 'deletes the timelog' do
+ expect { subject }.to change { Timelog.count }.by(-1)
+ end
+
+ it 'returns the deleted timelog' do
+ expect(subject[:timelog]).to eq(timelog)
+ end
+
+ it 'returns no errors' do
+ expect(subject[:errors]).to be_empty
+ end
+ end
+
+ context 'when the current user is not the timelog\'s author but a maintainer of the project' do
+ let(:current_user) { maintainer }
+
+ before do
+ project.add_maintainer(maintainer)
+ end
+
+ it 'deletes the timelog' do
+ expect { subject }.to change { Timelog.count }.by(-1)
+ end
+
+ it 'returns the deleted timelog' do
+ expect(subject[:timelog]).to eq(timelog)
+ end
+
+ it 'returns no errors' do
+ expect(subject[:errors]).to be_empty
+ end
+ end
+
+ context 'when the current user is not the timelog\'s author, not a maintainer but an admin', :enable_admin_mode do
+ let(:current_user) { administrator }
+
+ it 'deletes the timelog' do
+ expect { subject }.to change { Timelog.count }.by(-1)
+ end
+
+ it 'returns the deleted timelog' do
+ expect(subject[:timelog]).to eq(timelog)
+ end
+
+ it 'returns no errors' do
+ expect(subject[:errors]).to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/todos/create_spec.rb b/spec/graphql/mutations/todos/create_spec.rb
index bbb033e2f33..8c6dca98bad 100644
--- a/spec/graphql/mutations/todos/create_spec.rb
+++ b/spec/graphql/mutations/todos/create_spec.rb
@@ -10,12 +10,19 @@ RSpec.describe Mutations::Todos::Create do
context 'when target does not support todos' do
it 'raises error' do
current_user = create(:user)
- mutation = described_class.new(object: nil, context: { current_user: current_user }, field: nil)
-
target = create(:milestone)
- expect { mutation.resolve(target_id: global_id_of(target)) }
- .to raise_error(GraphQL::CoercionError)
+ ctx = { current_user: current_user }
+ input = { target_id: global_id_of(target).to_s }
+ mutation = graphql_mutation(described_class, input)
+
+ response = GitlabSchema.execute(mutation.query, context: ctx, variables: mutation.variables).to_h
+
+ expect(response).to include(
+ 'errors' => contain_exactly(
+ include('message' => /invalid value for targetId/)
+ )
+ )
end
end
diff --git a/spec/graphql/mutations/todos/mark_done_spec.rb b/spec/graphql/mutations/todos/mark_done_spec.rb
index 9723ac8af42..51df2032cf1 100644
--- a/spec/graphql/mutations/todos/mark_done_spec.rb
+++ b/spec/graphql/mutations/todos/mark_done_spec.rb
@@ -56,15 +56,6 @@ RSpec.describe Mutations::Todos::MarkDone do
expect(todo2.reload.state).to eq('done')
expect(other_user_todo.reload.state).to eq('pending')
end
-
- it 'ignores invalid GIDs' do
- expect { mutation.resolve(id: author.to_global_id.to_s) }
- .to raise_error(::GraphQL::CoercionError)
-
- expect(todo1.reload.state).to eq('pending')
- expect(todo2.reload.state).to eq('done')
- expect(other_user_todo.reload.state).to eq('pending')
- end
end
def mark_done_mutation(todo)
diff --git a/spec/graphql/mutations/todos/restore_many_spec.rb b/spec/graphql/mutations/todos/restore_many_spec.rb
index dc10355ef22..d43f1c8a2e9 100644
--- a/spec/graphql/mutations/todos/restore_many_spec.rb
+++ b/spec/graphql/mutations/todos/restore_many_spec.rb
@@ -49,13 +49,6 @@ RSpec.describe Mutations::Todos::RestoreMany do
expect_states_were_not_changed
end
- it 'raises an error with invalid or non-Todo GIDs' do
- expect { mutation.resolve(ids: [author.to_global_id.to_s]) }
- .to raise_error(GraphQL::CoercionError)
-
- expect_states_were_not_changed
- end
-
it 'restores multiple todos' do
todo4 = create(:todo, user: current_user, author: author, state: :done)
diff --git a/spec/graphql/mutations/todos/restore_spec.rb b/spec/graphql/mutations/todos/restore_spec.rb
index 954bb3db668..fad9d6c08a6 100644
--- a/spec/graphql/mutations/todos/restore_spec.rb
+++ b/spec/graphql/mutations/todos/restore_spec.rb
@@ -56,15 +56,6 @@ RSpec.describe Mutations::Todos::Restore do
expect(todo2.reload.state).to eq('pending')
expect(other_user_todo.reload.state).to eq('done')
end
-
- it 'raises error for invalid GID' do
- expect { mutation.resolve(id: author.to_global_id.to_s) }
- .to raise_error(::GraphQL::CoercionError)
-
- expect(todo1.reload.state).to eq('done')
- expect(todo2.reload.state).to eq('pending')
- expect(other_user_todo.reload.state).to eq('done')
- end
end
def restore_mutation(todo)
diff --git a/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb b/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
index c042f6dac19..14ebe85d80e 100644
--- a/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
+++ b/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
@@ -39,8 +39,8 @@ RSpec.describe Resolvers::AlertManagement::AlertResolver do
end
context 'filtering by domain' do
- let_it_be(:alert1) { create(:alert_management_alert, project: project, monitoring_tool: 'Cilium', domain: :threat_monitoring) }
- let_it_be(:alert2) { create(:alert_management_alert, project: project, monitoring_tool: 'Cilium', domain: :threat_monitoring) }
+ let_it_be(:alert1) { create(:alert_management_alert, project: project, monitoring_tool: 'other', domain: :threat_monitoring) }
+ let_it_be(:alert2) { create(:alert_management_alert, project: project, monitoring_tool: 'other', domain: :threat_monitoring) }
let_it_be(:alert3) { create(:alert_management_alert, project: project, monitoring_tool: 'generic') }
let(:args) { { domain: 'operations' } }
diff --git a/spec/graphql/resolvers/ci/config_resolver_spec.rb b/spec/graphql/resolvers/ci/config_resolver_spec.rb
index 3ff6d8f4347..7a6104fc503 100644
--- a/spec/graphql/resolvers/ci/config_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/config_resolver_spec.rb
@@ -37,13 +37,15 @@ RSpec.describe Resolvers::Ci::ConfigResolver do
merged_yaml: content,
jobs: [],
errors: [],
- warnings: []
+ warnings: [],
+ includes: []
)
end
it 'lints the ci config file and returns the merged yaml file' do
expect(response[:status]).to eq(:valid)
expect(response[:merged_yaml]).to eq(content)
+ expect(response[:includes]).to eq([])
expect(response[:errors]).to be_empty
expect(::Gitlab::Ci::Lint).to have_received(:new).with(current_user: user, project: project, sha: sha)
end
@@ -69,7 +71,8 @@ RSpec.describe Resolvers::Ci::ConfigResolver do
jobs: [],
merged_yaml: content,
errors: ['Invalid configuration format'],
- warnings: []
+ warnings: [],
+ includes: []
)
end
diff --git a/spec/graphql/resolvers/concerns/resolves_ids_spec.rb b/spec/graphql/resolvers/concerns/resolves_ids_spec.rb
index 1dd27c0eff0..84741b7a603 100644
--- a/spec/graphql/resolvers/concerns/resolves_ids_spec.rb
+++ b/spec/graphql/resolvers/concerns/resolves_ids_spec.rb
@@ -3,33 +3,32 @@
require 'spec_helper'
RSpec.describe ResolvesIds do
+ include GraphqlHelpers
+
# gid://gitlab/Project/6
# gid://gitlab/Issue/6
# gid://gitlab/Project/6 gid://gitlab/Issue/6
context 'with a single project' do
- let(:ids) { 'gid://gitlab/Project/6' }
- let(:type) { ::Types::GlobalIDType[::Project] }
+ let(:ids) { global_id_of(model_name: 'Project', id: 6) }
it 'returns the correct array' do
- expect(resolve_ids).to match_array(['6'])
+ expect(resolve_ids).to contain_exactly('6')
end
end
context 'with a single issue' do
- let(:ids) { 'gid://gitlab/Issue/9' }
- let(:type) { ::Types::GlobalIDType[::Issue] }
+ let(:ids) { global_id_of(model_name: 'Issue', id: 9) }
it 'returns the correct array' do
- expect(resolve_ids).to match_array(['9'])
+ expect(resolve_ids).to contain_exactly('9')
end
end
context 'with multiple users' do
- let(:ids) { ['gid://gitlab/User/7', 'gid://gitlab/User/13', 'gid://gitlab/User/21'] }
- let(:type) { ::Types::GlobalIDType[::User] }
+ let(:ids) { [7, 13, 21].map { global_id_of(model_name: 'User', id: _1) } }
it 'returns the correct array' do
- expect(resolve_ids).to match_array(%w[7 13 21])
+ expect(resolve_ids).to eq %w[7 13 21]
end
end
@@ -38,6 +37,6 @@ RSpec.describe ResolvesIds do
end
def resolve_ids
- mock_resolver.resolve_ids(ids, type)
+ mock_resolver.resolve_ids(ids)
end
end
diff --git a/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb
index a16e8821cb5..3fe1ec4b5a4 100644
--- a/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe Resolvers::DesignManagement::DesignAtVersionResolver do
let(:current_user) { user }
let(:object) { issue.design_collection }
- let(:global_id) { GitlabSchema.id_from_object(design_at_version).to_s }
+ let(:global_id) { GitlabSchema.id_from_object(design_at_version) }
let(:design_at_version) { ::DesignManagement::DesignAtVersion.new(design: design_a, version: version_a) }
diff --git a/spec/graphql/resolvers/design_management/design_resolver_spec.rb b/spec/graphql/resolvers/design_management/design_resolver_spec.rb
index 4c8b3116875..0915dddf438 100644
--- a/spec/graphql/resolvers/design_management/design_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/design_resolver_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe Resolvers::DesignManagement::DesignResolver do
create(:design, issue: create(:issue, project: project), versions: [create(:design_version)])
end
- let(:args) { { id: GitlabSchema.id_from_object(first_design).to_s } }
+ let(:args) { { id: GitlabSchema.id_from_object(first_design) } }
let(:gql_context) { { current_user: current_user } }
before do
@@ -50,7 +50,7 @@ RSpec.describe Resolvers::DesignManagement::DesignResolver do
end
context 'when both arguments have been passed' do
- let(:args) { { filename: first_design.filename, id: GitlabSchema.id_from_object(first_design).to_s } }
+ let(:args) { { filename: first_design.filename, id: GitlabSchema.id_from_object(first_design) } }
it 'generates an error' do
expect_graphql_error_to_be_created(::Gitlab::Graphql::Errors::ArgumentError, /may/) do
@@ -71,15 +71,6 @@ RSpec.describe Resolvers::DesignManagement::DesignResolver 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 b091e58b06f..64eae14d888 100644
--- a/spec/graphql/resolvers/design_management/designs_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb
@@ -109,6 +109,8 @@ RSpec.describe Resolvers::DesignManagement::DesignsResolver do
end
def resolve_designs
- resolve(described_class, obj: issue.design_collection, args: args, ctx: gql_context)
+ Gitlab::Graphql::Lazy.force(
+ resolve(described_class, obj: issue.design_collection, args: args, ctx: gql_context)
+ )
end
end
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 8b9874c3580..00f37a8e5f6 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
@@ -50,15 +50,6 @@ RSpec.describe Resolvers::DesignManagement::VersionInCollectionResolver do
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(:appropriate_error) { ::GraphQL::CoercionError }
-
- it 'raises an appropriate error' do
- expect { result }.to raise_error(appropriate_error)
- end
- end
end
def resolve_version(obj, context = { current_user: current_user })
diff --git a/spec/graphql/resolvers/design_management/versions_resolver_spec.rb b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
index d98138f6385..8eab0222cf6 100644
--- a/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
@@ -18,8 +18,7 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
let(:project) { issue.project }
let(:params) { {} }
let(:current_user) { authorized_user }
- let(:parent_args) { { irrelevant: 1.2 } }
- let(:parent) { double('Parent', parent: nil, irep_node: double(arguments: parent_args)) }
+ let(:query_context) { { current_user: current_user } }
before do
enable_design_management
@@ -107,7 +106,9 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
end
context 'by at_version in parent' do
- let(:parent_args) { { atVersion: global_id_of(first_version) } }
+ before do
+ query_context[:at_version_argument] = first_version.to_global_id
+ end
it_behaves_like 'a query for all_versions up to the first_version'
end
@@ -126,8 +127,8 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
it_behaves_like 'a source of versions'
end
- def resolve_versions(obj, context = { current_user: current_user })
- eager_resolve(resolver, obj: obj, parent: parent, args: params, ctx: context)
+ def resolve_versions(obj)
+ eager_resolve(resolver, obj: obj, args: params, ctx: query_context)
end
end
end
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 2aef483ac95..f80b33e644e 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
@@ -8,28 +8,23 @@ RSpec.describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do
let_it_be(:project) { create(:project) }
let_it_be(:current_user) { create(:user) }
- let(:issue_details_service) { spy('ErrorTracking::IssueDetailsService') }
+ let(:issue_details_service) { instance_double('ErrorTracking::IssueDetailsService') }
+ let(:service_response) { {} }
- specify do
- expect(described_class).to have_nullable_graphql_type(Types::ErrorTracking::SentryDetailedErrorType)
+ before_all do
+ project.add_developer(current_user)
end
before do
- project.add_developer(current_user)
-
allow(ErrorTracking::IssueDetailsService)
.to receive(:new)
- .and_return issue_details_service
- end
+ .and_return(issue_details_service)
- shared_examples 'it resolves to nil' do
- it 'resolves to nil' do
- allow(issue_details_service).to receive(:execute)
- .and_return(issue: nil)
+ allow(issue_details_service).to receive(:execute).and_return(service_response)
+ end
- result = resolve_error(args)
- expect(result).to be_nil
- end
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::ErrorTracking::SentryDetailedErrorType)
end
describe '#resolve' do
@@ -41,13 +36,9 @@ RSpec.describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do
expect(issue_details_service).to have_received(:execute)
end
- context 'error matched' do
- let(:detailed_error) { build(:error_tracking_sentry_detailed_error) }
-
- before do
- allow(issue_details_service).to receive(:execute)
- .and_return(issue: detailed_error)
- end
+ context 'when error matches' do
+ let(:detailed_error) { build_stubbed(:error_tracking_sentry_detailed_error) }
+ let(:service_response) { { issue: detailed_error } }
it 'resolves to a detailed error' do
expect(resolve_error(args)).to eq detailed_error
@@ -58,24 +49,23 @@ RSpec.describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do
end
end
- context 'if id does not match issue' do
- it_behaves_like 'it resolves to nil'
- end
-
- context 'blank id' do
- let(:args) { { id: '' } }
+ context 'when id does not match issue' do
+ let(:service_response) { { issue: nil } }
- it 'responds with an error' do
- expect { resolve_error(args) }.to raise_error(::GraphQL::CoercionError)
+ it 'resolves to nil' do
+ result = resolve_error(args)
+ expect(result).to be_nil
end
end
end
+ private
+
def resolve_error(args = {}, context = { current_user: current_user })
resolve(described_class, obj: project, args: args, ctx: context)
end
def issue_global_id(issue_id)
- Gitlab::ErrorTracking::DetailedError.new(id: issue_id).to_global_id.to_s
+ Gitlab::ErrorTracking::DetailedError.new(id: issue_id).to_global_id
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 20c2bdcd4e1..5834faea97e 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
@@ -8,18 +8,22 @@ RSpec.describe Resolvers::ErrorTracking::SentryErrorCollectionResolver do
let_it_be(:project) { create(:project) }
let_it_be(:current_user) { create(:user) }
- let(:list_issues_service) { spy('ErrorTracking::ListIssuesService') }
+ let(:list_issues_service) { instance_double('ErrorTracking::ListIssuesService') }
- specify do
- expect(described_class).to have_nullable_graphql_type(Types::ErrorTracking::SentryErrorCollectionType)
+ before_all do
+ project.add_developer(current_user)
end
before do
- project.add_developer(current_user)
-
allow(ErrorTracking::ListIssuesService)
.to receive(:new)
.and_return list_issues_service
+
+ allow(list_issues_service).to receive(:external_url)
+ end
+
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::ErrorTracking::SentryErrorCollectionType)
end
describe '#resolve' do
@@ -34,8 +38,7 @@ RSpec.describe Resolvers::ErrorTracking::SentryErrorCollectionResolver do
.to receive(:external_url)
.and_return(fake_url)
- result = resolve_error_collection
- expect(result.external_url).to eq fake_url
+ expect(resolve_error_collection.external_url).to eq fake_url
end
it 'provides the project' do
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 68badb8e333..65b6c551dde 100644
--- a/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb
+++ b/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Resolvers::ErrorTracking::SentryErrorsResolver do
let_it_be(:current_user) { create(:user) }
let_it_be(:error_collection) { Gitlab::ErrorTracking::ErrorCollection.new(project: project) }
- let(:list_issues_service) { spy('ErrorTracking::ListIssuesService') }
+ let(:list_issues_service) { instance_double('ErrorTracking::ListIssuesService') }
let(:issues) { nil }
let(:pagination) { nil }
@@ -19,23 +19,25 @@ RSpec.describe Resolvers::ErrorTracking::SentryErrorsResolver do
end
describe '#resolve' do
+ before do
+ allow(ErrorTracking::ListIssuesService)
+ .to receive(:new)
+ .and_return list_issues_service
+
+ allow(list_issues_service).to receive(:execute).and_return({})
+ end
+
context 'with insufficient user permission' do
- let(:user) { create(:user) }
+ let(:current_user) { create(:user) }
it 'returns nil' do
- context = { current_user: user }
-
- expect(resolve_errors({}, context)).to eq nil
+ expect(resolve_errors).to eq nil
end
end
context 'with sufficient permission' do
- before do
+ before_all do
project.add_developer(current_user)
-
- allow(ErrorTracking::ListIssuesService)
- .to receive(:new)
- .and_return list_issues_service
end
context 'when after arg given' do
@@ -52,14 +54,9 @@ RSpec.describe Resolvers::ErrorTracking::SentryErrorsResolver do
end
context 'when no issues fetched' do
- before do
- allow(list_issues_service)
- .to receive(:execute)
- .and_return(
- issues: nil
- )
- end
it 'returns nil' do
+ expect(list_issues_service).to receive(:execute).and_return(issues: nil)
+
expect(resolve_errors).to eq nil
end
end
diff --git a/spec/graphql/resolvers/incident_management/timeline_events_resolver_spec.rb b/spec/graphql/resolvers/incident_management/timeline_events_resolver_spec.rb
new file mode 100644
index 00000000000..046cf242d56
--- /dev/null
+++ b/spec/graphql/resolvers/incident_management/timeline_events_resolver_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::IncidentManagement::TimelineEventsResolver do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:first_timeline_event) do
+ create(:incident_management_timeline_event, project: project, incident: incident)
+ end
+
+ let_it_be(:second_timeline_event) do
+ create(:incident_management_timeline_event, project: project, incident: incident)
+ end
+
+ let(:args) { { incident_id: incident.to_global_id } }
+ let(:resolver) { described_class }
+
+ subject(:resolved_timeline_events) { sync(resolve_timeline_events(args, current_user: current_user).to_a) }
+
+ before do
+ project.add_guest(current_user)
+ end
+
+ specify do
+ expect(resolver).to have_nullable_graphql_type(Types::IncidentManagement::TimelineEventType.connection_type)
+ end
+
+ it 'returns timeline events', :aggregate_failures do
+ expect(resolved_timeline_events.length).to eq(2)
+ expect(resolved_timeline_events.first).to be_a(::IncidentManagement::TimelineEvent)
+ end
+
+ context 'when user does not have permissions' do
+ let(:non_member) { create(:user) }
+
+ subject(:resolved_timeline_events) { sync(resolve_timeline_events(args, current_user: non_member).to_a) }
+
+ before do
+ project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE)
+ end
+
+ it 'returns no timeline events' do
+ expect(resolved_timeline_events.length).to eq(0)
+ end
+ end
+
+ context 'when resolving a single item' do
+ let(:resolver) { described_class.single }
+
+ subject(:resolved_timeline_event) { sync(resolve_timeline_events(args, current_user: current_user)) }
+
+ context 'when id given' do
+ let(:args) { { incident_id: incident.to_global_id, id: first_timeline_event.to_global_id } }
+
+ it 'returns the timeline event' do
+ expect(resolved_timeline_event).to eq(first_timeline_event)
+ end
+ end
+ end
+
+ private
+
+ def resolve_timeline_events(args = {}, context = { current_user: current_user })
+ resolve(resolver, obj: incident, args: args, ctx: context)
+ end
+end
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index 81aeee0a3d2..e6ec9d8c895 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -389,6 +389,34 @@ RSpec.describe Resolvers::IssuesResolver do
end
end
+ describe 'filtering by crm' do
+ let_it_be(:organization) { create(:organization, group: group) }
+ let_it_be(:contact1) { create(:contact, group: group, organization: organization) }
+ let_it_be(:contact2) { create(:contact, group: group, organization: organization) }
+ let_it_be(:contact3) { create(:contact, group: group) }
+ let_it_be(:crm_issue1) { create(:issue, project: project) }
+ let_it_be(:crm_issue2) { create(:issue, project: project) }
+ let_it_be(:crm_issue3) { create(:issue, project: project) }
+
+ before_all do
+ create(:issue_customer_relations_contact, issue: crm_issue1, contact: contact1)
+ create(:issue_customer_relations_contact, issue: crm_issue2, contact: contact2)
+ create(:issue_customer_relations_contact, issue: crm_issue3, contact: contact3)
+ end
+
+ context 'contact' do
+ it 'returns only the issues for the contact' do
+ expect(resolve_issues({ crm_contact_id: contact1.id })).to contain_exactly(crm_issue1)
+ end
+ end
+
+ context 'organization' do
+ it 'returns only the issues for the contact' do
+ expect(resolve_issues({ crm_organization_id: organization.id })).to contain_exactly(crm_issue1, crm_issue2)
+ end
+ end
+ end
+
describe 'sorting' do
context 'when sorting by created' do
it 'sorts issues ascending' do
@@ -603,13 +631,13 @@ RSpec.describe Resolvers::IssuesResolver do
end
it 'finds a specific issue with iid', :request_store do
- result = batch_sync(max_queries: 6) { resolve_issues(iid: issue1.iid).to_a }
+ result = batch_sync(max_queries: 7) { resolve_issues(iid: issue1.iid).to_a }
expect(result).to contain_exactly(issue1)
end
it 'batches queries that only include IIDs', :request_store do
- result = batch_sync(max_queries: 6) do
+ result = batch_sync(max_queries: 7) do
[issue1, issue2]
.map { |issue| resolve_issues(iid: issue.iid.to_s) }
.flat_map(&:to_a)
@@ -619,7 +647,7 @@ RSpec.describe Resolvers::IssuesResolver do
end
it 'finds a specific issue with iids', :request_store do
- result = batch_sync(max_queries: 6) do
+ result = batch_sync(max_queries: 7) do
resolve_issues(iids: [issue1.iid]).to_a
end
diff --git a/spec/graphql/resolvers/package_pipelines_resolver_spec.rb b/spec/graphql/resolvers/package_pipelines_resolver_spec.rb
index c757c876616..a52dee59bc6 100644
--- a/spec/graphql/resolvers/package_pipelines_resolver_spec.rb
+++ b/spec/graphql/resolvers/package_pipelines_resolver_spec.rb
@@ -9,10 +9,23 @@ RSpec.describe Resolvers::PackagePipelinesResolver do
let_it_be(:pipelines) { create_list(:ci_pipeline, 3, project: package.project) }
let(:user) { package.project.first_owner }
- let(:args) { {} }
describe '#resolve' do
- subject { resolve(described_class, obj: package, args: args, ctx: { current_user: user }) }
+ let(:returned_pipelines) { graphql_dig_at(subject, 'data', 'package', 'pipelines', 'nodes') }
+ let(:returned_errors) { graphql_dig_at(subject, 'errors', 'message') }
+ let(:pagination_args) { {} }
+ let(:query) do
+ pipelines_nodes = 'nodes { id }'
+ graphql_query_for(
+ :package,
+ { id: global_id_of(package) },
+ query_graphql_field('pipelines', pagination_args, pipelines_nodes)
+ )
+ end
+
+ subject do
+ GitlabSchema.execute(query, context: { current_user: user })
+ end
before do
pipelines.each do |pipeline|
@@ -20,67 +33,115 @@ RSpec.describe Resolvers::PackagePipelinesResolver do
end
end
- it { is_expected.to contain_exactly(*pipelines) }
+ it 'contains the expected pipelines' do
+ expect_to_contain_exactly(*pipelines)
+ end
+
+ context 'with valid after' do
+ let(:pagination_args) { { first: 1, after: encode_cursor(id: pipelines[1].id) } }
+
+ it 'contains the expected pipelines' do
+ expect_to_contain_exactly(pipelines[0])
+ end
+ end
+
+ context 'with valid before' do
+ let(:pagination_args) { { last: 1, before: encode_cursor(id: pipelines[1].id) } }
+
+ it 'contains the expected pipelines' do
+ expect_to_contain_exactly(pipelines[2])
+ end
+ end
context 'with invalid after' do
- let(:args) { { first: 1, after: 'not_json_string' } }
+ let(:pagination_args) { { first: 1, after: 'not_json_string' } }
it 'generates an argument error' do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError) do
- subject
- end
+ expect(returned_errors).to include('Please provide a valid cursor')
end
end
context 'with invalid after key' do
- let(:args) { { first: 1, after: encode_cursor(foo: 3) } }
+ let(:pagination_args) { { first: 1, after: encode_cursor(foo: 3) } }
it 'generates an argument error' do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError) do
- subject
- end
+ expect(returned_errors).to include('Please provide a valid cursor')
end
end
context 'with invalid before' do
- let(:args) { { last: 1, before: 'not_json_string' } }
+ let(:pagination_args) { { last: 1, before: 'not_json_string' } }
it 'generates an argument error' do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError) do
- subject
- end
+ expect(returned_errors).to include('Please provide a valid cursor')
end
end
context 'with invalid before key' do
- let(:args) { { last: 1, before: encode_cursor(foo: 3) } }
+ let(:pagination_args) { { last: 1, before: encode_cursor(foo: 3) } }
it 'generates an argument error' do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError) do
- subject
- end
+ expect(returned_errors).to include('Please provide a valid cursor')
end
end
- context 'field options' do
- let(:field) do
- field_options = described_class.field_options.merge(
- owner: resolver_parent,
- name: 'dummy_field'
- )
- ::Types::BaseField.new(**field_options)
- end
+ context 'with unauthorized user' do
+ let_it_be(:user) { create(:user) }
- it 'sets them properly' do
- expect(field).not_to be_connection
- expect(field.extras).to match_array([:lookahead])
+ it 'returns nothing' do
+ expect(returned_pipelines).to be_nil
end
end
- context 'with unauthorized user' do
- let_it_be(:user) { create(:user) }
+ context 'with many packages' do
+ let_it_be_with_reload(:other_package) { create(:package, project: package.project) }
+ let_it_be(:other_pipelines) { create_list(:ci_pipeline, 3, project: package.project) }
+
+ let(:returned_pipelines) do
+ graphql_dig_at(subject, 'data', 'project', 'packages', 'nodes', 'pipelines', 'nodes')
+ end
- it { is_expected.to be_nil }
+ let(:query) do
+ pipelines_query = query_graphql_field('pipelines', pagination_args, 'nodes { id }')
+ <<~QUERY
+ {
+ project(fullPath: "#{package.project.full_path}") {
+ packages {
+ nodes { #{pipelines_query} }
+ }
+ }
+ }
+ QUERY
+ end
+
+ before do
+ other_pipelines.each do |pipeline|
+ create(:package_build_info, package: other_package, pipeline: pipeline)
+ end
+ end
+
+ it 'contains the expected pipelines' do
+ expect_to_contain_exactly(*(pipelines + other_pipelines))
+ end
+
+ it 'handles n+1 situations' do
+ control = ActiveRecord::QueryRecorder.new do
+ GitlabSchema.execute(query, context: { current_user: user })
+ end
+
+ create_package_with_pipelines(package.project)
+
+ expectation = expect { GitlabSchema.execute(query, context: { current_user: user }) }
+
+ expectation.not_to exceed_query_limit(control)
+ end
+
+ def create_package_with_pipelines(project)
+ extra_package = create(:package, project: project)
+ create_list(:ci_pipeline, 3, project: project).each do |pipeline|
+ create(:package_build_info, package: extra_package, pipeline: pipeline)
+ end
+ end
end
def encode_cursor(json)
@@ -89,5 +150,25 @@ RSpec.describe Resolvers::PackagePipelinesResolver do
nonce: true
)
end
+
+ def expect_to_contain_exactly(*pipelines)
+ entities = pipelines.map { |pipeline| a_graphql_entity_for(pipeline) }
+ expect(returned_pipelines).to match_array(entities)
+ end
+ end
+
+ describe '.field options' do
+ let(:field) do
+ field_options = described_class.field_options.merge(
+ owner: resolver_parent,
+ name: 'dummy_field'
+ )
+ ::Types::BaseField.new(**field_options)
+ end
+
+ it 'sets them properly' do
+ expect(field).not_to be_connection
+ expect(field.extras).to match_array([:lookahead])
+ end
end
end
diff --git a/spec/graphql/resolvers/projects/snippets_resolver_spec.rb b/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
index b963f2509db..1d04db3ea6e 100644
--- a/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
@@ -58,12 +58,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(GraphQL::CoercionError)
- end
end
context 'when no project is provided' do
diff --git a/spec/graphql/resolvers/snippets_resolver_spec.rb b/spec/graphql/resolvers/snippets_resolver_spec.rb
index f9feb8901cd..ee9a6e67243 100644
--- a/spec/graphql/resolvers/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/snippets_resolver_spec.rb
@@ -40,12 +40,6 @@ RSpec.describe Resolvers::SnippetsResolver do
expect(snippets).to contain_exactly(personal_snippet, project_snippet)
end
-
- it 'returns an error if the param id is invalid' do
- expect do
- resolve_snippets(args: { author_id: 'foo' })
- end.to raise_error(GraphQL::CoercionError)
- end
end
it 'returns the snippets by type' do
@@ -61,12 +55,6 @@ RSpec.describe Resolvers::SnippetsResolver do
expect(snippets).to contain_exactly(project_snippet, other_project_snippet)
end
-
- it 'returns an error if the param id is invalid' do
- expect do
- resolve_snippets(args: { project_id: 'foo' })
- end.to raise_error(GraphQL::CoercionError)
- end
end
it 'returns the snippets by visibility' do
@@ -98,16 +86,6 @@ RSpec.describe Resolvers::SnippetsResolver do
expect(found).to match_array(snippets)
end
- 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(GraphQL::CoercionError, '"foo" is not a valid Global ID')
- end
-
it 'generates an error if both project and author are provided' do
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError) do
args = {
diff --git a/spec/graphql/resolvers/timelog_resolver_spec.rb b/spec/graphql/resolvers/timelog_resolver_spec.rb
index 84fa2932829..da2747fdf72 100644
--- a/spec/graphql/resolvers/timelog_resolver_spec.rb
+++ b/spec/graphql/resolvers/timelog_resolver_spec.rb
@@ -265,7 +265,7 @@ RSpec.describe Resolvers::TimelogResolver do
context 'when > `default_max_page_size` records' do
let(:object) { nil }
let!(:timelog_list) { create_list(:timelog, 101, issue: issue) }
- let(:args) { { project_id: "gid://gitlab/Project/#{project.id}" } }
+ let(:args) { { project_id: global_id_of(project) } }
let(:extra_args) { {} }
it 'pagination returns `default_max_page_size` and sets `has_next_page` true' do
diff --git a/spec/graphql/resolvers/users/snippets_resolver_spec.rb b/spec/graphql/resolvers/users/snippets_resolver_spec.rb
index 04fe3213a99..12baed2560e 100644
--- a/spec/graphql/resolvers/users/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/users/snippets_resolver_spec.rb
@@ -64,16 +64,6 @@ RSpec.describe Resolvers::Users::SnippetsResolver do
expect(found).to match_array(snippets)
end
-
- it 'returns an error if the gid is invalid' do
- args = {
- ids: [global_id_of(private_personal_snippet), 'foo']
- }
-
- expect do
- resolve_snippets(args: args)
- end.to raise_error(GraphQL::CoercionError)
- end
end
context 'when user profile is private' do
diff --git a/spec/graphql/resolvers/work_item_resolver_spec.rb b/spec/graphql/resolvers/work_item_resolver_spec.rb
index bfa0cf1d8a2..c44ed395102 100644
--- a/spec/graphql/resolvers/work_item_resolver_spec.rb
+++ b/spec/graphql/resolvers/work_item_resolver_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Resolvers::WorkItemResolver do
let(:current_user) { developer }
- subject(:resolved_work_item) { resolve_work_item('id' => work_item.to_gid.to_s) }
+ subject(:resolved_work_item) { resolve_work_item('id' => work_item.to_gid) }
context 'when the user can read the work item' do
it { is_expected.to eq(work_item) }
diff --git a/spec/graphql/subscriptions/issuable_updated_spec.rb b/spec/graphql/subscriptions/issuable_updated_spec.rb
index c15b4f532ef..0b8fcf67513 100644
--- a/spec/graphql/subscriptions/issuable_updated_spec.rb
+++ b/spec/graphql/subscriptions/issuable_updated_spec.rb
@@ -39,14 +39,6 @@ RSpec.describe Subscriptions::IssuableUpdated do
expect { subject }.to raise_error(GraphQL::ExecutionError)
end
end
-
- context 'when a GraphQL::Types::ID is provided' do
- let(:issuable_id) { issue.to_gid.to_s }
-
- it 'raises an exception' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
- end
- end
end
context 'subscription updates' do
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)