Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-12-17 14:59:07 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-12-17 14:59:07 +0300
commit8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch)
tree544930fb309b30317ae9797a9683768705d664c4 /spec/graphql
parent4b1de649d0168371549608993deac953eb692019 (diff)
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'spec/graphql')
-rw-r--r--spec/graphql/features/authorization_spec.rb22
-rw-r--r--spec/graphql/features/feature_flag_spec.rb2
-rw-r--r--spec/graphql/mutations/alert_management/create_alert_issue_spec.rb1
-rw-r--r--spec/graphql/mutations/alert_management/http_integration/destroy_spec.rb2
-rw-r--r--spec/graphql/mutations/alert_management/http_integration/reset_token_spec.rb2
-rw-r--r--spec/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb2
-rw-r--r--spec/graphql/mutations/alert_management/update_alert_status_spec.rb2
-rw-r--r--spec/graphql/mutations/boards/issues/issue_move_list_spec.rb18
-rw-r--r--spec/graphql/mutations/boards/lists/create_spec.rb9
-rw-r--r--spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb26
-rw-r--r--spec/graphql/mutations/container_expiration_policies/update_spec.rb2
-rw-r--r--spec/graphql/mutations/container_repositories/destroy_tags_spec.rb92
-rw-r--r--spec/graphql/mutations/discussions/toggle_resolve_spec.rb2
-rw-r--r--spec/graphql/mutations/environments/canary_ingress/update_spec.rb66
-rw-r--r--spec/graphql/mutations/issues/create_spec.rb8
-rw-r--r--spec/graphql/mutations/issues/update_spec.rb2
-rw-r--r--spec/graphql/mutations/labels/create_spec.rb2
-rw-r--r--spec/graphql/mutations/notes/reposition_image_diff_note_spec.rb2
-rw-r--r--spec/graphql/mutations/releases/delete_spec.rb92
-rw-r--r--spec/graphql/mutations/releases/update_spec.rb232
-rw-r--r--spec/graphql/resolvers/alert_management/alert_resolver_spec.rb12
-rw-r--r--spec/graphql/resolvers/base_resolver_spec.rb8
-rw-r--r--spec/graphql/resolvers/board_list_issues_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/board_lists_resolver_spec.rb12
-rw-r--r--spec/graphql/resolvers/ci/config_resolver_spec.rb56
-rw-r--r--spec/graphql/resolvers/ci/jobs_resolver_spec.rb20
-rw-r--r--spec/graphql/resolvers/commit_pipelines_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb83
-rw-r--r--spec/graphql/resolvers/concerns/looks_ahead_spec.rb3
-rw-r--r--spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb6
-rw-r--r--spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb6
-rw-r--r--spec/graphql/resolvers/design_management/versions_resolver_spec.rb18
-rw-r--r--spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/issue_status_counts_resolver_spec.rb11
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb48
-rw-r--r--spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/merge_requests_resolver_spec.rb22
-rw-r--r--spec/graphql/resolvers/project_merge_requests_resolver_spec.rb26
-rw-r--r--spec/graphql/resolvers/project_pipeline_resolver_spec.rb19
-rw-r--r--spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb36
-rw-r--r--spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb73
-rw-r--r--spec/graphql/resolvers/projects/snippets_resolver_spec.rb26
-rw-r--r--spec/graphql/resolvers/releases_resolver_spec.rb21
-rw-r--r--spec/graphql/resolvers/snippets/blobs_resolver_spec.rb26
-rw-r--r--spec/graphql/resolvers/snippets_resolver_spec.rb11
-rw-r--r--spec/graphql/resolvers/todo_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/user_discussions_count_resolver_spec.rb54
-rw-r--r--spec/graphql/resolvers/user_notes_count_resolver_spec.rb93
-rw-r--r--spec/graphql/resolvers/users/snippets_resolver_spec.rb13
-rw-r--r--spec/graphql/types/alert_management/domain_filter_enum_spec.rb11
-rw-r--r--spec/graphql/types/alert_management/prometheus_integration_type_spec.rb5
-rw-r--r--spec/graphql/types/base_field_spec.rb10
-rw-r--r--spec/graphql/types/ci/analytics_type_spec.rb23
-rw-r--r--spec/graphql/types/ci/config/config_type_spec.rb18
-rw-r--r--spec/graphql/types/ci/config/group_type_spec.rb17
-rw-r--r--spec/graphql/types/ci/config/job_type_spec.rb18
-rw-r--r--spec/graphql/types/ci/config/need_type_spec.rb15
-rw-r--r--spec/graphql/types/ci/config/stage_type_spec.rb16
-rw-r--r--spec/graphql/types/ci/job_artifact_file_type_enum_spec.rb11
-rw-r--r--spec/graphql/types/ci/job_artifact_type_spec.rb11
-rw-r--r--spec/graphql/types/ci/job_type_spec.rb1
-rw-r--r--spec/graphql/types/ci/pipeline_type_spec.rb15
-rw-r--r--spec/graphql/types/commit_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/countable_connection_type_spec.rb2
-rw-r--r--spec/graphql/types/group_member_relation_enum_spec.rb11
-rw-r--r--spec/graphql/types/group_type_spec.rb2
-rw-r--r--spec/graphql/types/merge_request_connection_type_spec.rb11
-rw-r--r--spec/graphql/types/merge_request_type_spec.rb11
-rw-r--r--spec/graphql/types/permission_types/base_permission_type_spec.rb6
-rw-r--r--spec/graphql/types/project_member_relation_enum_spec.rb11
-rw-r--r--spec/graphql/types/project_type_spec.rb34
-rw-r--r--spec/graphql/types/terraform/state_version_type_spec.rb4
-rw-r--r--spec/graphql/types/user_type_spec.rb3
75 files changed, 1279 insertions, 296 deletions
diff --git a/spec/graphql/features/authorization_spec.rb b/spec/graphql/features/authorization_spec.rb
index e40c44925e2..ec67ed16fe9 100644
--- a/spec/graphql/features/authorization_spec.rb
+++ b/spec/graphql/features/authorization_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
describe 'with a single permission' do
let(:query_type) do
query_factory do |query|
- query.field :item, type, null: true, resolve: ->(obj, args, ctx) { test_object }, authorize: permission_single
+ query.field :item, type, null: true, resolver: simple_resolver(test_object), authorize: permission_single
end
end
@@ -66,7 +66,7 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
let(:query_type) do
permissions = permission_collection
query_factory do |qt|
- qt.field :item, type, null: true, resolve: ->(obj, args, ctx) { test_object } do
+ qt.field :item, type, null: true, resolver: simple_resolver(test_object) do
authorize permissions
end
end
@@ -79,7 +79,7 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
describe 'Field authorizations when field is a built in type' do
let(:query_type) do
query_factory do |query|
- query.field :item, type, null: true, resolve: ->(obj, args, ctx) { test_object }
+ query.field :item, type, null: true, resolver: simple_resolver(test_object)
end
end
@@ -132,7 +132,7 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
describe 'Type authorizations' do
let(:query_type) do
query_factory do |query|
- query.field :item, type, null: true, resolve: ->(obj, args, ctx) { test_object }
+ query.field :item, type, null: true, resolver: simple_resolver(test_object)
end
end
@@ -169,7 +169,7 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
let(:query_type) do
query_factory do |query|
- query.field :item, type, null: true, resolve: ->(obj, args, ctx) { test_object }, authorize: permission_2
+ query.field :item, type, null: true, resolver: simple_resolver(test_object), authorize: permission_2
end
end
@@ -188,7 +188,7 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
let(:query_type) do
query_factory do |query|
- query.field :item, type.connection_type, null: true, resolve: ->(obj, args, ctx) { [test_object, second_test_object] }
+ query.field :item, type.connection_type, null: true, resolver: simple_resolver([test_object, second_test_object])
end
end
@@ -208,9 +208,7 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
describe 'limiting connections with multiple objects' do
let(:query_type) do
query_factory do |query|
- query.field :item, type.connection_type, null: true, resolve: ->(obj, args, ctx) do
- [test_object, second_test_object]
- end
+ query.field :item, type.connection_type, null: true, resolver: simple_resolver([test_object, second_test_object])
end
end
@@ -234,7 +232,7 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
let(:query_type) do
query_factory do |query|
- query.field :item, [type], null: true, resolve: ->(obj, args, ctx) { [test_object] }
+ query.field :item, [type], null: true, resolver: simple_resolver([test_object])
end
end
@@ -262,13 +260,13 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
type_factory do |type|
type.graphql_name 'FakeProjectType'
type.field :test_issues, issue_type.connection_type, null: false,
- resolve: -> (_, _, _) { Issue.where(project: [visible_project, other_project]).order(id: :asc) }
+ resolver: simple_resolver(Issue.where(project: [visible_project, other_project]).order(id: :asc))
end
end
let(:query_type) do
query_factory do |query|
- query.field :test_project, project_type, null: false, resolve: -> (_, _, _) { visible_project }
+ query.field :test_project, project_type, null: false, resolver: simple_resolver(visible_project)
end
end
diff --git a/spec/graphql/features/feature_flag_spec.rb b/spec/graphql/features/feature_flag_spec.rb
index 9ebc6e595a6..77810f78257 100644
--- a/spec/graphql/features/feature_flag_spec.rb
+++ b/spec/graphql/features/feature_flag_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'Graphql Field feature flags' do
let(:query_type) do
query_factory do |query|
- query.field :item, type, null: true, feature_flag: feature_flag, resolve: ->(obj, args, ctx) { test_object }
+ query.field :item, type, null: true, feature_flag: feature_flag, resolver: simple_resolver(test_object)
end
end
diff --git a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb
index e6a7434d579..47ee338ad34 100644
--- a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb
+++ b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb
@@ -28,6 +28,7 @@ RSpec.describe Mutations::AlertManagement::CreateAlertIssue do
end
it_behaves_like 'an incident management tracked event', :incident_management_incident_created
+ it_behaves_like 'an incident management tracked event', :incident_management_alert_create_incident
end
context 'when CreateAlertIssue responds with an error' do
diff --git a/spec/graphql/mutations/alert_management/http_integration/destroy_spec.rb b/spec/graphql/mutations/alert_management/http_integration/destroy_spec.rb
index f74f9186743..acd7070d0d3 100644
--- a/spec/graphql/mutations/alert_management/http_integration/destroy_spec.rb
+++ b/spec/graphql/mutations/alert_management/http_integration/destroy_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Mutations::AlertManagement::HttpIntegration::Destroy do
specify { expect(described_class).to require_graphql_authorizations(:admin_operations) }
describe '#resolve' do
- subject(:resolve) { mutation_for(project, current_user).resolve(args) }
+ subject(:resolve) { mutation_for(project, current_user).resolve(**args) }
context 'user has access to project' do
before do
diff --git a/spec/graphql/mutations/alert_management/http_integration/reset_token_spec.rb b/spec/graphql/mutations/alert_management/http_integration/reset_token_spec.rb
index d3ffb2abb47..96974c2aa6f 100644
--- a/spec/graphql/mutations/alert_management/http_integration/reset_token_spec.rb
+++ b/spec/graphql/mutations/alert_management/http_integration/reset_token_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Mutations::AlertManagement::HttpIntegration::ResetToken do
specify { expect(described_class).to require_graphql_authorizations(:admin_operations) }
describe '#resolve' do
- subject(:resolve) { mutation_for(project, current_user).resolve(args) }
+ subject(:resolve) { mutation_for(project, current_user).resolve(**args) }
context 'user has sufficient access to project' do
before do
diff --git a/spec/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb b/spec/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb
index 45d92695e06..ddf23909035 100644
--- a/spec/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb
+++ b/spec/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Mutations::AlertManagement::PrometheusIntegration::ResetToken do
specify { expect(described_class).to require_graphql_authorizations(:admin_project) }
describe '#resolve' do
- subject(:resolve) { mutation_for(project, current_user).resolve(args) }
+ subject(:resolve) { mutation_for(project, current_user).resolve(**args) }
context 'user has sufficient access to project' do
before do
diff --git a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb
index 08761ce64c2..8465393f299 100644
--- a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb
+++ b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Mutations::AlertManagement::UpdateAlertStatus do
specify { expect(described_class).to require_graphql_authorizations(:update_alert_management_alert) }
describe '#resolve' do
- subject(:resolve) { mutation_for(project, current_user).resolve(args) }
+ subject(:resolve) { mutation_for(project, current_user).resolve(**args) }
context 'user has access to project' do
before do
diff --git a/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb b/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb
index 71c43ed826c..24104a20465 100644
--- a/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb
+++ b/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb
@@ -34,18 +34,18 @@ RSpec.describe Mutations::Boards::Issues::IssueMoveList do
end
subject do
- mutation.resolve(params.merge(move_params))
+ mutation.resolve(**params.merge(move_params))
end
describe '#ready?' do
it 'raises an error if required arguments are missing' do
- expect { mutation.ready?(params) }
+ expect { mutation.ready?(**params) }
.to raise_error(Gitlab::Graphql::Errors::ArgumentError, "At least one of the arguments " \
"fromListId, toListId, afterId or beforeId is required")
end
it 'raises an error if only one of fromListId and toListId is present' do
- expect { mutation.ready?(params.merge(from_list_id: list1.id)) }
+ expect { mutation.ready?(**params.merge(from_list_id: list1.id)) }
.to raise_error(Gitlab::Graphql::Errors::ArgumentError,
'Both fromListId and toListId must be present'
)
@@ -73,18 +73,6 @@ RSpec.describe Mutations::Boards::Issues::IssueMoveList do
it_behaves_like 'raises a resource not available error'
end
-
- context 'when user cannot access board' do
- let(:board) { create(:board, group: create(:group, :private)) }
-
- it_behaves_like 'raises a resource not available error'
- end
-
- context 'when passing board_id as nil' do
- let(:board) { nil }
-
- it_behaves_like 'raises a resource not available error'
- end
end
end
end
diff --git a/spec/graphql/mutations/boards/lists/create_spec.rb b/spec/graphql/mutations/boards/lists/create_spec.rb
index b1fe9911c7b..894dd1f34b4 100644
--- a/spec/graphql/mutations/boards/lists/create_spec.rb
+++ b/spec/graphql/mutations/boards/lists/create_spec.rb
@@ -23,12 +23,12 @@ RSpec.describe Mutations::Boards::Lists::Create do
describe '#ready?' do
it 'raises an error if required arguments are missing' do
- expect { mutation.ready?({ board_id: 'some id' }) }
+ expect { mutation.ready?(board_id: 'some id') }
.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/)
end
it 'raises an error if too many required arguments are specified' do
- expect { mutation.ready?({ board_id: 'some id', backlog: true, label_id: 'some label' }) }
+ expect { mutation.ready?(board_id: 'some id', backlog: true, label_id: 'some label') }
.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/)
end
end
@@ -68,9 +68,8 @@ RSpec.describe Mutations::Boards::Lists::Create do
context 'when label not found' do
let(:list_create_params) { { label_id: "gid://gitlab/Label/#{non_existing_record_id}" } }
- it 'raises an error' do
- expect { subject }
- .to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'Label not found!')
+ it 'returns an error' do
+ expect(subject[:errors]).to include 'Label not found'
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
new file mode 100644
index 00000000000..37e0fd611e4
--- /dev/null
+++ b/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::FindsByGid do
+ include GraphqlHelpers
+
+ let(:mutation_class) do
+ Class.new(Mutations::BaseMutation) do
+ authorize :read_user
+
+ include Mutations::FindsByGid
+ end
+ end
+
+ let(:query) { double('Query', 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 }
+
+ subject(:mutation) { mutation_class.new(object: nil, context: context, field: nil) }
+
+ it 'calls GitlabSchema.find_by_gid to find objects during authorized_find!' do
+ expect(mutation.authorized_find!(id: gid)).to eq(user)
+ end
+end
diff --git a/spec/graphql/mutations/container_expiration_policies/update_spec.rb b/spec/graphql/mutations/container_expiration_policies/update_spec.rb
index 9c6016e0af4..e22fb951172 100644
--- a/spec/graphql/mutations/container_expiration_policies/update_spec.rb
+++ b/spec/graphql/mutations/container_expiration_policies/update_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe Mutations::ContainerExpirationPolicies::Update do
specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) }
describe '#resolve' do
- subject { described_class.new(object: project, context: { current_user: user }, field: nil).resolve(params) }
+ subject { described_class.new(object: project, context: { current_user: user }, field: nil).resolve(**params) }
RSpec.shared_examples 'returning a success' do
it 'returns the container expiration policy with no errors' do
diff --git a/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb b/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb
new file mode 100644
index 00000000000..f22d9ffe753
--- /dev/null
+++ b/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::ContainerRepositories::DestroyTags do
+ include_context 'container repository delete tags service shared context'
+ using RSpec::Parameterized::TableSyntax
+
+ let(:id) { repository.to_global_id.to_s }
+
+ specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) }
+
+ describe '#resolve' do
+ let(:tags) { %w[A C D E] }
+
+ subject do
+ described_class.new(object: nil, context: { current_user: user }, field: nil)
+ .resolve(id: id, tag_names: tags)
+ end
+
+ shared_examples 'destroying container repository tags' do
+ before do
+ stub_delete_reference_requests(tags)
+ expect_delete_tag_by_names(tags)
+ allow_next_instance_of(ContainerRegistry::Client) do |client|
+ allow(client).to receive(:supports_tag_delete?).and_return(true)
+ end
+ end
+
+ it 'destroys the container repository tags' do
+ expect(Projects::ContainerRepository::DeleteTagsService)
+ .to receive(:new).and_call_original
+
+ expect(subject).to eq(errors: [], deleted_tag_names: tags)
+ end
+
+ it 'creates a package event' do
+ expect(::Packages::CreateEventService)
+ .to receive(:new).with(nil, user, event_name: :delete_tag_bulk, scope: :tag).and_call_original
+ expect { subject }.to change { ::Packages::Event.count }.by(1)
+ end
+ end
+
+ shared_examples 'denying access to container respository' do
+ it 'raises an error' do
+ expect(::Projects::ContainerRepository::DeleteTagsService).not_to receive(:new)
+
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'with valid id' do
+ where(:user_role, :shared_examples_name) do
+ :maintainer | 'destroying container repository tags'
+ :developer | 'destroying container repository tags'
+ :reporter | 'denying access to container respository'
+ :guest | 'denying access to container respository'
+ :anonymous | 'denying access to container respository'
+ end
+
+ with_them do
+ before do
+ project.send("add_#{user_role}", user) unless user_role == :anonymous
+ end
+
+ 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
+
+ context 'with service error' do
+ before do
+ project.add_maintainer(user)
+ allow_next_instance_of(Projects::ContainerRepository::DeleteTagsService) do |service|
+ allow(service).to receive(:execute).and_return(message: 'could not delete tags', status: :error)
+ end
+ end
+
+ it { is_expected.to eq(errors: ['could not delete tags'], deleted_tag_names: []) }
+
+ it 'does not create a package event' do
+ expect(::Packages::CreateEventService).not_to receive(:new)
+ expect { subject }.not_to change { ::Packages::Event.count }
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb
index 2e5d41a8f1e..162b1249ab5 100644
--- a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb
+++ b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Mutations::Discussions::ToggleResolve do
describe '#resolve' do
subject do
- mutation.resolve({ id: id_arg, resolve: resolve_arg })
+ mutation.resolve(id: id_arg, resolve: resolve_arg)
end
let(:id_arg) { discussion.to_global_id.to_s }
diff --git a/spec/graphql/mutations/environments/canary_ingress/update_spec.rb b/spec/graphql/mutations/environments/canary_ingress/update_spec.rb
new file mode 100644
index 00000000000..c022828cf09
--- /dev/null
+++ b/spec/graphql/mutations/environments/canary_ingress/update_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Environments::CanaryIngress::Update do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:environment) { create(:environment, project: project) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let(:user) { maintainer }
+
+ subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
+
+ before_all do
+ project.add_maintainer(maintainer)
+ project.add_reporter(reporter)
+ end
+
+ describe '#resolve' do
+ subject { mutation.resolve(id: environment_id, weight: weight) }
+
+ let(:environment_id) { environment.to_global_id.to_s }
+ let(:weight) { 50 }
+ let(:update_service) { double('update_service') }
+
+ before do
+ allow(Environments::CanaryIngress::UpdateService).to receive(:new) { update_service }
+ end
+
+ context 'when service execution succeeded' do
+ before do
+ allow(update_service).to receive(:execute_async) { { status: :success } }
+ end
+
+ it 'returns no errors' do
+ expect(subject[:errors]).to be_empty
+ end
+ end
+
+ context 'when service encounters a problem' do
+ before do
+ allow(update_service).to receive(:execute_async) { { status: :error, message: 'something went wrong' } }
+ end
+
+ it 'returns an error' do
+ expect(subject[:errors]).to eq(['something went wrong'])
+ 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 }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error("The resource that you are attempting to access does not exist or you don't have permission to perform this action")
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/issues/create_spec.rb b/spec/graphql/mutations/issues/create_spec.rb
index 57658f6b358..422ad40a9cb 100644
--- a/spec/graphql/mutations/issues/create_spec.rb
+++ b/spec/graphql/mutations/issues/create_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe Mutations::Issues::Create do
project.add_guest(assignee2)
end
- subject { mutation.resolve(mutation_params) }
+ subject { mutation.resolve(**mutation_params) }
context 'when the user does not have permission to create an issue' do
it 'raises an error' do
@@ -117,7 +117,7 @@ RSpec.describe Mutations::Issues::Create do
end
it 'raises exception when mutually exclusive params are given' do
- expect { mutation.ready?(mutation_params) }
+ expect { mutation.ready?(**mutation_params) }
.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/)
end
end
@@ -128,7 +128,7 @@ RSpec.describe Mutations::Issues::Create do
end
it 'raises exception when mutually exclusive params are given' do
- expect { mutation.ready?(mutation_params) }
+ expect { mutation.ready?(**mutation_params) }
.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /to resolve a discussion please also provide `merge_request_to_resolve_discussions_of` parameter/)
end
end
@@ -139,7 +139,7 @@ RSpec.describe Mutations::Issues::Create do
end
it 'raises exception when mutually exclusive params are given' do
- expect { mutation.ready?(mutation_params) }.not_to raise_error
+ expect { mutation.ready?(**mutation_params) }.not_to raise_error
end
end
end
diff --git a/spec/graphql/mutations/issues/update_spec.rb b/spec/graphql/mutations/issues/update_spec.rb
index ce1eb874bcf..f10e257e153 100644
--- a/spec/graphql/mutations/issues/update_spec.rb
+++ b/spec/graphql/mutations/issues/update_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe Mutations::Issues::Update do
}.merge(expected_attributes)
end
- subject { mutation.resolve(mutation_params) }
+ subject { mutation.resolve(**mutation_params) }
it_behaves_like 'permission level for issue mutation is correctly verified'
diff --git a/spec/graphql/mutations/labels/create_spec.rb b/spec/graphql/mutations/labels/create_spec.rb
index 8b284816d63..b2dd94f31bb 100644
--- a/spec/graphql/mutations/labels/create_spec.rb
+++ b/spec/graphql/mutations/labels/create_spec.rb
@@ -58,7 +58,7 @@ RSpec.describe Mutations::Labels::Create do
end
describe '#ready?' do
- subject { mutation.ready?(attributes.merge(extra_params)) }
+ subject { mutation.ready?(**attributes.merge(extra_params)) }
context 'when passing both project_path and group_path' do
let(:extra_params) { { project_path: 'foo', group_path: 'bar' } }
diff --git a/spec/graphql/mutations/notes/reposition_image_diff_note_spec.rb b/spec/graphql/mutations/notes/reposition_image_diff_note_spec.rb
index 8c22e1a1cb6..d88b196cbff 100644
--- a/spec/graphql/mutations/notes/reposition_image_diff_note_spec.rb
+++ b/spec/graphql/mutations/notes/reposition_image_diff_note_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Mutations::Notes::RepositionImageDiffNote do
describe '#resolve' do
subject do
- mutation.resolve({ note: note, position: new_position })
+ mutation.resolve(note: note, position: new_position)
end
let_it_be(:noteable) { create(:merge_request) }
diff --git a/spec/graphql/mutations/releases/delete_spec.rb b/spec/graphql/mutations/releases/delete_spec.rb
new file mode 100644
index 00000000000..bedb72b002c
--- /dev/null
+++ b/spec/graphql/mutations/releases/delete_spec.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Releases::Delete do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:non_project_member) { create(:user) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:tag) { 'v1.1.0'}
+ let_it_be(:release) { create(:release, project: project, tag: tag) }
+
+ let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
+
+ let(:mutation_arguments) do
+ {
+ project_path: project.full_path,
+ tag: tag
+ }
+ end
+
+ before do
+ project.add_developer(developer)
+ project.add_maintainer(maintainer)
+ end
+
+ shared_examples 'unauthorized or not found error' do
+ it 'raises a Gitlab::Graphql::Errors::ResourceNotAvailable error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable, "The resource that you are attempting to access does not exist or you don't have permission to perform this action")
+ end
+ end
+
+ describe '#resolve' do
+ subject(:resolve) do
+ mutation.resolve(**mutation_arguments)
+ end
+
+ context 'when the current user has access to create releases' do
+ let(:current_user) { maintainer }
+
+ it 'deletes the release' do
+ expect { subject }.to change { Release.count }.by(-1)
+ end
+
+ it 'returns the deleted release' do
+ expect(subject[:release].tag).to eq(tag)
+ end
+
+ it 'does not remove the Git tag associated with the deleted release' do
+ expect { subject }.not_to change { Project.find_by_id(project.id).repository.tag_count }
+ end
+
+ it 'returns no errors' do
+ expect(subject[:errors]).to eq([])
+ end
+
+ context 'validation' do
+ context 'when the release does not exist' do
+ let(:mutation_arguments) { super().merge(tag: 'not-a-real-release') }
+
+ it 'returns the release as nil' do
+ expect(subject[:release]).to be_nil
+ end
+
+ it 'returns an errors-at-data message' do
+ expect(subject[:errors]).to eq(['Release does not exist'])
+ end
+ end
+
+ context 'when the project does not exist' do
+ let(:mutation_arguments) { super().merge(project_path: 'not/a/real/path') }
+
+ it_behaves_like 'unauthorized or not found error'
+ end
+ end
+ end
+
+ context "when the current user doesn't have access to update releases" do
+ context 'when the user is a developer' do
+ let(:current_user) { developer }
+
+ it_behaves_like 'unauthorized or not found error'
+ end
+
+ context 'when the user is a non-project member' do
+ let(:current_user) { non_project_member }
+
+ it_behaves_like 'unauthorized or not found error'
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/releases/update_spec.rb b/spec/graphql/mutations/releases/update_spec.rb
new file mode 100644
index 00000000000..0406e9c96f3
--- /dev/null
+++ b/spec/graphql/mutations/releases/update_spec.rb
@@ -0,0 +1,232 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Releases::Update do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:milestone_12_3) { create(:milestone, project: project, title: '12.3') }
+ let_it_be(:milestone_12_4) { create(:milestone, project: project, title: '12.4') }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:developer) { create(:user) }
+
+ let_it_be(:tag) { 'v1.1.0'}
+ let_it_be(:name) { 'Version 1.0'}
+ let_it_be(:description) { 'The first release :rocket:' }
+ let_it_be(:released_at) { Time.parse('2018-12-10').utc }
+ let_it_be(:created_at) { Time.parse('2018-11-05').utc }
+ let_it_be(:milestones) { [milestone_12_3.title, milestone_12_4.title] }
+
+ let_it_be(:release) do
+ create(:release, project: project, tag: tag, name: name,
+ description: description, released_at: released_at,
+ created_at: created_at, milestones: [milestone_12_3, milestone_12_4])
+ end
+
+ let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
+
+ let(:mutation_arguments) do
+ {
+ project_path: project.full_path,
+ tag: tag
+ }
+ end
+
+ around do |example|
+ freeze_time { example.run }
+ end
+
+ before do
+ project.add_reporter(reporter)
+ project.add_developer(developer)
+ end
+
+ shared_examples 'no changes to the release except for the' do |except_for|
+ it 'does not change other release properties' do
+ expect(updated_release.project).to eq(project)
+ expect(updated_release.tag).to eq(tag)
+
+ expect(updated_release.name).to eq(name) unless except_for == :name
+ expect(updated_release.description).to eq(description) unless except_for == :description
+ expect(updated_release.released_at).to eq(released_at) unless except_for == :released_at
+
+ # Right now the milestones are returned in a non-deterministic order.
+ # Because of this, we need to allow for milestones to be returned in any order.
+ # Once https://gitlab.com/gitlab-org/gitlab/-/issues/259012 has been
+ # fixed, this can be updated to expect a specific order.
+ expect(updated_release.milestones).to match_array([milestone_12_3, milestone_12_4]) unless except_for == :milestones
+ end
+ end
+
+ shared_examples 'validation error with message' do |message|
+ it 'returns the updated release as nil' do
+ expect(updated_release).to be_nil
+ end
+
+ it 'returns a validation error' do
+ expect(subject[:errors]).to eq([message])
+ end
+ end
+
+ describe '#ready?' do
+ let(:current_user) { developer }
+
+ subject(:ready) do
+ mutation.ready?(**mutation_arguments)
+ end
+
+ context 'when released_at is included as an argument but is passed nil' do
+ let(:mutation_arguments) { super().merge(released_at: nil) }
+
+ it 'raises a validation error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'if the releasedAt argument is provided, it cannot be null')
+ end
+ end
+
+ context 'when milestones is included as an argument but is passed nil' do
+ let(:mutation_arguments) { super().merge(milestones: nil) }
+
+ it 'raises a validation error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'if the milestones argument is provided, it cannot be null')
+ end
+ end
+ end
+
+ describe '#resolve' do
+ subject(:resolve) do
+ mutation.resolve(**mutation_arguments)
+ end
+
+ let(:updated_release) { subject[:release] }
+
+ context 'when the current user has access to create releases' do
+ let(:current_user) { developer }
+
+ context 'name' do
+ let(:mutation_arguments) { super().merge(name: updated_name) }
+
+ context 'when a new name is provided' do
+ let(:updated_name) { 'Updated name' }
+
+ it 'updates the name' do
+ expect(updated_release.name).to eq(updated_name)
+ end
+
+ it_behaves_like 'no changes to the release except for the', :name
+ end
+
+ context 'when nil is provided' do
+ let(:updated_name) { nil }
+
+ it 'updates the name to be the tag name' do
+ expect(updated_release.name).to eq(tag)
+ end
+
+ it_behaves_like 'no changes to the release except for the', :name
+ end
+ end
+
+ context 'description' do
+ let(:mutation_arguments) { super().merge(description: updated_description) }
+
+ context 'when a new description is provided' do
+ let(:updated_description) { 'Updated description' }
+
+ it 'updates the description' do
+ expect(updated_release.description).to eq(updated_description)
+ end
+
+ it_behaves_like 'no changes to the release except for the', :description
+ end
+
+ context 'when nil is provided' do
+ let(:updated_description) { nil }
+
+ it 'updates the description to nil' do
+ expect(updated_release.description).to eq(nil)
+ end
+
+ it_behaves_like 'no changes to the release except for the', :description
+ end
+ end
+
+ context 'released_at' do
+ let(:mutation_arguments) { super().merge(released_at: updated_released_at) }
+
+ context 'when a new released_at is provided' do
+ let(:updated_released_at) { Time.parse('2020-12-10').utc }
+
+ it 'updates the released_at' do
+ expect(updated_release.released_at).to eq(updated_released_at)
+ end
+
+ it_behaves_like 'no changes to the release except for the', :released_at
+ end
+ end
+
+ context 'milestones' do
+ let(:mutation_arguments) { super().merge(milestones: updated_milestones) }
+
+ context 'when a new set of milestones is provided provided' do
+ let(:updated_milestones) { [milestone_12_3.title] }
+
+ it 'updates the milestone associations' do
+ expect(updated_release.milestones).to eq([milestone_12_3])
+ end
+
+ it_behaves_like 'no changes to the release except for the', :milestones
+ end
+
+ context 'when an empty array is provided' do
+ let(:updated_milestones) { [] }
+
+ it 'removes all milestone associations' do
+ expect(updated_release.milestones).to eq([])
+ end
+
+ it_behaves_like 'no changes to the release except for the', :milestones
+ end
+
+ context 'when a non-existent milestone title is provided' do
+ let(:updated_milestones) { ['not real'] }
+
+ it_behaves_like 'validation error with message', 'Milestone(s) not found: not real'
+ end
+
+ context 'when a milestone title from a different project is provided' do
+ let(:milestone_in_different_project) { create(:milestone, title: 'milestone in different project') }
+ let(:updated_milestones) { [milestone_in_different_project.title] }
+
+ it_behaves_like 'validation error with message', 'Milestone(s) not found: milestone in different project'
+ end
+ end
+
+ context 'validation' do
+ context 'when no updated fields are provided' do
+ it_behaves_like 'validation error with message', 'params is empty'
+ end
+
+ context 'when the tag does not exist' do
+ let(:mutation_arguments) { super().merge(tag: 'not-a-real-tag') }
+
+ it_behaves_like 'validation error with message', 'Tag does not exist'
+ end
+
+ context 'when the project does not exist' do
+ let(:mutation_arguments) { super().merge(project_path: 'not/a/real/path') }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable, "The resource that you are attempting to access does not exist or you don't have permission to perform this action")
+ end
+ end
+ end
+ end
+
+ context "when the current user doesn't have access to update releases" do
+ let(:current_user) { reporter }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable, "The resource that you are attempting to access does not exist or you don't have permission to perform this action")
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb b/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
index 42830f0024d..c042f6dac19 100644
--- a/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
+++ b/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
@@ -33,11 +33,21 @@ RSpec.describe Resolvers::AlertManagement::AlertResolver do
end
context 'finding by status' do
- let(:args) { { status: [Types::AlertManagement::StatusEnum.values['IGNORED'].value] } }
+ let(:args) { { statuses: [Types::AlertManagement::StatusEnum.values['IGNORED'].value] } }
it { is_expected.to contain_exactly(ignored_alert) }
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(:alert3) { create(:alert_management_alert, project: project, monitoring_tool: 'generic') }
+
+ let(:args) { { domain: 'operations' } }
+
+ it { is_expected.to contain_exactly(resolved_alert, ignored_alert, alert3) }
+ end
+
describe 'sorting' do
# Other sorting examples in spec/finders/alert_management/alerts_finder_spec.rb
context 'when sorting by events count' do
diff --git a/spec/graphql/resolvers/base_resolver_spec.rb b/spec/graphql/resolvers/base_resolver_spec.rb
index e5b9fb57e42..8a24b69eb6f 100644
--- a/spec/graphql/resolvers/base_resolver_spec.rb
+++ b/spec/graphql/resolvers/base_resolver_spec.rb
@@ -273,4 +273,12 @@ RSpec.describe Resolvers::BaseResolver do
end
end
end
+
+ describe '#offset_pagination' do
+ let(:instance) { resolver_instance(resolver) }
+
+ it 'is sugar for OffsetActiveRecordRelationConnection.new' do
+ expect(instance.offset_pagination(User.none)).to be_a(::Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection)
+ end
+ end
end
diff --git a/spec/graphql/resolvers/board_list_issues_resolver_spec.rb b/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
index 4ccf194522f..e7c56a526f4 100644
--- a/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe Resolvers::BoardListIssuesResolver do
end
it 'finds only issues matching filters' do
- result = resolve_board_list_issues(args: { filters: { label_name: label.title, not: { label_name: label2.title } } }).items
+ result = resolve_board_list_issues(args: { filters: { label_name: [label.title], not: { label_name: [label2.title] } } }).items
expect(result).to match_array([issue1, issue3])
end
diff --git a/spec/graphql/resolvers/board_lists_resolver_spec.rb b/spec/graphql/resolvers/board_lists_resolver_spec.rb
index c1d8041a1e0..71ebec4dc7e 100644
--- a/spec/graphql/resolvers/board_lists_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_lists_resolver_spec.rb
@@ -29,9 +29,7 @@ RSpec.describe Resolvers::BoardListsResolver do
context 'with unauthorized user' do
it 'raises an error' do
- expect do
- resolve_board_lists(current_user: unauth_user)
- end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ expect(resolve_board_lists(current_user: unauth_user)).to be_nil
end
end
@@ -101,12 +99,6 @@ RSpec.describe Resolvers::BoardListsResolver do
end
def resolve_board_lists(args: {}, current_user: user)
- context = GraphQL::Query::Context.new(
- query: OpenStruct.new(schema: nil),
- values: { current_user: current_user },
- object: nil
- )
-
- resolve(described_class, obj: board, args: args, ctx: context )
+ resolve(described_class, obj: board, args: args, ctx: { current_user: current_user })
end
end
diff --git a/spec/graphql/resolvers/ci/config_resolver_spec.rb b/spec/graphql/resolvers/ci/config_resolver_spec.rb
new file mode 100644
index 00000000000..6911acdb4ec
--- /dev/null
+++ b/spec/graphql/resolvers/ci/config_resolver_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Ci::ConfigResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ before do
+ yaml_processor_double = instance_double(::Gitlab::Ci::YamlProcessor)
+ allow(yaml_processor_double).to receive(:execute).and_return(fake_result)
+
+ allow(::Gitlab::Ci::YamlProcessor).to receive(:new).and_return(yaml_processor_double)
+ end
+
+ context 'with a valid .gitlab-ci.yml' do
+ let(:fake_result) do
+ ::Gitlab::Ci::YamlProcessor::Result.new(
+ ci_config: ::Gitlab::Ci::Config.new(content),
+ errors: [],
+ warnings: []
+ )
+ end
+
+ let_it_be(:content) do
+ File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_includes.yml'))
+ end
+
+ it 'lints the ci config file' do
+ response = resolve(described_class, args: { content: content }, ctx: {})
+
+ expect(response[:status]).to eq(:valid)
+ expect(response[:errors]).to be_empty
+ end
+ end
+
+ context 'with an invalid .gitlab-ci.yml' do
+ let(:content) { 'invalid' }
+
+ let(:fake_result) do
+ Gitlab::Ci::YamlProcessor::Result.new(
+ ci_config: nil,
+ errors: ['Invalid configuration format'],
+ warnings: []
+ )
+ end
+
+ it 'responds with errors about invalid syntax' do
+ response = resolve(described_class, args: { content: content }, ctx: {})
+
+ expect(response[:status]).to eq(:invalid)
+ expect(response[:errors]).to eq(['Invalid configuration format'])
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/ci/jobs_resolver_spec.rb b/spec/graphql/resolvers/ci/jobs_resolver_spec.rb
index a836c89bd61..46ee74a5f7e 100644
--- a/spec/graphql/resolvers/ci/jobs_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/jobs_resolver_spec.rb
@@ -17,10 +17,14 @@ RSpec.describe Resolvers::Ci::JobsResolver do
describe '#resolve' do
context 'when security_report_types is empty' do
it "returns all of the pipeline's jobs" do
- jobs = resolve(described_class, obj: pipeline, args: {}, ctx: {})
-
- job_names = jobs.map(&:name)
- expect(job_names).to contain_exactly('Normal job', 'DAST job', 'SAST job', 'Container scanning job')
+ jobs = resolve(described_class, obj: pipeline)
+
+ expect(jobs).to contain_exactly(
+ have_attributes(name: 'Normal job'),
+ have_attributes(name: 'DAST job'),
+ have_attributes(name: 'SAST job'),
+ have_attributes(name: 'Container scanning job')
+ )
end
end
@@ -30,10 +34,12 @@ RSpec.describe Resolvers::Ci::JobsResolver do
::Types::Security::ReportTypeEnum.values['SAST'].value,
::Types::Security::ReportTypeEnum.values['DAST'].value
]
- jobs = resolve(described_class, obj: pipeline, args: { security_report_types: report_types }, ctx: {})
+ jobs = resolve(described_class, obj: pipeline, args: { security_report_types: report_types })
- job_names = jobs.map(&:name)
- expect(job_names).to contain_exactly('DAST job', 'SAST job')
+ expect(jobs).to contain_exactly(
+ have_attributes(name: 'DAST job'),
+ have_attributes(name: 'SAST job')
+ )
end
end
end
diff --git a/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb b/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb
index a408981c08e..241a9e58147 100644
--- a/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb
+++ b/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb
@@ -50,6 +50,6 @@ RSpec.describe Resolvers::CommitPipelinesResolver do
it 'resolves pipelines for commit and ref' do
pipelines = resolve_pipelines
- expect(pipelines).to eq([pipeline2, pipeline])
+ expect(pipelines.to_a).to eq([pipeline2, pipeline])
end
end
diff --git a/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb b/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb
index b6fe94a2312..5370f7a7433 100644
--- a/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb
+++ b/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb
@@ -4,18 +4,25 @@ require 'spec_helper'
RSpec.describe ::CachingArrayResolver do
include GraphqlHelpers
+ include Gitlab::Graphql::Laziness
- let_it_be(:non_admins) { create_list(:user, 4, admin: false) }
- let(:query_context) { {} }
+ let_it_be(:admins) { create_list(:user, 4, admin: true) }
+ let(:query_context) { { current_user: admins.first } }
let(:max_page_size) { 10 }
let(:field) { double('Field', max_page_size: max_page_size) }
- let(:schema) { double('Schema', default_max_page_size: 3) }
+ let(:schema) do
+ Class.new(GitlabSchema) do
+ default_max_page_size 3
+ end
+ end
let_it_be(:caching_resolver) do
mod = described_class
Class.new(::Resolvers::BaseResolver) do
include mod
+ type [::Types::UserType], null: true
+ argument :is_admin, ::GraphQL::BOOLEAN_TYPE, required: false
def query_input(is_admin:)
is_admin
@@ -44,6 +51,8 @@ RSpec.describe ::CachingArrayResolver do
Class.new(::Resolvers::BaseResolver) do
include mod
+ type [::Types::UserType], null: true
+ argument :username, ::GraphQL::STRING_TYPE, required: false
def query_input(username:)
username
@@ -72,7 +81,7 @@ RSpec.describe ::CachingArrayResolver do
expect(User).to receive(:from_union).twice.and_call_original
results = users.in_groups_of(2, false).map do |users|
- resolve(resolver, args: { username: users.map(&:username) }, field: field, schema: schema)
+ resolve(resolver, args: { username: users.map(&:username) }, schema: schema)
end
expect(results.flat_map(&method(:force))).to match_array(users)
@@ -80,19 +89,19 @@ RSpec.describe ::CachingArrayResolver do
end
context 'all queries return results' do
- let_it_be(:admins) { create_list(:admin, 3) }
+ let_it_be(:non_admins) { create_list(:user, 3, admin: false) }
it 'batches the queries' do
expect do
- [resolve_users(true), resolve_users(false)].each(&method(:force))
- end.to issue_same_number_of_queries_as { force(resolve_users(nil)) }
+ [resolve_users(admin: true), resolve_users(admin: false)].each(&method(:force))
+ end.to issue_same_number_of_queries_as { force(resolve_users(admin: nil)) }
end
it 'finds the correct values' do
- found_admins = resolve_users(true)
- found_others = resolve_users(false)
- admins_again = resolve_users(true)
- found_all = resolve_users(nil)
+ found_admins = resolve_users(admin: true)
+ found_others = resolve_users(admin: false)
+ admins_again = resolve_users(admin: true)
+ found_all = resolve_users(admin: nil)
expect(force(found_admins)).to match_array(admins)
expect(force(found_others)).to match_array(non_admins)
@@ -104,37 +113,37 @@ RSpec.describe ::CachingArrayResolver do
it 'does not perform a union of a query with itself' do
expect(User).to receive(:where).once.and_call_original
- [resolve_users(false), resolve_users(false)].each(&method(:force))
+ [resolve_users(admin: false), resolve_users(admin: false)].each(&method(:force))
end
context 'one of the queries returns no results' do
it 'finds the correct values' do
- found_admins = resolve_users(true)
- found_others = resolve_users(false)
- found_all = resolve_users(nil)
+ found_admins = resolve_users(admin: true)
+ found_others = resolve_users(admin: false)
+ found_all = resolve_users(admin: nil)
- expect(force(found_admins)).to be_empty
- expect(force(found_others)).to match_array(non_admins)
- expect(force(found_all)).to match_array(non_admins)
+ expect(force(found_admins)).to match_array(admins)
+ expect(force(found_others)).to be_empty
+ expect(force(found_all)).to match_array(admins)
end
end
context 'one of the queries has already been cached' do
before do
- force(resolve_users(nil))
+ force(resolve_users(admin: nil))
end
it 'avoids further queries' do
expect do
- repeated_find = resolve_users(nil)
+ repeated_find = resolve_users(admin: nil)
- expect(force(repeated_find)).to match_array(non_admins)
+ expect(force(repeated_find)).to match_array(admins)
end.not_to exceed_query_limit(0)
end
end
context 'the resolver overrides item_found' do
- let_it_be(:admins) { create_list(:admin, 2) }
+ let_it_be(:non_admins) { create_list(:user, 2, admin: false) }
let(:query_context) do
{
found: { true => [], false => [], nil => [] }
@@ -150,14 +159,14 @@ RSpec.describe ::CachingArrayResolver do
end
it 'receives item_found for each key the item mapped to' do
- found_admins = resolve_users(true, with_item_found)
- found_all = resolve_users(nil, with_item_found)
+ found_admins = resolve_users(admin: true, resolver: with_item_found)
+ found_all = resolve_users(admin: nil, resolver: with_item_found)
[found_admins, found_all].each(&method(:force))
expect(query_context[:found]).to match({
- false => be_empty,
true => match_array(admins),
+ false => be_empty,
nil => match_array(admins + non_admins)
})
end
@@ -167,11 +176,11 @@ RSpec.describe ::CachingArrayResolver do
let(:max_page_size) { 2 }
it 'respects the max_page_size, on a per subset basis' do
- found_all = resolve_users(nil)
- found_others = resolve_users(false)
+ found_all = resolve_users(admin: nil)
+ found_admins = resolve_users(admin: true)
expect(force(found_all).size).to eq(2)
- expect(force(found_others).size).to eq(2)
+ expect(force(found_admins).size).to eq(2)
end
end
@@ -179,11 +188,11 @@ RSpec.describe ::CachingArrayResolver do
let(:max_page_size) { nil }
it 'takes the page size from schema.default_max_page_size' do
- found_all = resolve_users(nil)
- found_others = resolve_users(false)
+ found_all = resolve_users(admin: nil)
+ found_admins = resolve_users(admin: true)
expect(force(found_all).size).to eq(schema.default_max_page_size)
- expect(force(found_others).size).to eq(schema.default_max_page_size)
+ expect(force(found_admins).size).to eq(schema.default_max_page_size)
end
end
@@ -197,12 +206,10 @@ RSpec.describe ::CachingArrayResolver do
end
end
- def resolve_users(is_admin, resolver = caching_resolver)
- args = { is_admin: is_admin }
- resolve(resolver, args: args, field: field, ctx: query_context, schema: schema)
- end
-
- def force(lazy)
- ::Gitlab::Graphql::Lazy.force(lazy)
+ def resolve_users(admin:, resolver: caching_resolver)
+ args = { is_admin: admin }
+ opts = resolver.field_options
+ allow(resolver).to receive(:field_options).and_return(opts.merge(max_page_size: max_page_size))
+ resolve(resolver, args: args, ctx: query_context, schema: schema, field: field)
end
end
diff --git a/spec/graphql/resolvers/concerns/looks_ahead_spec.rb b/spec/graphql/resolvers/concerns/looks_ahead_spec.rb
index ebea9e5522b..27ac1572cab 100644
--- a/spec/graphql/resolvers/concerns/looks_ahead_spec.rb
+++ b/spec/graphql/resolvers/concerns/looks_ahead_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe LooksAhead do
# Simplified schema to test lookahead
let_it_be(:schema) do
- issues_resolver = Class.new(Resolvers::BaseResolver) do
+ issues_resolver = Class.new(GraphQL::Schema::Resolver) do
include LooksAhead
def resolve_with_lookahead(**args)
@@ -41,7 +41,6 @@ RSpec.describe LooksAhead do
field :issues, issue.connection_type,
null: true
field :issues_with_lookahead, issue.connection_type,
- extras: [:lookahead],
resolver: issues_resolver,
null: true
end
diff --git a/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb
index 850b9f8cc87..cc7e2f6814a 100644
--- a/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe Resolvers::DesignManagement::Version::DesignAtVersionResolver do
let(:all_singular_args) do
{
- design_at_version_id: global_id_of(dav(design)),
+ id: global_id_of(dav(design)),
design_id: global_id_of(design),
filename: design.filename
}
@@ -50,7 +50,7 @@ RSpec.describe Resolvers::DesignManagement::Version::DesignAtVersionResolver do
end
end
- %i[design_at_version_id design_id filename].each do |arg|
+ %i[id design_id filename].each do |arg|
describe "passing #{arg}" do
let(:args) { all_singular_args.slice(arg) }
@@ -71,7 +71,7 @@ RSpec.describe Resolvers::DesignManagement::Version::DesignAtVersionResolver do
describe 'attempting to retrieve an object not visible at this version' do
let(:design) { design_d }
- %i[design_at_version_id design_id filename].each do |arg|
+ %i[id design_id filename].each do |arg|
describe "passing #{arg}" do
let(:args) { all_singular_args.slice(arg) }
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 403261fc22a..b0fc78af2af 100644
--- a/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe Resolvers::DesignManagement::VersionInCollectionResolver do
end
context 'we pass an id' do
- let(:params) { { version_id: global_id_of(first_version) } }
+ let(:params) { { id: global_id_of(first_version) } }
it { is_expected.to eq(first_version) }
end
@@ -44,13 +44,13 @@ RSpec.describe Resolvers::DesignManagement::VersionInCollectionResolver do
end
context 'we pass an inconsistent mixture of sha and version id' do
- let(:params) { { sha: first_version.sha, version_id: global_id_of(create(:design_version)) } }
+ let(:params) { { sha: first_version.sha, id: global_id_of(create(:design_version)) } }
it { is_expected.to be_nil }
end
context 'we pass the id of something that is not a design_version' do
- let(:params) { { version_id: global_id_of(project) } }
+ let(:params) { { id: global_id_of(project) } }
let(:appropriate_error) { ::GraphQL::CoercionError }
it 'raises an appropriate error' do
diff --git a/spec/graphql/resolvers/design_management/versions_resolver_spec.rb b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
index 5bc1c555e9a..23d4d86c79a 100644
--- a/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
end
shared_examples 'a source of versions' do
- subject(:result) { resolve_versions(object) }
+ subject(:result) { resolve_versions(object)&.to_a }
let_it_be(:all_versions) { object.versions.ordered }
@@ -39,7 +39,7 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
context 'without constraints' do
it 'returns the ordered versions' do
- expect(result).to eq(all_versions)
+ expect(result.to_a).to eq(all_versions)
end
end
@@ -51,13 +51,13 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
end
context 'by earlier_or_equal_to_id' do
- let(:params) { { id: global_id_of(first_version) } }
+ let(:params) { { earlier_or_equal_to_id: global_id_of(first_version) } }
it_behaves_like 'a query for all_versions up to the first_version'
end
context 'by earlier_or_equal_to_sha' do
- let(:params) { { sha: first_version.sha } }
+ let(:params) { { earlier_or_equal_to_sha: first_version.sha } }
it_behaves_like 'a query for all_versions up to the first_version'
end
@@ -68,8 +68,8 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
# return successfully
let(:params) do
{
- sha: first_version.sha,
- id: global_id_of(first_version)
+ earlier_or_equal_to_sha: first_version.sha,
+ earlier_or_equal_to_id: global_id_of(first_version)
}
end
@@ -79,8 +79,8 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
context 'and they do not match' do
let(:params) do
{
- sha: first_version.sha,
- id: global_id_of(other_version)
+ earlier_or_equal_to_sha: first_version.sha,
+ earlier_or_equal_to_id: global_id_of(other_version)
}
end
@@ -111,7 +111,7 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
end
def resolve_versions(obj, context = { current_user: current_user })
- eager_resolve(resolver, obj: obj, args: params.merge(parent: parent), ctx: context)
+ eager_resolve(resolver, obj: obj, parent: parent, args: params, ctx: context)
end
end
end
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 edca11f40d7..170a602fb0d 100644
--- a/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb
+++ b/spec/graphql/resolvers/error_tracking/sentry_errors_resolver_spec.rb
@@ -88,8 +88,8 @@ RSpec.describe Resolvers::ErrorTracking::SentryErrorsResolver do
it 'sets the pagination variables' do
result = resolve_errors
- expect(result.next_cursor).to eq 'next'
- expect(result.previous_cursor).to eq 'prev'
+ expect(result.end_cursor).to eq 'next'
+ expect(result.start_cursor).to eq 'prev'
end
it 'returns an externally paginated array' do
diff --git a/spec/graphql/resolvers/issue_status_counts_resolver_spec.rb b/spec/graphql/resolvers/issue_status_counts_resolver_spec.rb
index 16eb190efc6..decc3569d6c 100644
--- a/spec/graphql/resolvers/issue_status_counts_resolver_spec.rb
+++ b/spec/graphql/resolvers/issue_status_counts_resolver_spec.rb
@@ -62,22 +62,13 @@ RSpec.describe Resolvers::IssueStatusCountsResolver do
end
it 'filters by issue type', :aggregate_failures do
- result = resolve_issue_status_counts(issue_types: ['incident'])
+ result = resolve_issue_status_counts(types: ['incident'])
expect(result.all).to eq 1
expect(result.opened).to eq 0
expect(result.closed).to eq 1
end
- # The state param is ignored in IssuableFinder#count_by_state
- it 'ignores state filter', :aggregate_failures do
- result = resolve_issue_status_counts(state: 'closed')
-
- expect(result.all).to eq 2
- expect(result.opened).to eq 1
- expect(result.closed).to eq 1
- end
-
private
def resolve_issue_status_counts(args = {}, context = { current_user: current_user })
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index 43cbd4d2bdd..f6f746a8572 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Resolvers::IssuesResolver do
include GraphqlHelpers
- let(:current_user) { create(:user) }
+ let_it_be(:current_user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
@@ -25,7 +25,7 @@ RSpec.describe Resolvers::IssuesResolver do
end
context "with a project" do
- before do
+ before_all do
project.add_developer(current_user)
create(:label_link, label: label1, target: issue1)
create(:label_link, label: label1, target: issue2)
@@ -43,11 +43,11 @@ RSpec.describe Resolvers::IssuesResolver do
end
it 'filters by milestone' do
- expect(resolve_issues(milestone_title: milestone.title)).to contain_exactly(issue1)
+ expect(resolve_issues(milestone_title: [milestone.title])).to contain_exactly(issue1)
end
it 'filters by assignee_username' do
- expect(resolve_issues(assignee_username: assignee.username)).to contain_exactly(issue2)
+ expect(resolve_issues(assignee_username: [assignee.username])).to contain_exactly(issue2)
end
it 'filters by two assignees' do
@@ -112,15 +112,19 @@ RSpec.describe Resolvers::IssuesResolver do
describe 'filters by issue_type' do
it 'filters by a single type' do
- expect(resolve_issues(issue_types: ['incident'])).to contain_exactly(issue1)
+ expect(resolve_issues(types: %w[incident])).to contain_exactly(issue1)
+ end
+
+ it 'filters by a single type, negative assertion' do
+ expect(resolve_issues(types: %w[issue])).not_to include(issue1)
end
it 'filters by more than one type' do
- expect(resolve_issues(issue_types: %w(incident issue))).to contain_exactly(issue1, issue2)
+ expect(resolve_issues(types: %w[incident issue])).to contain_exactly(issue1, issue2)
end
it 'ignores the filter if none given' do
- expect(resolve_issues(issue_types: [])).to contain_exactly(issue1, issue2)
+ expect(resolve_issues(types: [])).to contain_exactly(issue1, issue2)
end
end
@@ -143,44 +147,44 @@ RSpec.describe Resolvers::IssuesResolver do
describe 'sorting' do
context 'when sorting by created' do
it 'sorts issues ascending' do
- expect(resolve_issues(sort: 'created_asc')).to eq [issue1, issue2]
+ expect(resolve_issues(sort: 'created_asc').to_a).to eq [issue1, issue2]
end
it 'sorts issues descending' do
- expect(resolve_issues(sort: 'created_desc')).to eq [issue2, issue1]
+ expect(resolve_issues(sort: 'created_desc').to_a).to eq [issue2, issue1]
end
end
context 'when sorting by due date' do
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { create(:project, :public) }
let_it_be(:due_issue1) { create(:issue, project: project, due_date: 3.days.from_now) }
let_it_be(:due_issue2) { create(:issue, project: project, due_date: nil) }
let_it_be(:due_issue3) { create(:issue, project: project, due_date: 2.days.ago) }
let_it_be(:due_issue4) { create(:issue, project: project, due_date: nil) }
it 'sorts issues ascending' do
- expect(resolve_issues(sort: :due_date_asc)).to eq [due_issue3, due_issue1, due_issue4, due_issue2]
+ expect(resolve_issues(sort: :due_date_asc).to_a).to eq [due_issue3, due_issue1, due_issue4, due_issue2]
end
it 'sorts issues descending' do
- expect(resolve_issues(sort: :due_date_desc)).to eq [due_issue1, due_issue3, due_issue4, due_issue2]
+ expect(resolve_issues(sort: :due_date_desc).to_a).to eq [due_issue1, due_issue3, due_issue4, due_issue2]
end
end
context 'when sorting by relative position' do
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { create(:project, :public) }
let_it_be(:relative_issue1) { create(:issue, project: project, relative_position: 2000) }
let_it_be(:relative_issue2) { create(:issue, project: project, relative_position: nil) }
let_it_be(:relative_issue3) { create(:issue, project: project, relative_position: 1000) }
let_it_be(:relative_issue4) { create(:issue, project: project, relative_position: nil) }
it 'sorts issues ascending' do
- expect(resolve_issues(sort: :relative_position_asc)).to eq [relative_issue3, relative_issue1, relative_issue4, relative_issue2]
+ expect(resolve_issues(sort: :relative_position_asc).to_a).to eq [relative_issue3, relative_issue1, relative_issue4, relative_issue2]
end
end
context 'when sorting by priority' do
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { create(:project, :public) }
let_it_be(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) }
let_it_be(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) }
let_it_be(:priority_label1) { create(:label, project: project, priority: 1) }
@@ -200,7 +204,7 @@ RSpec.describe Resolvers::IssuesResolver do
end
context 'when sorting by label priority' do
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { create(:project, :public) }
let_it_be(:label1) { create(:label, project: project, priority: 1) }
let_it_be(:label2) { create(:label, project: project, priority: 5) }
let_it_be(:label3) { create(:label, project: project, priority: 10) }
@@ -219,7 +223,7 @@ RSpec.describe Resolvers::IssuesResolver do
end
context 'when sorting by milestone due date' do
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { create(:project, :public) }
let_it_be(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) }
let_it_be(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) }
let_it_be(:milestone_issue1) { create(:issue, project: project) }
@@ -236,17 +240,17 @@ RSpec.describe Resolvers::IssuesResolver do
end
context 'when sorting by severity' do
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { create(:project, :public) }
let_it_be(:issue_high_severity) { create_issue_with_severity(project, severity: :high) }
let_it_be(:issue_low_severity) { create_issue_with_severity(project, severity: :low) }
let_it_be(:issue_no_severity) { create(:incident, project: project) }
it 'sorts issues ascending' do
- expect(resolve_issues(sort: :severity_asc)).to eq([issue_no_severity, issue_low_severity, issue_high_severity])
+ expect(resolve_issues(sort: :severity_asc).to_a).to eq([issue_no_severity, issue_low_severity, issue_high_severity])
end
it 'sorts issues descending' do
- expect(resolve_issues(sort: :severity_desc)).to eq([issue_high_severity, issue_low_severity, issue_no_severity])
+ expect(resolve_issues(sort: :severity_desc).to_a).to eq([issue_high_severity, issue_low_severity, issue_no_severity])
end
end
end
@@ -267,7 +271,9 @@ RSpec.describe Resolvers::IssuesResolver do
it 'batches queries that only include IIDs', :request_store do
result = batch_sync(max_queries: 2) do
- resolve_issues(iid: issue1.iid) + resolve_issues(iids: issue2.iid)
+ [issue1, issue2]
+ .map { |issue| resolve_issues(iid: issue.iid.to_s) }
+ .flat_map(&:to_a)
end
expect(result).to contain_exactly(issue1, issue2)
diff --git a/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb b/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb
index deb5ff584cf..84ef906b72f 100644
--- a/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe Resolvers::MergeRequestPipelinesResolver do
end
def resolve_pipelines
- resolve(described_class, obj: merge_request, ctx: { current_user: current_user })
+ sync(resolve(described_class, obj: merge_request, ctx: { current_user: current_user }))
end
it 'resolves only MRs for the passed merge request' do
diff --git a/spec/graphql/resolvers/merge_requests_resolver_spec.rb b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
index 3a3393a185c..63fbd04848d 100644
--- a/spec/graphql/resolvers/merge_requests_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
@@ -75,9 +75,9 @@ RSpec.describe Resolvers::MergeRequestsResolver do
it 'can batch-resolve merge requests from different projects' do
# 2 queries for project_authorizations, and 2 for merge_requests
result = batch_sync(max_queries: queries_per_project * 2) do
- resolve_mr(project, iids: iid_1) +
- resolve_mr(project, iids: iid_2) +
- resolve_mr(other_project, iids: other_iid)
+ resolve_mr(project, iids: [iid_1]) +
+ resolve_mr(project, iids: [iid_2]) +
+ resolve_mr(other_project, iids: [other_iid])
end
expect(result).to contain_exactly(merge_request_1, merge_request_2, other_merge_request)
@@ -110,7 +110,7 @@ RSpec.describe Resolvers::MergeRequestsResolver do
context 'by source branches' do
it 'takes one argument' do
- result = resolve_mr(project, source_branch: [merge_request_3.source_branch])
+ result = resolve_mr(project, source_branches: [merge_request_3.source_branch])
expect(result).to contain_exactly(merge_request_3)
end
@@ -118,7 +118,7 @@ RSpec.describe Resolvers::MergeRequestsResolver do
it 'takes more than one argument' do
mrs = [merge_request_3, merge_request_4]
branches = mrs.map(&:source_branch)
- result = resolve_mr(project, source_branch: branches )
+ result = resolve_mr(project, source_branches: branches )
expect(result).to match_array(mrs)
end
@@ -126,7 +126,7 @@ RSpec.describe Resolvers::MergeRequestsResolver do
context 'by target branches' do
it 'takes one argument' do
- result = resolve_mr(project, target_branch: [merge_request_3.target_branch])
+ result = resolve_mr(project, target_branches: [merge_request_3.target_branch])
expect(result).to contain_exactly(merge_request_3)
end
@@ -134,7 +134,7 @@ RSpec.describe Resolvers::MergeRequestsResolver do
it 'takes more than one argument' do
mrs = [merge_request_3, merge_request_4]
branches = mrs.map(&:target_branch)
- result = resolve_mr(project, target_branch: branches )
+ result = resolve_mr(project, target_branches: branches )
expect(result.compact).to match_array(mrs)
end
@@ -153,13 +153,13 @@ RSpec.describe Resolvers::MergeRequestsResolver do
let_it_be(:with_label) { create(:labeled_merge_request, :closed, labels: [label], **common_attrs) }
it 'takes one argument' do
- result = resolve_mr(project, label_name: [label.title])
+ result = resolve_mr(project, labels: [label.title])
expect(result).to contain_exactly(merge_request_6, with_label)
end
it 'takes multiple arguments, with semantics of ALL MUST MATCH' do
- result = resolve_mr(project, label_name: merge_request_6.labels.map(&:title))
+ result = resolve_mr(project, labels: merge_request_6.labels.map(&:title))
expect(result).to contain_exactly(merge_request_6)
end
@@ -201,7 +201,7 @@ RSpec.describe Resolvers::MergeRequestsResolver do
it 'requires all filters' do
create(:merge_request, :closed, source_project: project, target_project: project, source_branch: merge_request_4.source_branch)
- result = resolve_mr(project, source_branch: [merge_request_4.source_branch], state: 'locked')
+ result = resolve_mr(project, source_branches: [merge_request_4.source_branch], state: 'locked')
expect(result.compact).to contain_exactly(merge_request_4)
end
@@ -236,7 +236,7 @@ RSpec.describe Resolvers::MergeRequestsResolver do
end
def resolve_mr_single(project, iid)
- resolve_mr(project, resolver: described_class.single, iids: iid)
+ resolve_mr(project, resolver: described_class.single, iid: iid.to_s)
end
def resolve_mr(project, resolver: described_class, user: current_user, **args)
diff --git a/spec/graphql/resolvers/project_merge_requests_resolver_spec.rb b/spec/graphql/resolvers/project_merge_requests_resolver_spec.rb
index bfb3ce91d58..45777aa96e1 100644
--- a/spec/graphql/resolvers/project_merge_requests_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_merge_requests_resolver_spec.rb
@@ -8,14 +8,16 @@ RSpec.describe Resolvers::ProjectMergeRequestsResolver do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:current_user) { create(:user) }
let_it_be(:other_user) { create(:user) }
+ let_it_be(:reviewer) { create(:user) }
- let_it_be(:merge_request_with_author_and_assignee) do
+ let_it_be(:merge_request) do
create(:merge_request,
:unique_branches,
source_project: project,
target_project: project,
author: other_user,
- assignee: other_user)
+ assignee: other_user,
+ reviewers: [reviewer])
end
before do
@@ -26,7 +28,7 @@ RSpec.describe Resolvers::ProjectMergeRequestsResolver do
it 'filters merge requests by assignee username' do
result = resolve_mr(project, assignee_username: other_user.username)
- expect(result).to eq([merge_request_with_author_and_assignee])
+ expect(result).to contain_exactly(merge_request)
end
it 'does not find anything' do
@@ -40,7 +42,7 @@ RSpec.describe Resolvers::ProjectMergeRequestsResolver do
it 'filters merge requests by author username' do
result = resolve_mr(project, author_username: other_user.username)
- expect(result).to eq([merge_request_with_author_and_assignee])
+ expect(result).to contain_exactly(merge_request)
end
it 'does not find anything' do
@@ -50,7 +52,21 @@ RSpec.describe Resolvers::ProjectMergeRequestsResolver do
end
end
- def resolve_mr(project, args, resolver: described_class, user: current_user)
+ context 'by reviewer' do
+ it 'filters merge requests by reviewer username' do
+ result = resolve_mr(project, reviewer_username: reviewer.username)
+
+ expect(result).to contain_exactly(merge_request)
+ end
+
+ it 'does not find anything' do
+ result = resolve_mr(project, reviewer_username: 'unknown-user')
+
+ expect(result).to be_empty
+ end
+ end
+
+ def resolve_mr(project, resolver: described_class, user: current_user, **args)
resolve(resolver, obj: project, args: args, ctx: { current_user: user })
end
end
diff --git a/spec/graphql/resolvers/project_pipeline_resolver_spec.rb b/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
index 1950c2ca067..b852b349d4f 100644
--- a/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
@@ -18,6 +18,10 @@ RSpec.describe Resolvers::ProjectPipelineResolver do
resolve(described_class, obj: project, args: args, ctx: { current_user: current_user })
end
+ before do
+ project.add_developer(current_user)
+ end
+
it 'resolves pipeline for the passed iid' do
result = batch_sync do
resolve_pipeline(project, { iid: '1234' })
@@ -26,6 +30,21 @@ RSpec.describe Resolvers::ProjectPipelineResolver do
expect(result).to eq(pipeline)
end
+ it 'keeps the queries under the threshold' do
+ create(:ci_pipeline, project: project, iid: '1235')
+
+ control = ActiveRecord::QueryRecorder.new do
+ batch_sync { resolve_pipeline(project, { iid: '1234' }) }
+ end
+
+ expect do
+ batch_sync do
+ resolve_pipeline(project, { iid: '1234' })
+ resolve_pipeline(project, { iid: '1235' })
+ end
+ end.not_to exceed_query_limit(control)
+ end
+
it 'does not resolve a pipeline outside the project' do
result = batch_sync do
resolve_pipeline(other_pipeline.project, { iid: '1234' })
diff --git a/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb b/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb
new file mode 100644
index 00000000000..c0367f7d42e
--- /dev/null
+++ b/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::ProjectPipelineStatisticsResolver do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+
+ specify do
+ expect(described_class).to have_nullable_graphql_type(::Types::Ci::AnalyticsType)
+ end
+
+ def resolve_statistics(project, args)
+ resolve(described_class, obj: project, args: args)
+ end
+
+ describe '#resolve' do
+ it 'returns the pipelines statistics for a given project' do
+ result = resolve_statistics(project, {})
+ expect(result.keys).to contain_exactly(
+ :week_pipelines_labels,
+ :week_pipelines_totals,
+ :week_pipelines_successful,
+ :month_pipelines_labels,
+ :month_pipelines_totals,
+ :month_pipelines_successful,
+ :year_pipelines_labels,
+ :year_pipelines_totals,
+ :year_pipelines_successful,
+ :pipeline_times_labels,
+ :pipeline_times_values
+ )
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb
deleted file mode 100644
index ad59cb6b95e..00000000000
--- a/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Resolvers::Projects::JiraImportsResolver do
- include GraphqlHelpers
-
- specify do
- expect(described_class).to have_nullable_graphql_type(Types::JiraImportType.connection_type)
- end
-
- describe '#resolve' do
- let_it_be(:user) { create(:user) }
- let_it_be(:project, reload: true) { create(:project, :public) }
-
- context 'when project does not have Jira imports' do
- let(:current_user) { user }
-
- context 'when user cannot read Jira imports' do
- context 'when anonymous user' do
- let(:current_user) { nil }
-
- it_behaves_like 'no Jira import access'
- end
- end
-
- context 'when user can read Jira import data' do
- before do
- project.add_guest(user)
- end
-
- it_behaves_like 'no Jira import data present'
-
- it 'does not raise access error' do
- expect do
- resolve_imports
- end.not_to raise_error
- end
- end
- end
-
- context 'when project has Jira imports' do
- let_it_be(:current_user) { user }
- let_it_be(:jira_import1) { create(:jira_import_state, :finished, project: project, jira_project_key: 'AA', created_at: 2.days.ago) }
- let_it_be(:jira_import2) { create(:jira_import_state, :finished, project: project, jira_project_key: 'BB', created_at: 5.days.ago) }
-
- context 'when user cannot read Jira imports' do
- context 'when anonymous user' do
- let(:current_user) { nil }
-
- it_behaves_like 'no Jira import access'
- end
- end
-
- context 'when user can access Jira imports' do
- before do
- project.add_guest(user)
- end
-
- it 'returns Jira imports sorted ascending by created_at time' do
- imports = resolve_imports
-
- expect(imports.size).to eq 2
- expect(imports.map(&:jira_project_key)).to eq %w(BB AA)
- end
- end
- end
- end
-
- def resolve_imports(args = {}, context = { current_user: current_user })
- resolve(described_class, obj: project, args: args, ctx: context)
- end
-end
diff --git a/spec/graphql/resolvers/projects/snippets_resolver_spec.rb b/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
index 6f7feff8fe5..2d8929c0e8f 100644
--- a/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/snippets_resolver_spec.rb
@@ -6,16 +6,18 @@ RSpec.describe Resolvers::Projects::SnippetsResolver do
include GraphqlHelpers
describe '#resolve' do
- let_it_be(:current_user) { create(:user) }
+ let_it_be(:user) { create(:user) }
let_it_be(:other_user) { create(:user) }
let_it_be(:project) { create(:project) }
- let_it_be(:personal_snippet) { create(:personal_snippet, :private, author: current_user) }
- let_it_be(:project_snippet) { create(:project_snippet, :internal, author: current_user, project: project) }
+ let_it_be(:personal_snippet) { create(:personal_snippet, :private, author: user) }
+ let_it_be(:project_snippet) { create(:project_snippet, :internal, author: user, project: project) }
let_it_be(:other_project_snippet) { create(:project_snippet, :public, author: other_user, project: project) }
- before do
- project.add_developer(current_user)
+ let(:current_user) { user }
+
+ before_all do
+ project.add_developer(user)
end
it 'calls SnippetsFinder' do
@@ -42,20 +44,26 @@ RSpec.describe Resolvers::Projects::SnippetsResolver do
end
it 'returns the snippets by gid' do
- snippets = resolve_snippets(args: { ids: project_snippet.to_global_id })
+ snippets = resolve_snippets(args: { ids: [global_id_of(project_snippet)] })
expect(snippets).to contain_exactly(project_snippet)
end
it 'returns the snippets by array of gid' do
args = {
- ids: [project_snippet.to_global_id, other_project_snippet.to_global_id]
+ ids: [global_id_of(project_snippet), global_id_of(other_project_snippet)]
}
snippets = resolve_snippets(args: args)
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
@@ -65,8 +73,10 @@ RSpec.describe Resolvers::Projects::SnippetsResolver do
end
context 'when provided user is not current user' do
+ let(:current_user) { other_user }
+
it 'returns no snippets' do
- expect(resolve_snippets(context: { current_user: other_user }, args: { ids: project_snippet.to_global_id })).to be_empty
+ expect(resolve_snippets(args: { ids: [global_id_of(project_snippet)] })).to be_empty
end
end
diff --git a/spec/graphql/resolvers/releases_resolver_spec.rb b/spec/graphql/resolvers/releases_resolver_spec.rb
index b9b90686aa7..89623be891f 100644
--- a/spec/graphql/resolvers/releases_resolver_spec.rb
+++ b/spec/graphql/resolvers/releases_resolver_spec.rb
@@ -17,6 +17,7 @@ RSpec.describe Resolvers::ReleasesResolver do
let_it_be(:public_user) { create(:user) }
let(:args) { { sort: :released_at_desc } }
+ let(:all_releases) { [release_v1, release_v2, release_v3] }
before do
project.add_developer(developer)
@@ -27,7 +28,7 @@ RSpec.describe Resolvers::ReleasesResolver do
let(:current_user) { public_user }
it 'returns an empty array' do
- expect(resolve_releases).to eq([])
+ expect(resolve_releases).to be_empty
end
end
@@ -35,7 +36,7 @@ RSpec.describe Resolvers::ReleasesResolver do
let(:current_user) { developer }
it 'returns all releases associated to the project' do
- expect(resolve_releases).to eq([release_v3, release_v2, release_v1])
+ expect(resolve_releases).to match_array(all_releases)
end
describe 'sorting behavior' do
@@ -43,7 +44,9 @@ RSpec.describe Resolvers::ReleasesResolver do
let(:args) { { sort: :released_at_desc } }
it 'returns the releases ordered by released_at in descending order' do
- expect(resolve_releases).to eq([release_v3, release_v2, release_v1])
+ expect(resolve_releases.to_a)
+ .to match_array(all_releases)
+ .and be_sorted(:released_at, :desc)
end
end
@@ -51,7 +54,9 @@ RSpec.describe Resolvers::ReleasesResolver do
let(:args) { { sort: :released_at_asc } }
it 'returns the releases ordered by released_at in ascending order' do
- expect(resolve_releases).to eq([release_v1, release_v2, release_v3])
+ expect(resolve_releases.to_a)
+ .to match_array(all_releases)
+ .and be_sorted(:released_at, :asc)
end
end
@@ -59,7 +64,9 @@ RSpec.describe Resolvers::ReleasesResolver do
let(:args) { { sort: :created_desc } }
it 'returns the releases ordered by created_at in descending order' do
- expect(resolve_releases).to eq([release_v1, release_v3, release_v2])
+ expect(resolve_releases.to_a)
+ .to match_array(all_releases)
+ .and be_sorted(:created_at, :desc)
end
end
@@ -67,7 +74,9 @@ RSpec.describe Resolvers::ReleasesResolver do
let(:args) { { sort: :created_asc } }
it 'returns the releases ordered by created_at in ascending order' do
- expect(resolve_releases).to eq([release_v2, release_v3, release_v1])
+ expect(resolve_releases.to_a)
+ .to match_array(all_releases)
+ .and be_sorted(:created_at, :asc)
end
end
end
diff --git a/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb b/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb
index 16e69f662c0..ebe286769cf 100644
--- a/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb
+++ b/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb
@@ -16,16 +16,18 @@ RSpec.describe Resolvers::Snippets::BlobsResolver do
context 'when user is not authorized' do
let(:other_user) { create(:user) }
- it 'raises an error' do
- expect do
- resolve_blobs(snippet, user: other_user)
- end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ it 'redacts the field' do
+ expect(resolve_blobs(snippet, user: other_user)).to be_nil
end
end
context 'when using no filter' do
it 'returns all snippet blobs' do
- expect(resolve_blobs(snippet).map(&:path)).to contain_exactly(*snippet.list_files)
+ result = resolve_blobs(snippet, args: {})
+
+ expect(result).to match_array(snippet.list_files.map do |file|
+ have_attributes(path: file)
+ end)
end
end
@@ -34,7 +36,13 @@ RSpec.describe Resolvers::Snippets::BlobsResolver do
it 'returns an array of files' do
path = 'CHANGELOG'
- expect(resolve_blobs(snippet, args: { paths: path }).first.path).to eq(path)
+ expect(resolve_blobs(snippet, paths: [path])).to contain_exactly(have_attributes(path: path))
+ end
+ end
+
+ context 'the argument does not match anything' do
+ it 'returns an empty result' do
+ expect(resolve_blobs(snippet, paths: ['does not exist'])).to be_empty
end
end
@@ -42,13 +50,15 @@ RSpec.describe Resolvers::Snippets::BlobsResolver do
it 'returns an array of files' do
paths = ['CHANGELOG', 'README.md']
- expect(resolve_blobs(snippet, args: { paths: paths }).map(&:path)).to contain_exactly(*paths)
+ expect(resolve_blobs(snippet, paths: paths)).to match_array(paths.map do |file|
+ have_attributes(path: file)
+ end)
end
end
end
end
- def resolve_blobs(snippet, user: current_user, args: {})
+ def resolve_blobs(snippet, user: current_user, paths: [], args: { paths: paths })
resolve(described_class, args: args, ctx: { current_user: user }, obj: snippet)
end
end
diff --git a/spec/graphql/resolvers/snippets_resolver_spec.rb b/spec/graphql/resolvers/snippets_resolver_spec.rb
index a58d9c5ac3a..11cb1c0ec4b 100644
--- a/spec/graphql/resolvers/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/snippets_resolver_spec.rb
@@ -84,19 +84,18 @@ RSpec.describe Resolvers::SnippetsResolver do
end
it 'returns the snippets by single gid' do
- snippets = resolve_snippets(args: { ids: personal_snippet.to_global_id })
+ snippets = resolve_snippets(args: { ids: [global_id_of(personal_snippet)] })
expect(snippets).to contain_exactly(personal_snippet)
end
it 'returns the snippets by array of gid' do
- args = {
- ids: [personal_snippet.to_global_id, project_snippet.to_global_id]
- }
+ snippets = [personal_snippet, project_snippet]
+ args = { ids: snippets.map { |s| global_id_of(s) } }
- snippets = resolve_snippets(args: args)
+ found = resolve_snippets(args: args)
- expect(snippets).to contain_exactly(personal_snippet, project_snippet)
+ expect(found).to match_array(snippets)
end
it 'returns an error if the id cannot be coerced' do
diff --git a/spec/graphql/resolvers/todo_resolver_spec.rb b/spec/graphql/resolvers/todo_resolver_spec.rb
index c764f389c16..ac14852b365 100644
--- a/spec/graphql/resolvers/todo_resolver_spec.rb
+++ b/spec/graphql/resolvers/todo_resolver_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Resolvers::TodoResolver do
it 'calls TodosFinder' do
expect_next_instance_of(TodosFinder) do |finder|
- expect(finder).to receive(:execute)
+ expect(finder).to receive(:execute).and_call_original
end
resolve_todos
@@ -48,7 +48,7 @@ RSpec.describe Resolvers::TodoResolver do
end
it 'returns the todos for single filter' do
- todos = resolve_todos(type: 'MergeRequest')
+ todos = resolve_todos(type: ['MergeRequest'])
expect(todos).to contain_exactly(merge_request_todo_pending)
end
diff --git a/spec/graphql/resolvers/user_discussions_count_resolver_spec.rb b/spec/graphql/resolvers/user_discussions_count_resolver_spec.rb
new file mode 100644
index 00000000000..cc855bbcb53
--- /dev/null
+++ b/spec/graphql/resolvers/user_discussions_count_resolver_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::UserDiscussionsCountResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:private_project) { create(:project, :private) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:private_issue) { create(:issue, project: private_project) }
+ let_it_be(:public_discussions) { create_list(:discussion_note_on_issue, 2, noteable: issue, project: project) }
+ let_it_be(:system_discussion) { create(:discussion_note_on_issue, system: true, noteable: issue, project: project) }
+ let_it_be(:private_discussion) { create_list(:discussion_note_on_issue, 3, noteable: private_issue, project: private_project) }
+
+ specify do
+ expect(described_class).to have_nullable_graphql_type(GraphQL::INT_TYPE)
+ end
+
+ context 'when counting discussions from a public issue' do
+ subject { batch_sync { resolve_user_discussions_count(issue) } }
+
+ it 'returns the number of discussions for the issue' do
+ expect(subject).to eq(2)
+ end
+ end
+
+ context 'when a user has permission to view discussions' do
+ before do
+ private_project.add_developer(user)
+ end
+
+ subject { batch_sync { resolve_user_discussions_count(private_issue) } }
+
+ it 'returns the number of non-system discussions for the issue' do
+ expect(subject).to eq(3)
+ end
+ end
+
+ context 'when a user does not have permission to view discussions' do
+ subject { batch_sync { resolve_user_discussions_count(private_issue) } }
+
+ it 'returns no discussions' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+
+ def resolve_user_discussions_count(obj)
+ resolve(described_class, obj: obj, ctx: { current_user: user })
+ end
+end
diff --git a/spec/graphql/resolvers/user_notes_count_resolver_spec.rb b/spec/graphql/resolvers/user_notes_count_resolver_spec.rb
new file mode 100644
index 00000000000..3cb0810c698
--- /dev/null
+++ b/spec/graphql/resolvers/user_notes_count_resolver_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::UserNotesCountResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository, :public) }
+ let_it_be(:private_project) { create(:project, :repository, :private) }
+
+ specify do
+ expect(described_class).to have_nullable_graphql_type(GraphQL::INT_TYPE)
+ end
+
+ context 'when counting notes from an issue' do
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:private_issue) { create(:issue, project: private_project) }
+ let_it_be(:public_notes) { create_list(:note, 2, noteable: issue, project: project) }
+ let_it_be(:system_note) { create(:note, system: true, noteable: issue, project: project) }
+ let_it_be(:private_notes) { create_list(:note, 3, noteable: private_issue, project: private_project) }
+
+ context 'when counting notes from a public issue' do
+ subject { batch_sync { resolve_user_notes_count(issue) } }
+
+ it 'returns the number of non-system notes for the issue' do
+ expect(subject).to eq(2)
+ end
+ end
+
+ context 'when a user has permission to view notes' do
+ before do
+ private_project.add_developer(user)
+ end
+
+ subject { batch_sync { resolve_user_notes_count(private_issue) } }
+
+ it 'returns the number of notes for the issue' do
+ expect(subject).to eq(3)
+ end
+ end
+
+ context 'when a user does not have permission to view notes' do
+ subject { batch_sync { resolve_user_notes_count(private_issue) } }
+
+ it 'returns no notes' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+
+ context 'when counting notes from a merge request' do
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
+ let_it_be(:private_merge_request) { create(:merge_request, source_project: private_project) }
+ let_it_be(:public_notes) { create_list(:note, 2, noteable: merge_request, project: project) }
+ let_it_be(:system_note) { create(:note, system: true, noteable: merge_request, project: project) }
+ let_it_be(:private_notes) { create_list(:note, 3, noteable: private_merge_request, project: private_project) }
+
+ context 'when counting notes from a public merge request' do
+ subject { batch_sync { resolve_user_notes_count(merge_request) } }
+
+ it 'returns the number of non-system notes for the merge request' do
+ expect(subject).to eq(2)
+ end
+ end
+
+ context 'when a user has permission to view notes' do
+ before do
+ private_project.add_developer(user)
+ end
+
+ subject { batch_sync { resolve_user_notes_count(private_merge_request) } }
+
+ it 'returns the number of notes for the merge request' do
+ expect(subject).to eq(3)
+ end
+ end
+
+ context 'when a user does not have permission to view notes' do
+ subject { batch_sync { resolve_user_notes_count(private_merge_request) } }
+
+ it 'returns no notes' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+ end
+
+ def resolve_user_notes_count(obj)
+ resolve(described_class, obj: obj, ctx: { current_user: user })
+ end
+end
diff --git a/spec/graphql/resolvers/users/snippets_resolver_spec.rb b/spec/graphql/resolvers/users/snippets_resolver_spec.rb
index 9ccbebc59e6..11a5b7517e0 100644
--- a/spec/graphql/resolvers/users/snippets_resolver_spec.rb
+++ b/spec/graphql/resolvers/users/snippets_resolver_spec.rb
@@ -51,24 +51,23 @@ RSpec.describe Resolvers::Users::SnippetsResolver do
end
it 'returns the snippets by single gid' do
- snippets = resolve_snippets(args: { ids: private_personal_snippet.to_global_id })
+ snippets = resolve_snippets(args: { ids: [global_id_of(private_personal_snippet)] })
expect(snippets).to contain_exactly(private_personal_snippet)
end
it 'returns the snippets by array of gid' do
- args = {
- ids: [private_personal_snippet.to_global_id, public_personal_snippet.to_global_id]
- }
+ snippets = [private_personal_snippet, public_personal_snippet]
+ args = { ids: snippets.map { |s| global_id_of(s) } }
- snippets = resolve_snippets(args: args)
+ found = resolve_snippets(args: args)
- expect(snippets).to contain_exactly(private_personal_snippet, public_personal_snippet)
+ expect(found).to match_array(snippets)
end
it 'returns an error if the gid is invalid' do
args = {
- ids: [private_personal_snippet.to_global_id, 'foo']
+ ids: [global_id_of(private_personal_snippet), 'foo']
}
expect 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
new file mode 100644
index 00000000000..2111a33b8b4
--- /dev/null
+++ b/spec/graphql/types/alert_management/domain_filter_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+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])
+ end
+end
diff --git a/spec/graphql/types/alert_management/prometheus_integration_type_spec.rb b/spec/graphql/types/alert_management/prometheus_integration_type_spec.rb
index 0e9994035d8..b10c2a2ab2a 100644
--- a/spec/graphql/types/alert_management/prometheus_integration_type_spec.rb
+++ b/spec/graphql/types/alert_management/prometheus_integration_type_spec.rb
@@ -11,11 +11,14 @@ RSpec.describe GitlabSchema.types['AlertManagementPrometheusIntegration'] do
describe 'resolvers' do
shared_examples_for 'has field with value' do |field_name|
it 'correctly renders the field' do
- expect(resolve_field(field_name, integration)).to eq(value)
+ result = resolve_field(field_name, integration, current_user: user)
+
+ expect(result).to eq(value)
end
end
let_it_be_with_reload(:integration) { create(:prometheus_service) }
+ let_it_be(:user) { create(:user, maintainer_projects: [integration.project]) }
it_behaves_like 'has field with value', 'name' do
let(:value) { integration.title }
diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb
index d61ea6aa6e9..54b59317b55 100644
--- a/spec/graphql/types/base_field_spec.rb
+++ b/spec/graphql/types/base_field_spec.rb
@@ -145,11 +145,11 @@ RSpec.describe Types::BaseField do
describe '#description' do
context 'feature flag given' do
- let(:field) { described_class.new(name: 'test', type: GraphQL::STRING_TYPE, feature_flag: flag, null: false, description: 'Test description') }
+ let(:field) { described_class.new(name: 'test', type: GraphQL::STRING_TYPE, feature_flag: flag, null: false, description: 'Test description.') }
let(:flag) { :test_flag }
it 'prepends the description' do
- expect(field.description). to eq 'Test description. Available only when feature flag `test_flag` is enabled'
+ expect(field.description). to eq 'Test description. Available only when feature flag `test_flag` is enabled.'
end
context 'falsey feature_flag values' do
@@ -164,7 +164,7 @@ RSpec.describe Types::BaseField do
with_them do
it 'returns the correct description' do
- expect(field.description).to eq('Test description')
+ expect(field.description).to eq('Test description.')
end
end
end
@@ -181,11 +181,11 @@ RSpec.describe Types::BaseField do
it 'interacts well with the `feature_flag` property' do
field = subject(
deprecated: { milestone: '1.10', reason: 'Deprecation reason' },
- description: 'Field description',
+ description: 'Field description.',
feature_flag: 'foo_flag'
)
- expectation = 'Field description. Available only when feature flag `foo_flag` is enabled. Deprecated in 1.10: Deprecation reason'
+ expectation = 'Field description. Available only when feature flag `foo_flag` is enabled. Deprecated in 1.10: Deprecation reason.'
expect(field.description).to eq(expectation)
end
diff --git a/spec/graphql/types/ci/analytics_type_spec.rb b/spec/graphql/types/ci/analytics_type_spec.rb
new file mode 100644
index 00000000000..c8462d40769
--- /dev/null
+++ b/spec/graphql/types/ci/analytics_type_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::AnalyticsType do
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ weekPipelinesTotals
+ weekPipelinesLabels
+ weekPipelinesSuccessful
+ monthPipelinesLabels
+ monthPipelinesTotals
+ monthPipelinesSuccessful
+ yearPipelinesLabels
+ yearPipelinesTotals
+ yearPipelinesSuccessful
+ pipelineTimesLabels
+ pipelineTimesValues
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/config/config_type_spec.rb b/spec/graphql/types/ci/config/config_type_spec.rb
new file mode 100644
index 00000000000..edd190a4365
--- /dev/null
+++ b/spec/graphql/types/ci/config/config_type_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::Config::ConfigType do
+ specify { expect(described_class.graphql_name).to eq('CiConfig') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ errors
+ mergedYaml
+ stages
+ status
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/config/group_type_spec.rb b/spec/graphql/types/ci/config/group_type_spec.rb
new file mode 100644
index 00000000000..7d808e85371
--- /dev/null
+++ b/spec/graphql/types/ci/config/group_type_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::Config::GroupType do
+ specify { expect(described_class.graphql_name).to eq('CiConfigGroup') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ name
+ jobs
+ size
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/config/job_type_spec.rb b/spec/graphql/types/ci/config/job_type_spec.rb
new file mode 100644
index 00000000000..600d665a84b
--- /dev/null
+++ b/spec/graphql/types/ci/config/job_type_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::Config::JobType do
+ specify { expect(described_class.graphql_name).to eq('CiConfigJob') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ name
+ group_name
+ stage
+ needs
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/config/need_type_spec.rb b/spec/graphql/types/ci/config/need_type_spec.rb
new file mode 100644
index 00000000000..3387049a81d
--- /dev/null
+++ b/spec/graphql/types/ci/config/need_type_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::Config::NeedType do
+ specify { expect(described_class.graphql_name).to eq('CiConfigNeed') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ name
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/config/stage_type_spec.rb b/spec/graphql/types/ci/config/stage_type_spec.rb
new file mode 100644
index 00000000000..aba97f8c7ed
--- /dev/null
+++ b/spec/graphql/types/ci/config/stage_type_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::Config::StageType do
+ specify { expect(described_class.graphql_name).to eq('CiConfigStage') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ name
+ groups
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/job_artifact_file_type_enum_spec.rb b/spec/graphql/types/ci/job_artifact_file_type_enum_spec.rb
new file mode 100644
index 00000000000..78a32595730
--- /dev/null
+++ b/spec/graphql/types/ci/job_artifact_file_type_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['JobArtifactFileType'] do
+ it 'exposes all job artifact file types' do
+ expect(described_class.values.keys).to contain_exactly(
+ *::Ci::JobArtifact::TYPE_AND_FORMAT_PAIRS.keys.map(&:to_s).map(&:upcase)
+ )
+ end
+end
diff --git a/spec/graphql/types/ci/job_artifact_type_spec.rb b/spec/graphql/types/ci/job_artifact_type_spec.rb
new file mode 100644
index 00000000000..d4dc5ef214d
--- /dev/null
+++ b/spec/graphql/types/ci/job_artifact_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CiJobArtifact'] do
+ it 'has the correct fields' do
+ expected_fields = [:download_path, :file_type]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/job_type_spec.rb b/spec/graphql/types/ci/job_type_spec.rb
index 3dcb81eefbf..441a719df8c 100644
--- a/spec/graphql/types/ci/job_type_spec.rb
+++ b/spec/graphql/types/ci/job_type_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe Types::Ci::JobType do
needs
detailedStatus
scheduledAt
+ artifacts
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/ci/pipeline_type_spec.rb b/spec/graphql/types/ci/pipeline_type_spec.rb
index f13f1c9afb2..d435e337ad7 100644
--- a/spec/graphql/types/ci/pipeline_type_spec.rb
+++ b/spec/graphql/types/ci/pipeline_type_spec.rb
@@ -6,4 +6,19 @@ RSpec.describe Types::Ci::PipelineType do
specify { expect(described_class.graphql_name).to eq('Pipeline') }
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Ci::Pipeline) }
+
+ it 'contains attributes related to a pipeline' do
+ expected_fields = %w[
+ id iid sha before_sha status detailed_status config_source duration
+ coverage created_at updated_at started_at finished_at committed_at
+ stages user retryable cancelable jobs source_job downstream
+ upstream path project active user_permissions
+ ]
+
+ if Gitlab.ee?
+ expected_fields << 'security_report_summary'
+ end
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
end
diff --git a/spec/graphql/types/commit_type_spec.rb b/spec/graphql/types/commit_type_spec.rb
index e9bc7f6bb94..b43693e5804 100644
--- a/spec/graphql/types/commit_type_spec.rb
+++ b/spec/graphql/types/commit_type_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe GitlabSchema.types['Commit'] do
it 'contains attributes related to commit' do
expect(described_class).to have_graphql_fields(
- :id, :sha, :title, :description, :description_html, :message, :title_html, :authored_date,
+ :id, :sha, :short_id, :title, :description, :description_html, :message, :title_html, :authored_date,
:author_name, :author_gravatar, :author, :web_url, :web_path,
:pipelines, :signature_html
)
diff --git a/spec/graphql/types/container_repository_details_type_spec.rb b/spec/graphql/types/container_repository_details_type_spec.rb
index b5ff460fcf7..45f6449d8c8 100644
--- a/spec/graphql/types/container_repository_details_type_spec.rb
+++ b/spec/graphql/types/container_repository_details_type_spec.rb
@@ -3,7 +3,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]
+ fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete expiration_policy_cleanup_status tags project]
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 3d3445ba5c3..87e1c11ce19 100644
--- a/spec/graphql/types/container_repository_type_spec.rb
+++ b/spec/graphql/types/container_repository_type_spec.rb
@@ -3,7 +3,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]
+ fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete expiration_policy_cleanup_status project]
it { expect(described_class.graphql_name).to eq('ContainerRepository') }
diff --git a/spec/graphql/types/countable_connection_type_spec.rb b/spec/graphql/types/countable_connection_type_spec.rb
index 3b3c02baa5d..648dbacff42 100644
--- a/spec/graphql/types/countable_connection_type_spec.rb
+++ b/spec/graphql/types/countable_connection_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GitlabSchema.types['MergeRequestConnection'] do
+RSpec.describe GitlabSchema.types['PipelineConnection'] do
it 'has the expected fields' do
expected_fields = %i[count page_info edges nodes]
diff --git a/spec/graphql/types/group_member_relation_enum_spec.rb b/spec/graphql/types/group_member_relation_enum_spec.rb
new file mode 100644
index 00000000000..315809ef75e
--- /dev/null
+++ b/spec/graphql/types/group_member_relation_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::GroupMemberRelationEnum do
+ specify { expect(described_class.graphql_name).to eq('GroupMemberRelation') }
+
+ it 'exposes all the existing group member relation type values' do
+ expect(described_class.values.keys).to contain_exactly('DIRECT', 'INHERITED', 'DESCENDANTS')
+ end
+end
diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb
index 7d14ef87551..de19e8b602a 100644
--- a/spec/graphql/types/group_type_spec.rb
+++ b/spec/graphql/types/group_type_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe GitlabSchema.types['Group'] do
subgroup_creation_level require_two_factor_authentication
two_factor_grace_period auto_devops_enabled emails_disabled
mentions_disabled parent boards milestones group_members
- merge_requests
+ merge_requests container_repositories container_repositories_count
]
expect(described_class).to include_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/merge_request_connection_type_spec.rb b/spec/graphql/types/merge_request_connection_type_spec.rb
new file mode 100644
index 00000000000..f4ab6c79721
--- /dev/null
+++ b/spec/graphql/types/merge_request_connection_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['MergeRequestConnection'] do
+ it 'has the expected fields' do
+ expected_fields = %i[count totalTimeToMerge page_info edges nodes]
+
+ 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 8800250b103..51e7b4029d5 100644
--- a/spec/graphql/types/merge_request_type_spec.rb
+++ b/spec/graphql/types/merge_request_type_spec.rb
@@ -27,18 +27,27 @@ RSpec.describe GitlabSchema.types['MergeRequest'] do
upvotes downvotes head_pipeline pipelines task_completion_status
milestone assignees participants subscribed labels discussion_locked time_estimate
total_time_spent reference author merged_at commit_count current_user_todos
- conflicts auto_merge_enabled approved_by
+ conflicts auto_merge_enabled approved_by source_branch_protected
+ default_merge_commit_message_with_description squash_on_merge available_auto_merge_strategies
+ has_ci mergeable commits_without_merge_commits security_auto_fix
]
if Gitlab.ee?
expected_fields << 'approved'
expected_fields << 'approvals_left'
expected_fields << 'approvals_required'
+ expected_fields << 'merge_trains_count'
end
expect(described_class).to have_graphql_fields(*expected_fields)
end
+ describe '#pipelines' do
+ subject { described_class.fields['pipelines'] }
+
+ it { is_expected.to have_attributes(max_page_size: 500) }
+ end
+
describe '#diff_stats_summary' do
subject { GitlabSchema.execute(query, context: { current_user: current_user }).as_json }
diff --git a/spec/graphql/types/permission_types/base_permission_type_spec.rb b/spec/graphql/types/permission_types/base_permission_type_spec.rb
index 2ce02f1520c..68632a509ee 100644
--- a/spec/graphql/types/permission_types/base_permission_type_spec.rb
+++ b/spec/graphql/types/permission_types/base_permission_type_spec.rb
@@ -11,9 +11,13 @@ RSpec.describe Types::PermissionTypes::BasePermissionType do
Class.new(described_class) do
graphql_name 'TestClass'
- permission_field :do_stuff, resolve: -> (_, _, _) { true }
+ permission_field :do_stuff
ability_field(:read_issue)
abilities :admin_issue
+
+ define_method :do_stuff do
+ true
+ end
end
end
diff --git a/spec/graphql/types/project_member_relation_enum_spec.rb b/spec/graphql/types/project_member_relation_enum_spec.rb
new file mode 100644
index 00000000000..3c947bf8406
--- /dev/null
+++ b/spec/graphql/types/project_member_relation_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::ProjectMemberRelationEnum do
+ specify { expect(described_class.graphql_name).to eq('ProjectMemberRelation') }
+
+ it 'exposes all the existing project member relation type values' do
+ expect(described_class.values.keys).to contain_exactly('DIRECT', 'INHERITED', 'DESCENDANTS', 'INVITED_GROUPS')
+ end
+end
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index be579e92fb3..b3028e034cc 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe GitlabSchema.types['Project'] do
+ include GraphqlHelpers
+
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Project) }
specify { expect(described_class.graphql_name).to eq('Project') }
@@ -28,7 +30,8 @@ RSpec.describe GitlabSchema.types['Project'] do
alert_management_alerts alert_management_alert alert_management_alert_status_counts
container_expiration_policy service_desk_enabled service_desk_address
issue_status_counts terraform_states alert_management_integrations
-
+ container_repositories container_repositories_count
+ pipeline_analytics total_pipeline_duration squash_read_only
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -76,6 +79,7 @@ RSpec.describe GitlabSchema.types['Project'] do
:merged_before,
:author_username,
:assignee_username,
+ :reviewer_username,
:milestone_title,
:sort
)
@@ -163,4 +167,32 @@ RSpec.describe GitlabSchema.types['Project'] do
end
it_behaves_like 'a GraphQL type with labels'
+
+ describe 'jira_imports' do
+ subject { resolve_field(:jira_imports, project) }
+
+ let_it_be(:project) { create(:project, :public) }
+
+ context 'when project has Jira imports' do
+ let_it_be(:jira_import1) { create(:jira_import_state, :finished, project: project, jira_project_key: 'AA', created_at: 2.days.ago) }
+ let_it_be(:jira_import2) { create(:jira_import_state, :finished, project: project, jira_project_key: 'BB', created_at: 5.days.ago) }
+
+ it 'retrieves the imports' do
+ expect(subject).to contain_exactly(jira_import1, jira_import2)
+ end
+ end
+
+ context 'when project does not have Jira imports' do
+ it 'returns an empty result' do
+ expect(subject).to be_empty
+ end
+ end
+ end
+
+ describe 'pipeline_analytics field' do
+ subject { described_class.fields['pipelineAnalytics'] }
+
+ it { is_expected.to have_graphql_type(Types::Ci::AnalyticsType) }
+ it { is_expected.to have_graphql_resolver(Resolvers::ProjectPipelineStatisticsResolver) }
+ end
end
diff --git a/spec/graphql/types/terraform/state_version_type_spec.rb b/spec/graphql/types/terraform/state_version_type_spec.rb
index 1c1e95039dc..18f869e4f1f 100644
--- a/spec/graphql/types/terraform/state_version_type_spec.rb
+++ b/spec/graphql/types/terraform/state_version_type_spec.rb
@@ -7,13 +7,15 @@ RSpec.describe GitlabSchema.types['TerraformStateVersion'] do
it { expect(described_class).to require_graphql_authorizations(:read_terraform_state) }
describe 'fields' do
- let(:fields) { %i[id created_by_user job created_at updated_at] }
+ let(:fields) { %i[id created_by_user job download_path serial created_at updated_at] }
it { expect(described_class).to have_graphql_fields(fields) }
it { expect(described_class.fields['id'].type).to be_non_null }
it { expect(described_class.fields['createdByUser'].type).not_to be_non_null }
it { expect(described_class.fields['job'].type).not_to be_non_null }
+ it { expect(described_class.fields['downloadPath'].type).not_to be_non_null }
+ it { expect(described_class.fields['serial'].type).not_to be_non_null }
it { expect(described_class.fields['createdAt'].type).to be_non_null }
it { expect(described_class.fields['updatedAt'].type).to be_non_null }
end
diff --git a/spec/graphql/types/user_type_spec.rb b/spec/graphql/types/user_type_spec.rb
index c8953d9ccb7..0eff33bb25b 100644
--- a/spec/graphql/types/user_type_spec.rb
+++ b/spec/graphql/types/user_type_spec.rb
@@ -15,14 +15,17 @@ RSpec.describe GitlabSchema.types['User'] do
name
username
email
+ publicEmail
avatarUrl
webUrl
webPath
todos
state
status
+ location
authoredMergeRequests
assignedMergeRequests
+ reviewRequestedMergeRequests
groupMemberships
groupCount
projectMemberships