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:
Diffstat (limited to 'spec/requests/api/graphql')
-rw-r--r--spec/requests/api/graphql/abuse_report_spec.rb131
-rw-r--r--spec/requests/api/graphql/ci/catalog/resource_spec.rb341
-rw-r--r--spec/requests/api/graphql/ci/catalog/resources_spec.rb359
-rw-r--r--spec/requests/api/graphql/ci/manual_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/runners_spec.rb87
-rw-r--r--spec/requests/api/graphql/container_repository/container_repository_details_spec.rb120
-rw-r--r--spec/requests/api/graphql/gitlab_schema_spec.rb6
-rw-r--r--spec/requests/api/graphql/group/container_repositories_spec.rb4
-rw-r--r--spec/requests/api/graphql/group/data_transfer_spec.rb42
-rw-r--r--spec/requests/api/graphql/group/milestones_spec.rb8
-rw-r--r--spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb12
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb32
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb37
-rw-r--r--spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb34
-rw-r--r--spec/requests/api/graphql/mutations/ci/catalog/resources/create_spec.rb40
-rw-r--r--spec/requests/api/graphql/mutations/ci/catalog/unpublish_spec.rb52
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_retry_spec.rb16
-rw-r--r--spec/requests/api/graphql/mutations/clusters/agent_tokens/agent_tokens/create_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/container_registry/protection/rule/create_spec.rb180
-rw-r--r--spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/design_management/delete_spec.rb10
-rw-r--r--spec/requests/api/graphql/mutations/design_management/upload_spec.rb9
-rw-r--r--spec/requests/api/graphql/mutations/issues/link_alerts_spec.rb28
-rw-r--r--spec/requests/api/graphql/mutations/issues/move_spec.rb18
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb20
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb26
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb22
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_locked_spec.rb20
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_severity_spec.rb20
-rw-r--r--spec/requests/api/graphql/mutations/issues/unlink_alerts_spec.rb28
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb12
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb28
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb20
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_labels_spec.rb28
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb20
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb24
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb28
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_time_estimate_spec.rb5
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/update_spec.rb17
-rw-r--r--spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb20
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/note_spec.rb43
-rw-r--r--spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb12
-rw-r--r--spec/requests/api/graphql/mutations/organizations/create_spec.rb64
-rw-r--r--spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb18
-rw-r--r--spec/requests/api/graphql/mutations/packages/protection/rule/create_spec.rb232
-rw-r--r--spec/requests/api/graphql/mutations/packages/protection/rule/delete_spec.rb88
-rw-r--r--spec/requests/api/graphql/mutations/release_asset_links/update_spec.rb14
-rw-r--r--spec/requests/api/graphql/mutations/snippets/create_spec.rb10
-rw-r--r--spec/requests/api/graphql/mutations/snippets/destroy_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/snippets/update_spec.rb38
-rw-r--r--spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb14
-rw-r--r--spec/requests/api/graphql/mutations/todos/mark_done_spec.rb20
-rw-r--r--spec/requests/api/graphql/mutations/todos/restore_many_spec.rb20
-rw-r--r--spec/requests/api/graphql/mutations/todos/restore_spec.rb20
-rw-r--r--spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb9
-rw-r--r--spec/requests/api/graphql/organizations/organization_query_spec.rb7
-rw-r--r--spec/requests/api/graphql/project/base_service_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/container_repositories_spec.rb14
-rw-r--r--spec/requests/api/graphql/project/data_transfer_spec.rb42
-rw-r--r--spec/requests/api/graphql/project/environments_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue_spec.rb4
-rw-r--r--spec/requests/api/graphql/project/jira_import_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/jira_projects_spec.rb8
-rw-r--r--spec/requests/api/graphql/project/merge_request_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/merge_requests_spec.rb5
-rw-r--r--spec/requests/api/graphql/project/release_spec.rb24
-rw-r--r--spec/requests/api/graphql/project/terraform/state_spec.rb4
-rw-r--r--spec/requests/api/graphql/project/terraform/states_spec.rb4
-rw-r--r--spec/requests/api/graphql/project/work_items_spec.rb17
-rw-r--r--spec/requests/api/graphql/projects/projects_spec.rb77
-rw-r--r--spec/requests/api/graphql/user_spec.rb32
-rw-r--r--spec/requests/api/graphql/work_item_spec.rb75
77 files changed, 2205 insertions, 646 deletions
diff --git a/spec/requests/api/graphql/abuse_report_spec.rb b/spec/requests/api/graphql/abuse_report_spec.rb
index 7d0b8b35763..f74b1fb4061 100644
--- a/spec/requests/api/graphql/abuse_report_spec.rb
+++ b/spec/requests/api/graphql/abuse_report_spec.rb
@@ -2,49 +2,122 @@
require 'spec_helper'
-RSpec.describe 'abuse_report', feature_category: :insider_threat do
+RSpec.describe 'Querying an Abuse Report', feature_category: :insider_threat do
include GraphqlHelpers
let_it_be(:current_user) { create(:admin) }
- let_it_be(:label) { create(:abuse_report_label, title: 'Uno') }
- let_it_be(:report) { create(:abuse_report, labels: [label]) }
-
- let(:report_gid) { Gitlab::GlobalId.build(report, id: report.id).to_s }
-
- let(:fields) do
- <<~GRAPHQL
- labels {
- nodes {
- id
- title
- description
- color
- textColor
- }
- }
- GRAPHQL
- end
+ let_it_be(:abuse_report) { create(:abuse_report) }
- let(:arguments) { { id: report_gid } }
- let(:query) { graphql_query_for('abuseReport', arguments, fields) }
+ let(:global_id) { abuse_report.to_gid.to_s }
+ let(:abuse_report_fields) { all_graphql_fields_for('AbuseReport', max_depth: 2) }
+ let(:abuse_report_data) { graphql_data['abuseReport'] }
+
+ let(:query) do
+ graphql_query_for('abuseReport', { 'id' => global_id }, abuse_report_fields)
+ end
before do
post_graphql(query, current_user: current_user)
end
- it_behaves_like 'a working graphql query that returns data'
+ context 'when the user is an admin' do
+ it_behaves_like 'a working graphql query that returns data'
- it 'returns abuse report with labels' do
- expect(graphql_data_at('abuseReport', 'labels', 'nodes', 0)).to match(a_graphql_entity_for(label))
+ it 'returns all fields' do
+ expect(abuse_report_data).to include(
+ 'id' => global_id,
+ 'userPermissions' => {
+ 'readAbuseReport' => true,
+ 'createNote' => true
+ }
+ )
+ end
end
- context 'when current user is not an admin' do
- let_it_be(:current_user) { create(:user) }
+ context 'when the user is not an admin' do
+ let(:current_user) { create(:user) }
+
+ it 'returns nil' do
+ expect(abuse_report_data).to be_nil
+ end
+ end
- it_behaves_like 'a working graphql query'
+ describe 'labels' do
+ let_it_be(:abuse_report_label) { create(:abuse_report_label, title: 'Label') }
+ let_it_be(:abuse_report) { create(:abuse_report, labels: [abuse_report_label]) }
+
+ let(:labels_response) do
+ graphql_data_at(:abuse_report, :labels, :nodes)
+ end
+
+ let(:abuse_report_fields) do
+ <<~GRAPHQL
+ labels {
+ nodes {
+ id
+ title
+ description
+ color
+ textColor
+ }
+ }
+ GRAPHQL
+ end
+
+ it 'returns labels' do
+ expect(labels_response).to contain_exactly(
+ a_graphql_entity_for(abuse_report_label)
+ )
+ end
+ end
+
+ describe 'notes' do
+ let_it_be(:note) { create(:note, noteable: abuse_report, author: current_user) }
+
+ let(:notes_response) do
+ graphql_data_at(:abuse_report, :notes, :nodes)
+ end
+
+ let(:abuse_report_fields) do
+ <<~GRAPHQL
+ notes {
+ nodes {
+ #{all_graphql_fields_for('Note', max_depth: 2)}
+ }
+ }
+ GRAPHQL
+ end
+
+ it 'returns notes' do
+ expect(notes_response).to contain_exactly(
+ a_graphql_entity_for(note)
+ )
+ end
+ end
+
+ describe 'discussions' do
+ let_it_be(:discussion) do
+ create(:discussion_note_on_abuse_report, noteable: abuse_report, author: current_user).to_discussion
+ end
+
+ let(:discussions_response) do
+ graphql_data_at(:abuse_report, :discussions, :nodes)
+ end
+
+ let(:abuse_report_fields) do
+ <<~GRAPHQL
+ discussions {
+ nodes {
+ #{all_graphql_fields_for('Discussion', max_depth: 2)}
+ }
+ }
+ GRAPHQL
+ end
- it 'does not contain any data' do
- expect(graphql_data_at('abuseReportLabel')).to be_nil
+ it 'returns discussions' do
+ expect(discussions_response).to contain_exactly(
+ a_graphql_entity_for(discussion)
+ )
end
end
end
diff --git a/spec/requests/api/graphql/ci/catalog/resource_spec.rb b/spec/requests/api/graphql/ci/catalog/resource_spec.rb
new file mode 100644
index 00000000000..fce773f320b
--- /dev/null
+++ b/spec/requests/api/graphql/ci/catalog/resource_spec.rb
@@ -0,0 +1,341 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_composition do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:namespace) { create(:group) }
+
+ let_it_be(:project) do
+ create(
+ :project, :with_avatar, :custom_repo,
+ name: 'Component Repository',
+ description: 'A simple component',
+ namespace: namespace,
+ star_count: 1,
+ files: { 'README.md' => '[link](README.md)' }
+ )
+ end
+
+ let_it_be(:resource) { create(:ci_catalog_resource, project: project) }
+
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResource(id: "#{resource.to_global_id}") {
+ #{all_graphql_fields_for('CiCatalogResource', max_depth: 1)}
+ }
+ }
+ GQL
+ end
+
+ subject(:post_query) { post_graphql(query, current_user: user) }
+
+ context 'when the current user has permission to read the namespace catalog' do
+ it 'returns the resource with the expected data' do
+ namespace.add_developer(user)
+
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(
+ a_graphql_entity_for(
+ resource, :name, :description,
+ icon: project.avatar_path,
+ webPath: "/#{project.full_path}",
+ starCount: project.star_count,
+ forksCount: project.forks_count,
+ readmeHtml: a_string_including(
+ "#{project.full_path}/-/blob/#{project.default_branch}/README.md"
+ )
+ )
+ )
+ end
+ end
+
+ context 'when the current user does not have permission to read the namespace catalog' do
+ it 'returns nil' do
+ namespace.add_guest(user)
+
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to be_nil
+ end
+ end
+
+ describe 'versions' do
+ before_all do
+ namespace.add_developer(user)
+ end
+
+ before do
+ stub_licensed_features(ci_namespace_catalog: true)
+ end
+
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResource(id: "#{resource.to_global_id}") {
+ id
+ versions {
+ nodes {
+ id
+ tagName
+ releasedAt
+ author {
+ id
+ name
+ webUrl
+ }
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ context 'when the resource has versions' do
+ let_it_be(:author) { create(:user, name: 'author') }
+
+ let_it_be(:version1) do
+ create(:release, project: project, released_at: '2023-01-01T00:00:00Z', author: author)
+ end
+
+ let_it_be(:version2) do
+ create(:release, project: project, released_at: '2023-02-01T00:00:00Z', author: author)
+ end
+
+ it 'returns the resource with the versions data' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(
+ a_graphql_entity_for(resource)
+ )
+
+ expect(graphql_data_at(:ciCatalogResource, :versions, :nodes)).to contain_exactly(
+ a_graphql_entity_for(
+ version1,
+ tagName: version1.tag,
+ releasedAt: version1.released_at,
+ author: a_graphql_entity_for(author, :name)
+ ),
+ a_graphql_entity_for(
+ version2,
+ tagName: version2.tag,
+ releasedAt: version2.released_at,
+ author: a_graphql_entity_for(author, :name)
+ )
+ )
+ end
+ end
+
+ context 'when the resource does not have a version' do
+ it 'returns versions as an empty array' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(
+ a_graphql_entity_for(resource, versions: { 'nodes' => [] })
+ )
+ end
+ end
+ end
+
+ describe 'latestVersion' do
+ before_all do
+ namespace.add_developer(user)
+ end
+
+ before do
+ stub_licensed_features(ci_namespace_catalog: true)
+ end
+
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResource(id: "#{resource.to_global_id}") {
+ id
+ latestVersion {
+ id
+ tagName
+ releasedAt
+ author {
+ id
+ name
+ webUrl
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ context 'when the resource has versions' do
+ let_it_be(:author) { create(:user, name: 'author') }
+
+ let_it_be(:latest_version) do
+ create(:release, project: project, released_at: '2023-02-01T00:00:00Z', author: author)
+ end
+
+ before_all do
+ # Previous version of the project
+ create(:release, project: project, released_at: '2023-01-01T00:00:00Z', author: author)
+ end
+
+ it 'returns the resource with the latest version data' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(
+ a_graphql_entity_for(
+ resource,
+ latestVersion: a_graphql_entity_for(
+ latest_version,
+ tagName: latest_version.tag,
+ releasedAt: latest_version.released_at,
+ author: a_graphql_entity_for(author, :name)
+ )
+ )
+ )
+ end
+ end
+
+ context 'when the resource does not have a version' do
+ it 'returns nil' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(
+ a_graphql_entity_for(resource, latestVersion: nil)
+ )
+ end
+ end
+ end
+
+ describe 'rootNamespace' do
+ before_all do
+ namespace.add_developer(user)
+ end
+
+ before do
+ stub_licensed_features(ci_namespace_catalog: true)
+ end
+
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResource(id: "#{resource.to_global_id}") {
+ id
+ rootNamespace {
+ id
+ name
+ path
+ }
+ }
+ }
+ GQL
+ end
+
+ it 'returns the correct root namespace data' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(
+ a_graphql_entity_for(
+ resource,
+ rootNamespace: a_graphql_entity_for(namespace, :name, :path)
+ )
+ )
+ end
+ end
+
+ describe 'openIssuesCount' do
+ before do
+ stub_licensed_features(ci_namespace_catalog: true)
+ end
+
+ context 'when open_issue_count is requested' do
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResource(id: "#{resource.to_global_id}") {
+ openIssuesCount
+ }
+ }
+ GQL
+ end
+
+ it 'returns the correct count' do
+ create(:issue, :opened, project: project)
+ create(:issue, :opened, project: project)
+
+ namespace.add_developer(user)
+
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(
+ a_graphql_entity_for(
+ open_issues_count: 2
+ )
+ )
+ end
+
+ context 'when open_issue_count is zero' do
+ it 'returns zero' do
+ namespace.add_developer(user)
+
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(
+ a_graphql_entity_for(
+ open_issues_count: 0
+ )
+ )
+ end
+ end
+ end
+ end
+
+ describe 'openMergeRequestsCount' do
+ before do
+ stub_licensed_features(ci_namespace_catalog: true)
+ end
+
+ context 'when merge_requests_count is requested' do
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResource(id: "#{resource.to_global_id}") {
+ openMergeRequestsCount
+ }
+ }
+ GQL
+ end
+
+ it 'returns the correct count' do
+ create(:merge_request, :opened, source_project: project)
+
+ namespace.add_developer(user)
+
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(
+ a_graphql_entity_for(
+ open_merge_requests_count: 1
+ )
+ )
+ end
+
+ context 'when open merge_requests_count is zero' do
+ it 'returns zero' do
+ namespace.add_developer(user)
+
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(
+ a_graphql_entity_for(
+ open_merge_requests_count: 0
+ )
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/ci/catalog/resources_spec.rb b/spec/requests/api/graphql/ci/catalog/resources_spec.rb
new file mode 100644
index 00000000000..7c955a1202c
--- /dev/null
+++ b/spec/requests/api/graphql/ci/catalog/resources_spec.rb
@@ -0,0 +1,359 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Query.ciCatalogResources', feature_category: :pipeline_composition do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:namespace) { create(:group) }
+ let_it_be(:project2) { create(:project, namespace: namespace) }
+
+ let_it_be(:project1) do
+ create(
+ :project, :with_avatar, :custom_repo,
+ name: 'Component Repository',
+ description: 'A simple component',
+ namespace: namespace,
+ star_count: 1,
+ files: { 'README.md' => '**Test**' }
+ )
+ end
+
+ let_it_be(:public_project) do
+ create(
+ :project, :with_avatar, :custom_repo, :public,
+ name: 'Public Component',
+ description: 'A public component',
+ files: { 'README.md' => '**Test**' }
+ )
+ end
+
+ let_it_be(:resource1) { create(:ci_catalog_resource, project: project1, latest_released_at: '2023-01-01T00:00:00Z') }
+ let_it_be(:public_resource) { create(:ci_catalog_resource, project: public_project) }
+
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResources {
+ nodes {
+ id
+ name
+ description
+ icon
+ webPath
+ latestReleasedAt
+ starCount
+ forksCount
+ readmeHtml
+ }
+ }
+ }
+ GQL
+ end
+
+ subject(:post_query) { post_graphql(query, current_user: user) }
+
+ shared_examples 'avoids N+1 queries' do
+ it do
+ ctx = { current_user: user }
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ run_with_clean_state(query, context: ctx)
+ end
+
+ create(:ci_catalog_resource, project: project2)
+
+ expect do
+ run_with_clean_state(query, context: ctx)
+ end.not_to exceed_query_limit(control_count)
+ end
+ end
+
+ it_behaves_like 'avoids N+1 queries'
+
+ it 'returns the resources with the expected data' do
+ namespace.add_developer(user)
+
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResources, :nodes)).to contain_exactly(
+ a_graphql_entity_for(
+ resource1, :name, :description,
+ icon: project1.avatar_path,
+ webPath: "/#{project1.full_path}",
+ starCount: project1.star_count,
+ forksCount: project1.forks_count,
+ readmeHtml: a_string_including('Test</strong>'),
+ latestReleasedAt: resource1.latest_released_at
+ ),
+ a_graphql_entity_for(public_resource)
+ )
+ end
+
+ describe 'versions' do
+ before_all do
+ namespace.add_developer(user)
+ end
+
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResources {
+ nodes {
+ id
+ versions {
+ nodes {
+ id
+ tagName
+ releasedAt
+ author {
+ id
+ name
+ webUrl
+ }
+ }
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ it 'limits the request to 1 resource at a time' do
+ create(:ci_catalog_resource, project: project2)
+
+ post_query
+
+ expect_graphql_errors_to_include \
+ [/"versions" field can be requested only for 1 CiCatalogResource\(s\) at a time./]
+ end
+ end
+
+ describe 'latestVersion' do
+ let_it_be(:author1) { create(:user, name: 'author1') }
+ let_it_be(:author2) { create(:user, name: 'author2') }
+
+ let_it_be(:latest_version1) do
+ create(:release, project: project1, released_at: '2023-02-01T00:00:00Z', author: author1)
+ end
+
+ let_it_be(:latest_version2) do
+ create(:release, project: public_project, released_at: '2023-02-01T00:00:00Z', author: author2)
+ end
+
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResources {
+ nodes {
+ id
+ latestVersion {
+ id
+ tagName
+ releasedAt
+ author {
+ id
+ name
+ webUrl
+ }
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ before_all do
+ namespace.add_developer(user)
+
+ # Previous versions of the projects
+ create(:release, project: project1, released_at: '2023-01-01T00:00:00Z', author: author1)
+ create(:release, project: public_project, released_at: '2023-01-01T00:00:00Z', author: author2)
+ end
+
+ it 'returns all resources with the latest version data' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResources, :nodes)).to contain_exactly(
+ a_graphql_entity_for(
+ resource1,
+ latestVersion: a_graphql_entity_for(
+ latest_version1,
+ tagName: latest_version1.tag,
+ releasedAt: latest_version1.released_at,
+ author: a_graphql_entity_for(author1, :name)
+ )
+ ),
+ a_graphql_entity_for(
+ public_resource,
+ latestVersion: a_graphql_entity_for(
+ latest_version2,
+ tagName: latest_version2.tag,
+ releasedAt: latest_version2.released_at,
+ author: a_graphql_entity_for(author2, :name)
+ )
+ )
+ )
+ end
+
+ # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/430350
+ # it_behaves_like 'avoids N+1 queries'
+ end
+
+ describe 'rootNamespace' do
+ before_all do
+ namespace.add_developer(user)
+ end
+
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResources {
+ nodes {
+ id
+ rootNamespace {
+ id
+ name
+ path
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ it 'returns the correct root namespace data' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResources, :nodes)).to contain_exactly(
+ a_graphql_entity_for(
+ resource1,
+ rootNamespace: a_graphql_entity_for(namespace, :name, :path)
+ ),
+ a_graphql_entity_for(public_resource, rootNamespace: nil)
+ )
+ end
+ end
+
+ describe 'openIssuesCount' do
+ before_all do
+ namespace.add_developer(user)
+ end
+
+ before_all do
+ create(:issue, :opened, project: project1)
+ create(:issue, :opened, project: project1)
+
+ create(:issue, :opened, project: public_project)
+ end
+
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResources {
+ nodes {
+ openIssuesCount
+ }
+ }
+ }
+ GQL
+ end
+
+ it 'returns the correct count' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResources, :nodes)).to contain_exactly(
+ a_graphql_entity_for(openIssuesCount: 2),
+ a_graphql_entity_for(openIssuesCount: 1)
+ )
+ end
+
+ it_behaves_like 'avoids N+1 queries'
+ end
+
+ describe 'openMergeRequestsCount' do
+ before_all do
+ namespace.add_developer(user)
+ end
+
+ before_all do
+ create(:merge_request, :opened, source_project: project1)
+ create(:merge_request, :opened, source_project: public_project)
+ end
+
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResources {
+ nodes {
+ openMergeRequestsCount
+ }
+ }
+ }
+ GQL
+ end
+
+ it 'returns the correct count' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResources, :nodes)).to contain_exactly(
+ a_graphql_entity_for(openMergeRequestsCount: 1),
+ a_graphql_entity_for(openMergeRequestsCount: 1)
+ )
+ end
+
+ it_behaves_like 'avoids N+1 queries'
+ end
+
+ # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/429636
+ context 'when using `projectPath` (legacy) to fetch resources' do
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResources(projectPath: "#{project1.full_path}") {
+ nodes {
+ #{all_graphql_fields_for('CiCatalogResource', max_depth: 1)}
+ }
+ }
+ }
+ GQL
+ end
+
+ context 'when the current user has permission to read the namespace catalog' do
+ before_all do
+ namespace.add_developer(user)
+ end
+
+ it 'returns catalog resources with the expected data' do
+ resource2 = create(:ci_catalog_resource, project: project2)
+ _resource_in_another_namespace = create(:ci_catalog_resource)
+
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResources, :nodes)).to contain_exactly(
+ a_graphql_entity_for(resource1),
+ a_graphql_entity_for(
+ resource2, :name, :description,
+ icon: project2.avatar_path,
+ webPath: "/#{project2.full_path}",
+ starCount: project2.star_count,
+ forksCount: project2.forks_count,
+ readmeHtml: '',
+ latestReleasedAt: resource2.latest_released_at
+ )
+ )
+ end
+
+ it_behaves_like 'avoids N+1 queries'
+ end
+
+ context 'when the current user does not have permission to read the namespace catalog' do
+ it 'returns no resources' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResources, :nodes)).to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/ci/manual_variables_spec.rb b/spec/requests/api/graphql/ci/manual_variables_spec.rb
index 47dccc0deb6..41788881e62 100644
--- a/spec/requests/api/graphql/ci/manual_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/manual_variables_spec.rb
@@ -90,6 +90,6 @@ RSpec.describe 'Query.project(fullPath).pipelines.jobs.manualVariables', feature
variables_data = graphql_data.dig('project', 'pipelines', 'nodes').first
.dig('jobs', 'nodes').flat_map { |job| job.dig('manualVariables', 'nodes') }
- expect(variables_data.map { |var| var['key'] }).to match_array(%w(MANUAL_TEST_VAR_1 MANUAL_TEST_VAR_2))
+ expect(variables_data.map { |var| var['key'] }).to match_array(%w[MANUAL_TEST_VAR_1 MANUAL_TEST_VAR_2])
end
end
diff --git a/spec/requests/api/graphql/ci/runners_spec.rb b/spec/requests/api/graphql/ci/runners_spec.rb
index c5571086700..0e2712d742d 100644
--- a/spec/requests/api/graphql/ci/runners_spec.rb
+++ b/spec/requests/api/graphql/ci/runners_spec.rb
@@ -35,28 +35,16 @@ RSpec.describe 'Query.runners', feature_category: :runner_fleet do
end
context 'with filters' do
- let(:query) do
- %(
- query {
- runners(type: #{runner_type}, status: #{status}) {
- #{fields}
- }
- }
- )
- end
-
- before do
- allow_next_instance_of(::Gitlab::Ci::RunnerUpgradeCheck) do |instance|
- allow(instance).to receive(:check_runner_upgrade_suggestion)
- end
-
- post_graphql(query, current_user: current_user)
- end
-
shared_examples 'a working graphql query returning expected runner' do
- it_behaves_like 'a working graphql query'
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+ end
it 'returns expected runner' do
+ post_graphql(query, current_user: current_user)
+
expect(runners_graphql_data['nodes']).to contain_exactly(a_graphql_entity_for(expected_runner))
end
@@ -86,22 +74,63 @@ RSpec.describe 'Query.runners', feature_category: :runner_fleet do
end
end
- context 'runner_type is INSTANCE_TYPE and status is ACTIVE' do
- let(:runner_type) { 'INSTANCE_TYPE' }
- let(:status) { 'ACTIVE' }
+ context 'when filtered on type and status' do
+ let(:query) do
+ %(
+ query {
+ runners(type: #{runner_type}, status: #{status}) {
+ #{fields}
+ }
+ }
+ )
+ end
- let!(:expected_runner) { instance_runner }
+ before do
+ allow_next_instance_of(::Gitlab::Ci::RunnerUpgradeCheck) do |instance|
+ allow(instance).to receive(:check_runner_upgrade_suggestion)
+ end
+ end
- it_behaves_like 'a working graphql query returning expected runner'
+ context 'runner_type is INSTANCE_TYPE and status is ACTIVE' do
+ let(:runner_type) { 'INSTANCE_TYPE' }
+ let(:status) { 'ACTIVE' }
+
+ let!(:expected_runner) { instance_runner }
+
+ it_behaves_like 'a working graphql query returning expected runner'
+ end
+
+ context 'runner_type is PROJECT_TYPE and status is NEVER_CONTACTED' do
+ let(:runner_type) { 'PROJECT_TYPE' }
+ let(:status) { 'NEVER_CONTACTED' }
+
+ let!(:expected_runner) { project_runner }
+
+ it_behaves_like 'a working graphql query returning expected runner'
+ end
end
- context 'runner_type is PROJECT_TYPE and status is NEVER_CONTACTED' do
- let(:runner_type) { 'PROJECT_TYPE' }
- let(:status) { 'NEVER_CONTACTED' }
+ context 'when filtered on version prefix' do
+ let_it_be(:version_runner) { create(:ci_runner, :project, active: false, description: 'Runner with machine') }
+ let_it_be(:version_runner_machine) { create(:ci_runner_machine, runner: version_runner, version: '15.11.0') }
+
+ let(:query) do
+ %(
+ query {
+ runners(versionPrefix: "#{version_prefix}") {
+ #{fields}
+ }
+ }
+ )
+ end
+
+ context 'version_prefix is "15."' do
+ let(:version_prefix) { '15.' }
- let!(:expected_runner) { project_runner }
+ let!(:expected_runner) { version_runner }
- it_behaves_like 'a working graphql query returning expected runner'
+ it_behaves_like 'a working graphql query returning expected runner'
+ end
end
end
diff --git a/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb b/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
index 118a11851dd..20277c7e27b 100644
--- a/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
+++ b/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
@@ -313,4 +313,124 @@ RSpec.describe 'container repository details', feature_category: :container_regi
end
it_behaves_like 'handling graphql network errors with the container registry'
+
+ context 'when list tags API is enabled', :saas do
+ before do
+ stub_container_registry_config(enabled: true)
+ allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(true)
+
+ allow_next_instances_of(ContainerRegistry::GitlabApiClient, nil) do |client|
+ allow(client).to receive(:tags).and_return(response_body)
+ end
+ end
+
+ let_it_be(:raw_tags_response) do
+ [
+ {
+ name: 'latest',
+ digest: 'sha256:1234567892',
+ config_digest: 'sha256:3332132331',
+ media_type: 'application/vnd.oci.image.manifest.v1+json',
+ size_bytes: 1234567892,
+ created_at: 10.minutes.ago,
+ updated_at: 10.minutes.ago
+ }
+ ]
+ end
+
+ let_it_be(:url) { URI('/gitlab/v1/repositories/group1/proj1/tags/list/?before=tag1') }
+
+ let_it_be(:response_body) do
+ {
+ pagination: { previous: { uri: url }, next: { uri: url } },
+ response_body: ::Gitlab::Json.parse(raw_tags_response.to_json)
+ }
+ end
+
+ it_behaves_like 'a working graphql query' do # OK
+ before do
+ subject
+ end
+
+ it 'matches the JSON schema' do
+ expect(container_repository_details_response).to match_schema('graphql/container_repository_details')
+ end
+ end
+
+ context 'with different permissions' do # OK
+ let_it_be(:user) { create(:user) }
+
+ let(:tags_response) { container_repository_details_response.dig('tags', 'nodes') }
+
+ where(:project_visibility, :role, :access_granted, :can_delete) do
+ :private | :maintainer | true | true
+ :private | :developer | true | true
+ :private | :reporter | true | false
+ :private | :guest | false | false
+ :private | :anonymous | false | false
+ :public | :maintainer | true | true
+ :public | :developer | true | true
+ :public | :reporter | true | false
+ :public | :guest | true | false
+ :public | :anonymous | true | false
+ end
+
+ with_them do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility.to_s.upcase, false))
+ project.add_member(user, role) unless role == :anonymous
+ end
+
+ it 'return the proper response' do
+ subject
+
+ if access_granted
+ expect(tags_response.size).to eq(raw_tags_response.size)
+ expect(container_repository_details_response.dig('canDelete')).to eq(can_delete)
+ else
+ expect(container_repository_details_response).to eq(nil)
+ end
+ end
+ end
+ end
+
+ context 'querying' do
+ let(:name) { 'l' }
+ let(:tags_response) { container_repository_details_response.dig('tags', 'edges') }
+ let(:variables) do
+ { id: container_repository_global_id, n: name }
+ end
+
+ let(:query) do
+ <<~GQL
+ query($id: ContainerRepositoryID!, $n: String) {
+ containerRepository(id: $id) {
+ tags(name: $n) {
+ edges {
+ node {
+ #{all_graphql_fields_for('ContainerRepositoryTag')}
+ }
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ it 'returns the tag response', :aggregate_failures do
+ subject
+
+ expect(tags_response.size).to eq(1)
+ expect(tags_response.first.dig('node', 'name')).to eq('latest')
+ end
+
+ context 'invalid filter' do
+ let(:name) { 1 }
+
+ it_behaves_like 'returning an invalid value error'
+ end
+ end
+
+ it_behaves_like 'handling graphql network errors with the container registry'
+ end
end
diff --git a/spec/requests/api/graphql/gitlab_schema_spec.rb b/spec/requests/api/graphql/gitlab_schema_spec.rb
index d55a70f503c..060a1b42cb6 100644
--- a/spec/requests/api/graphql/gitlab_schema_spec.rb
+++ b/spec/requests/api/graphql/gitlab_schema_spec.rb
@@ -113,7 +113,7 @@ RSpec.describe 'GitlabSchema configurations', feature_category: :integrations do
context 'regular queries' do
subject do
- query = graphql_query_for('project', { 'fullPath' => project.full_path }, %w(id name description))
+ query = graphql_query_for('project', { 'fullPath' => project.full_path }, %w[id name description])
post_graphql(query)
end
@@ -125,7 +125,7 @@ RSpec.describe 'GitlabSchema configurations', feature_category: :integrations do
subject do
queries = [
- { query: graphql_query_for('project', { 'fullPath' => '$fullPath' }, %w(id name description)) }, # Complexity 4
+ { query: graphql_query_for('project', { 'fullPath' => '$fullPath' }, %w[id name description]) }, # Complexity 4
{ query: graphql_query_for('echo', { 'text' => "$test" }, []), variables: { "test" => "Hello world" } }, # Complexity 1
{ query: graphql_query_for('project', { 'fullPath' => project.full_path }, "userPermissions { createIssue }") } # Complexity 3
]
@@ -215,7 +215,7 @@ RSpec.describe 'GitlabSchema configurations', feature_category: :integrations do
context "global id's" do
it 'uses GlobalID to expose ids' do
- post_graphql(graphql_query_for('project', { 'fullPath' => project.full_path }, %w(id)),
+ post_graphql(graphql_query_for('project', { 'fullPath' => project.full_path }, %w[id]),
current_user: project.first_owner)
parsed_id = GlobalID.parse(graphql_data['project']['id'])
diff --git a/spec/requests/api/graphql/group/container_repositories_spec.rb b/spec/requests/api/graphql/group/container_repositories_spec.rb
index 51d12261247..9206ead1534 100644
--- a/spec/requests/api/graphql/group/container_repositories_spec.rb
+++ b/spec/requests/api/graphql/group/container_repositories_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe 'getting container repositories in a group', feature_category: :s
group.add_owner(owner)
stub_container_registry_config(enabled: true)
container_repositories.each do |repository|
- stub_container_registry_tags(repository: repository.path, tags: %w(tag1 tag2 tag3), with_manifest: false)
+ stub_container_registry_tags(repository: repository.path, tags: %w[tag1 tag2 tag3], with_manifest: false)
end
end
@@ -142,7 +142,7 @@ RSpec.describe 'getting container repositories in a group', feature_category: :s
end
before do
- stub_container_registry_tags(repository: container_repository.path, tags: %w(tag4 tag5 tag6), with_manifest: false)
+ stub_container_registry_tags(repository: container_repository.path, tags: %w[tag4 tag5 tag6], with_manifest: false)
end
it 'returns the searched container repository' do
diff --git a/spec/requests/api/graphql/group/data_transfer_spec.rb b/spec/requests/api/graphql/group/data_transfer_spec.rb
index b7c038afa54..e17074a0247 100644
--- a/spec/requests/api/graphql/group/data_transfer_spec.rb
+++ b/spec/requests/api/graphql/group/data_transfer_spec.rb
@@ -71,45 +71,21 @@ RSpec.describe 'group data transfers', feature_category: :source_code_management
context 'when user has enough permissions' do
before do
group.add_owner(current_user)
+ subject
end
- context 'when data_transfer_monitoring_mock_data is NOT enabled' do
- before do
- stub_feature_flags(data_transfer_monitoring_mock_data: false)
- subject
- end
-
- it 'returns real results' do
- expect(response).to have_gitlab_http_status(:ok)
+ it 'returns real results' do
+ expect(response).to have_gitlab_http_status(:ok)
- expect(egress_data.count).to eq(2)
+ expect(egress_data.count).to eq(2)
- expect(egress_data.first.keys).to match_array(
- %w[date totalEgress repositoryEgress artifactsEgress packagesEgress registryEgress]
- )
+ expect(egress_data.first.keys).to match_array(
+ %w[date totalEgress repositoryEgress artifactsEgress packagesEgress registryEgress]
+ )
- expect(egress_data.pluck('repositoryEgress')).to match_array(%w[1 6])
- end
-
- it_behaves_like 'a working graphql query'
+ expect(egress_data.pluck('repositoryEgress')).to match_array(%w[1 6])
end
- context 'when data_transfer_monitoring_mock_data is enabled' do
- before do
- stub_feature_flags(data_transfer_monitoring_mock_data: true)
- subject
- end
-
- it 'returns mock results' do
- expect(response).to have_gitlab_http_status(:ok)
-
- expect(egress_data.count).to eq(12)
- expect(egress_data.first.keys).to match_array(
- %w[date totalEgress repositoryEgress artifactsEgress packagesEgress registryEgress]
- )
- end
-
- it_behaves_like 'a working graphql query'
- end
+ it_behaves_like 'a working graphql query'
end
end
diff --git a/spec/requests/api/graphql/group/milestones_spec.rb b/spec/requests/api/graphql/group/milestones_spec.rb
index 209588835f2..6063e6d5293 100644
--- a/spec/requests/api/graphql/group/milestones_spec.rb
+++ b/spec/requests/api/graphql/group/milestones_spec.rb
@@ -136,7 +136,7 @@ RSpec.describe 'Milestones through GroupQuery', feature_category: :team_planning
let_it_be(:closed_issue) { create(:issue, :closed, project: project, milestone: milestone) }
let(:milestone_query) do
- %{
+ %(
id
title
description
@@ -149,7 +149,7 @@ RSpec.describe 'Milestones through GroupQuery', feature_category: :team_planning
projectMilestone
groupMilestone
subgroupMilestone
- }
+ )
end
def post_query
@@ -180,12 +180,12 @@ RSpec.describe 'Milestones through GroupQuery', feature_category: :team_planning
context 'milestone statistics' do
let(:milestone_query) do
- %{
+ %(
stats {
totalIssuesCount
closedIssuesCount
}
- }
+ )
end
it 'returns the correct milestone statistics' do
diff --git a/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb b/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb
index 2939e9307e9..09a229c2098 100644
--- a/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb
+++ b/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb
@@ -54,6 +54,7 @@ RSpec.describe 'Query.project.mergeRequest.codequalityReportsComparer', feature_
let(:codequality_reports_comparer_fields) do
<<~QUERY
codequalityReportsComparer {
+ status
report {
status
newErrors {
@@ -138,6 +139,7 @@ RSpec.describe 'Query.project.mergeRequest.codequalityReportsComparer', feature_
expect(result).to match(
a_hash_including(
{
+ status: 'PARSED',
report: {
status: 'FAILED',
newErrors: [
diff --git a/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb b/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
index e3a7442ffe6..316b0f3755d 100644
--- a/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
+++ b/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe 'Deleting Sidekiq jobs', :clean_gitlab_redis_queues, feature_cate
let(:current_user) { create(:user) }
it_behaves_like 'a mutation that returns top-level errors',
- errors: ['You must be an admin to use this mutation']
+ errors: ['You must be an admin to use this mutation']
end
context 'when the user is an admin' do
@@ -43,7 +43,7 @@ RSpec.describe 'Deleting Sidekiq jobs', :clean_gitlab_redis_queues, feature_cate
raise 'Not enqueued!' if Sidekiq::Queue.new(queue).size.zero?
end
- it 'returns info about the deleted jobs', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/425824' do
+ it 'returns info about the deleted jobs' do
add_job(admin, [1])
add_job(admin, [2])
add_job(create(:user), [3])
@@ -51,9 +51,7 @@ RSpec.describe 'Deleting Sidekiq jobs', :clean_gitlab_redis_queues, feature_cate
post_graphql_mutation(mutation, current_user: admin)
expect(mutation_response['errors']).to be_empty
- expect(mutation_response['result']).to eq('completed' => true,
- 'deletedJobs' => 2,
- 'queueSize' => 1)
+ expect(mutation_response['result']).to eq('completed' => true, 'deletedJobs' => 2, 'queueSize' => 1)
end
end
@@ -61,14 +59,14 @@ RSpec.describe 'Deleting Sidekiq jobs', :clean_gitlab_redis_queues, feature_cate
let(:variables) { { queue_name: queue } }
it_behaves_like 'a mutation that returns errors in the response',
- errors: ['No metadata provided']
+ errors: ['No metadata provided']
end
context 'when the queue does not exist' do
let(:variables) { { user: admin.username, queue_name: 'authorized_projects_2' } }
it_behaves_like 'a mutation that returns top-level errors',
- errors: ['Queue authorized_projects_2 not found']
+ errors: ['Queue authorized_projects_2 not found']
end
end
end
diff --git a/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb b/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb
index fbe6d95dfff..f2b516783e5 100644
--- a/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb
@@ -14,21 +14,23 @@ RSpec.describe 'Create an alert issue from an alert', feature_category: :inciden
project_path: project.full_path,
iid: alert.iid.to_s
}
- graphql_mutation(:create_alert_issue, variables,
- <<~QL
- clientMutationId
- errors
- alert {
- iid
- issue {
- iid
- }
- }
- issue {
- iid
- title
- }
- QL
+ graphql_mutation(
+ :create_alert_issue,
+ variables,
+ <<~QL
+ clientMutationId
+ errors
+ alert {
+ iid
+ issue {
+ iid
+ }
+ }
+ issue {
+ iid
+ title
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
index 65a5fb87f9a..e7e23304d81 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
@@ -6,9 +6,11 @@ RSpec.describe 'Toggling an AwardEmoji', feature_category: :shared do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
- let_it_be(:project, reload: true) { create(:project) }
- let_it_be(:awardable) { create(:note, project: project) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project, reload: true) { create(:project, group: group) }
+ let_it_be(:issue_note) { create(:note, project: project) }
+ let(:awardable) { issue_note }
let(:emoji_name) { 'thumbsup' }
let(:mutation) do
variables = {
@@ -36,8 +38,8 @@ RSpec.describe 'Toggling an AwardEmoji', feature_category: :shared do
end
context 'when the user has permission' do
- before do
- project.add_developer(current_user)
+ before_all do
+ group.add_developer(current_user)
end
context 'when the given awardable is not an Awardable' do
@@ -60,6 +62,33 @@ RSpec.describe 'Toggling an AwardEmoji', feature_category: :shared do
end
context 'when the given awardable is an Awardable' do
+ context 'when the awardable is a work item' do
+ context 'when the work item is associated directly with a group' do
+ let_it_be(:group_work_item) { create(:work_item, :group_level, namespace: group) }
+ let(:awardable) { group_work_item }
+
+ context 'when no emoji has been awarded by the current_user yet' do
+ it 'creates an emoji' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { AwardEmoji.count }.by(1)
+ end
+ end
+
+ context 'when an emoji has been awarded by the current_user' do
+ before do
+ create_award_emoji(current_user)
+ end
+
+ it 'removes the emoji' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { AwardEmoji.count }.by(-1)
+ end
+ end
+ end
+ end
+
context 'when no emoji has been awarded by the current_user yet' do
# Create an award emoji for another user. This therefore tests that
# toggling is correctly scoped to the user's emoji only.
diff --git a/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb b/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb
index df64caa1cfb..8e71d77f7bc 100644
--- a/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb
+++ b/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb
@@ -131,22 +131,24 @@ RSpec.describe 'Reposition and move issue within board lists', feature_category:
end
def mutation(additional_params = {})
- graphql_mutation(mutation_name, issue_move_params.merge(additional_params),
- <<-QL.strip_heredoc
- clientMutationId
- issue {
- iid,
- relativePosition
- labels {
- edges {
- node{
- title
- }
- }
- }
- }
- errors
- QL
+ graphql_mutation(
+ mutation_name,
+ issue_move_params.merge(additional_params),
+ <<-QL.strip_heredoc
+ clientMutationId
+ issue {
+ iid,
+ relativePosition
+ labels {
+ edges {
+ node{
+ title
+ }
+ }
+ }
+ }
+ errors
+ QL
)
end
end
diff --git a/spec/requests/api/graphql/mutations/ci/catalog/resources/create_spec.rb b/spec/requests/api/graphql/mutations/ci/catalog/resources/create_spec.rb
new file mode 100644
index 00000000000..f990cab55f4
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/catalog/resources/create_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'CatalogResourcesCreate', feature_category: :pipeline_composition do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project, :catalog_resource_with_components) }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path
+ }
+ graphql_mutation(:catalog_resources_create, variables,
+ <<-QL.strip_heredoc
+ errors
+ QL
+ )
+ end
+
+ context 'when unauthorized' do
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when authorized' do
+ context 'with a valid project' do
+ before_all do
+ project.add_owner(current_user)
+ end
+
+ it 'creates a catalog resource' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_mutation_response(:catalog_resources_create)['errors']).to be_empty
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/catalog/unpublish_spec.rb b/spec/requests/api/graphql/mutations/ci/catalog/unpublish_spec.rb
new file mode 100644
index 00000000000..07465777263
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/catalog/unpublish_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'CatalogResourceUnpublish', feature_category: :pipeline_composition do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be_with_reload(:resource) { create(:ci_catalog_resource) }
+
+ let(:mutation) do
+ graphql_mutation(
+ :catalog_resource_unpublish,
+ id: resource.to_gid.to_s
+ )
+ end
+
+ subject(:post_query) { post_graphql_mutation(mutation, current_user: current_user) }
+
+ context 'when unauthorized' do
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when authorized' do
+ before_all do
+ resource.project.add_owner(current_user)
+ end
+
+ context 'when the catalog resource is in published state' do
+ it 'updates the state to draft' do
+ resource.update!(state: :published)
+ expect(resource.state).to eq('published')
+
+ post_query
+
+ expect(resource.reload.state).to eq('draft')
+ expect_graphql_errors_to_be_empty
+ end
+ end
+
+ context 'when the catalog resource is already in draft state' do
+ it 'leaves the state as draft' do
+ expect(resource.state).to eq('draft')
+
+ post_query
+
+ expect(resource.reload.state).to eq('draft')
+ expect_graphql_errors_to_be_empty
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_retry_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_retry_spec.rb
index e7edc86bea0..70b154946ef 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_retry_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_retry_spec.rb
@@ -13,13 +13,15 @@ RSpec.describe 'PipelineRetry', feature_category: :continuous_integration do
variables = {
id: pipeline.to_global_id.to_s
}
- graphql_mutation(:pipeline_retry, variables,
- <<-QL
- errors
- pipeline {
- id
- }
- QL
+ graphql_mutation(
+ :pipeline_retry,
+ variables,
+ <<-QL
+ errors
+ pipeline {
+ id
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/clusters/agent_tokens/agent_tokens/create_spec.rb b/spec/requests/api/graphql/mutations/clusters/agent_tokens/agent_tokens/create_spec.rb
index ef0d44395bf..dd4b015409b 100644
--- a/spec/requests/api/graphql/mutations/clusters/agent_tokens/agent_tokens/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/clusters/agent_tokens/agent_tokens/create_spec.rb
@@ -23,8 +23,8 @@ RSpec.describe 'Create a new cluster agent token', feature_category: :deployment
context 'without user permissions' do
it_behaves_like 'a mutation that returns top-level errors',
- errors: ["The resource that you are attempting to access does not exist "\
- "or you don't have permission to perform this action"]
+ errors: ["The resource that you are attempting to access does not exist "\
+ "or you don't have permission to perform this action"]
it 'does not create a token' do
expect { post_graphql_mutation(mutation, current_user: current_user) }.not_to change(Clusters::AgentToken, :count)
diff --git a/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb b/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb
index b70a6282a7a..a2a093d63e6 100644
--- a/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb
@@ -22,8 +22,8 @@ RSpec.describe 'Delete a cluster agent', feature_category: :deployment_managemen
context 'without project permissions' do
it_behaves_like 'a mutation that returns top-level errors',
- errors: ['The resource that you are attempting to access does not exist '\
- 'or you don\'t have permission to perform this action']
+ errors: ['The resource that you are attempting to access does not exist '\
+ 'or you don\'t have permission to perform this action']
it 'does not delete cluster agent' do
expect { cluster_agent.reload }.not_to raise_error
diff --git a/spec/requests/api/graphql/mutations/container_registry/protection/rule/create_spec.rb b/spec/requests/api/graphql/mutations/container_registry/protection/rule/create_spec.rb
new file mode 100644
index 00000000000..0c708c3dc41
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/container_registry/protection/rule/create_spec.rb
@@ -0,0 +1,180 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Creating the container registry protection rule', :aggregate_failures, feature_category: :container_registry do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user, maintainer_projects: [project]) }
+
+ let(:container_registry_protection_rule_attributes) do
+ build_stubbed(:container_registry_protection_rule, project: project)
+ end
+
+ let(:kwargs) do
+ {
+ project_path: project.full_path,
+ container_path_pattern: container_registry_protection_rule_attributes.container_path_pattern,
+ push_protected_up_to_access_level: 'MAINTAINER',
+ delete_protected_up_to_access_level: 'MAINTAINER'
+ }
+ end
+
+ let(:mutation) do
+ graphql_mutation(:create_container_registry_protection_rule, kwargs,
+ <<~QUERY
+ containerRegistryProtectionRule {
+ id
+ containerPathPattern
+ }
+ clientMutationId
+ errors
+ QUERY
+ )
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:create_container_registry_protection_rule) }
+
+ subject { post_graphql_mutation(mutation, current_user: user) }
+
+ shared_examples 'a successful response' do
+ it { subject.tap { expect_graphql_errors_to_be_empty } }
+
+ it do
+ subject
+
+ expect(mutation_response).to include(
+ 'errors' => be_blank,
+ 'containerRegistryProtectionRule' => {
+ 'id' => be_present,
+ 'containerPathPattern' => kwargs[:container_path_pattern]
+ }
+ )
+ end
+
+ it 'creates container registry protection rule in the database' do
+ expect { subject }.to change { ::ContainerRegistry::Protection::Rule.count }.by(1)
+
+ expect(::ContainerRegistry::Protection::Rule.where(project: project,
+ container_path_pattern: kwargs[:container_path_pattern])).to exist
+ end
+ end
+
+ shared_examples 'an erroneous response' do
+ it { expect { subject }.not_to change { ::ContainerRegistry::Protection::Rule.count } }
+ end
+
+ it_behaves_like 'a successful response'
+
+ context 'with invalid input fields `pushProtectedUpToAccessLevel` and `deleteProtectedUpToAccessLevel`' do
+ let(:kwargs) do
+ super().merge(
+ push_protected_up_to_access_level: 'UNKNOWN_ACCESS_LEVEL',
+ delete_protected_up_to_access_level: 'UNKNOWN_ACCESS_LEVEL'
+ )
+ end
+
+ it_behaves_like 'an erroneous response'
+
+ it {
+ subject
+
+ expect_graphql_errors_to_include([/pushProtectedUpToAccessLevel/, /deleteProtectedUpToAccessLevel/])
+ }
+ end
+
+ context 'with invalid input field `containerPathPattern`' do
+ let(:kwargs) do
+ super().merge(container_path_pattern: '')
+ end
+
+ it_behaves_like 'an erroneous response'
+
+ it { subject.tap { expect_graphql_errors_to_be_empty } }
+
+ it {
+ subject.tap do
+ expect(mutation_response['errors']).to eq ["Container path pattern can't be blank"]
+ end
+ }
+ end
+
+ context 'with existing containers protection rule' do
+ let_it_be(:existing_container_registry_protection_rule) do
+ create(:container_registry_protection_rule, project: project,
+ push_protected_up_to_access_level: Gitlab::Access::DEVELOPER)
+ end
+
+ context 'when container name pattern is slightly different' do
+ let(:kwargs) do
+ # The field `container_path_pattern` is unique; this is why we change the value in a minimum way
+ super().merge(
+ container_path_pattern: "#{existing_container_registry_protection_rule.container_path_pattern}-unique"
+ )
+ end
+
+ it_behaves_like 'a successful response'
+
+ it 'adds another container registry protection rule to the database' do
+ expect { subject }.to change { ::ContainerRegistry::Protection::Rule.count }.from(1).to(2)
+ end
+ end
+
+ context 'when field `container_path_pattern` is taken' do
+ let(:kwargs) do
+ super().merge(container_path_pattern: existing_container_registry_protection_rule.container_path_pattern,
+ push_protected_up_to_access_level: 'MAINTAINER')
+ end
+
+ it_behaves_like 'an erroneous response'
+
+ it { subject.tap { expect_graphql_errors_to_be_empty } }
+
+ it 'returns without error' do
+ subject
+
+ expect(mutation_response['errors']).to eq ['Container path pattern has already been taken']
+ end
+
+ it 'does not create new container protection rules' do
+ expect(::ContainerRegistry::Protection::Rule.where(project: project,
+ container_path_pattern: kwargs[:container_path_pattern],
+ push_protected_up_to_access_level: Gitlab::Access::MAINTAINER)).not_to exist
+ end
+ end
+ end
+
+ context 'when user does not have permission' do
+ let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
+ let_it_be(:reporter) { create(:user).tap { |u| project.add_reporter(u) } }
+ let_it_be(:guest) { create(:user).tap { |u| project.add_guest(u) } }
+ let_it_be(:anonymous) { create(:user) }
+
+ where(:user) do
+ [ref(:developer), ref(:reporter), ref(:guest), ref(:anonymous)]
+ end
+
+ with_them do
+ it_behaves_like 'an erroneous response'
+
+ it { subject.tap { expect_graphql_errors_to_include(/you don't have permission to perform this action/) } }
+ end
+ end
+
+ context "when feature flag ':container_registry_protected_containers' disabled" do
+ before do
+ stub_feature_flags(container_registry_protected_containers: false)
+ end
+
+ it_behaves_like 'an erroneous response'
+
+ it { subject.tap { expect(::ContainerRegistry::Protection::Rule.where(project: project)).not_to exist } }
+
+ it 'returns error of disabled feature flag' do
+ subject.tap do
+ expect_graphql_errors_to_include(/'container_registry_protected_containers' feature flag is disabled/)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb b/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb
index 0cb607e13ec..7ced22890df 100644
--- a/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb
+++ b/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe 'Destroying a container repository tags', feature_category: :cont
shared_examples 'destroying the container repository tags' do
before do
stub_delete_reference_requests(tags)
- expect_delete_tag_by_names(tags)
+ expect_delete_tags(tags)
allow_next_instance_of(ContainerRegistry::Client) do |client|
allow(client).to receive(:supports_tag_delete?).and_return(true)
end
diff --git a/spec/requests/api/graphql/mutations/design_management/delete_spec.rb b/spec/requests/api/graphql/mutations/design_management/delete_spec.rb
index 7ea32ae6d19..6f421abc489 100644
--- a/spec/requests/api/graphql/mutations/design_management/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/design_management/delete_spec.rb
@@ -47,28 +47,28 @@ RSpec.describe "deleting designs", feature_category: :design_management do
context 'the designs list is empty' do
it_behaves_like 'a failed request' do
let(:designs) { [] }
- let(:the_error) { a_string_matching %r/no filenames/ }
+ let(:the_error) { a_string_matching %r{no filenames} }
end
end
context 'the designs list contains filenames we cannot find' do
it_behaves_like 'a failed request' do
- let(:designs) { %w/foo bar baz/.map { |fn| double('file', filename: fn) } }
- let(:the_error) { a_string_matching %r/filenames were not found/ }
+ let(:designs) { %w[foo bar baz].map { |fn| double('file', filename: fn) } }
+ let(:the_error) { a_string_matching %r{filenames were not found} }
end
end
context 'the current user does not have developer access' do
it_behaves_like 'a failed request' do
let(:current_user) { create(:user) }
- let(:the_error) { a_string_matching %r/you don't have permission/ }
+ let(:the_error) { a_string_matching %r{you don't have permission} }
end
end
context "when the issue does not exist" do
it_behaves_like 'a failed request' do
let(:variables) { { iid: "1234567890" } }
- let(:the_error) { a_string_matching %r/does not exist/ }
+ let(:the_error) { a_string_matching %r{does not exist} }
end
end
diff --git a/spec/requests/api/graphql/mutations/design_management/upload_spec.rb b/spec/requests/api/graphql/mutations/design_management/upload_spec.rb
index 9b42b32c150..82a88a2c593 100644
--- a/spec/requests/api/graphql/mutations/design_management/upload_spec.rb
+++ b/spec/requests/api/graphql/mutations/design_management/upload_spec.rb
@@ -36,10 +36,11 @@ RSpec.describe "uploading designs", feature_category: :design_management do
end
it 'returns an error' do
- workhorse_post_with_file(api('/', current_user, version: 'graphql'),
- params: params,
- file_key: '1'
- )
+ workhorse_post_with_file(
+ api('/', current_user, version: 'graphql'),
+ params: params,
+ file_key: '1'
+ )
expect(response).to have_attributes(
code: eq('400'),
diff --git a/spec/requests/api/graphql/mutations/issues/link_alerts_spec.rb b/spec/requests/api/graphql/mutations/issues/link_alerts_spec.rb
index 85e21952f47..df6c20d6176 100644
--- a/spec/requests/api/graphql/mutations/issues/link_alerts_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/link_alerts_spec.rb
@@ -19,19 +19,21 @@ RSpec.describe 'Link alerts to an incident', feature_category: :incident_managem
alert_references: [alert1.to_reference, alert2.details_url]
}
- graphql_mutation(:issue_link_alerts, variables,
- <<-QL.strip_heredoc
- clientMutationId
- errors
- issue {
- iid
- alertManagementAlerts {
- nodes {
- iid
- }
- }
- }
- QL
+ graphql_mutation(
+ :issue_link_alerts,
+ variables,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ alertManagementAlerts {
+ nodes {
+ iid
+ }
+ }
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/issues/move_spec.rb b/spec/requests/api/graphql/mutations/issues/move_spec.rb
index 7d9579067b6..24188d5341d 100644
--- a/spec/requests/api/graphql/mutations/issues/move_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/move_spec.rb
@@ -16,14 +16,16 @@ RSpec.describe 'Moving an issue', feature_category: :team_planning do
iid: issue.iid.to_s
}
- graphql_mutation(:issue_move, variables,
- <<-QL.strip_heredoc
- clientMutationId
- errors
- issue {
- title
- }
- QL
+ graphql_mutation(
+ :issue_move,
+ variables,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ title
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb b/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb
index c5e6901d8f8..c62995c0b9b 100644
--- a/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb
@@ -15,15 +15,17 @@ RSpec.describe 'Setting an issue as confidential', feature_category: :team_plann
project_path: project.full_path,
iid: issue.iid.to_s
}
- graphql_mutation(:issue_set_confidential, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- issue {
- iid
- confidential
- }
- QL
+ graphql_mutation(
+ :issue_set_confidential,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ confidential
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb b/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb
index 497ae1cc13f..cdab267162e 100644
--- a/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb
@@ -26,18 +26,20 @@ RSpec.describe 'Setting issues crm contacts', feature_category: :service_desk do
contact_ids: contact_ids
}
- graphql_mutation(:issue_set_crm_contacts, variables,
- <<-QL.strip_heredoc
- clientMutationId
- errors
- issue {
- customerRelationsContacts {
- nodes {
- id
- }
- }
- }
- QL
+ graphql_mutation(
+ :issue_set_crm_contacts,
+ variables,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ customerRelationsContacts {
+ nodes {
+ id
+ }
+ }
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb b/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb
index 1a5a64e4196..f7c5febe56f 100644
--- a/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb
@@ -15,15 +15,17 @@ RSpec.describe 'Setting Due Date of an issue', feature_category: :team_planning
project_path: project.full_path,
iid: issue.iid.to_s
}
- graphql_mutation(:issue_set_due_date, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- issue {
- iid
- dueDate
- }
- QL
+ graphql_mutation(
+ :issue_set_due_date,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ dueDate
+ }
+ QL
)
end
@@ -68,7 +70,7 @@ RSpec.describe 'Setting Due Date of an issue', feature_category: :team_planning
it 'returns an error' do
post_graphql_mutation(mutation, current_user: current_user)
- expect(graphql_errors).to include(a_hash_including('message' => /Arguments must be provided: dueDate/))
+ expect(graphql_errors).to include(a_hash_including('message' => 'issueSetDueDate has the wrong arguments'))
end
end
diff --git a/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb b/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb
index a8025894b1e..547ec280150 100644
--- a/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb
@@ -16,15 +16,17 @@ RSpec.describe 'Setting an issue as locked', feature_category: :team_planning do
project_path: project.full_path,
iid: issue.iid.to_s
}
- graphql_mutation(:issue_set_locked, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- issue {
- iid
- discussionLocked
- }
- QL
+ graphql_mutation(
+ :issue_set_locked,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ discussionLocked
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb b/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb
index 77262c7f64f..d53b938a983 100644
--- a/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb
@@ -17,15 +17,17 @@ RSpec.describe 'Setting severity level of an incident', feature_category: :incid
iid: incident.iid.to_s
}
- graphql_mutation(:issue_set_severity, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- issue {
- iid
- severity
- }
- QL
+ graphql_mutation(
+ :issue_set_severity,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ severity
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/issues/unlink_alerts_spec.rb b/spec/requests/api/graphql/mutations/issues/unlink_alerts_spec.rb
index 7f6f968b1dd..807afdfb812 100644
--- a/spec/requests/api/graphql/mutations/issues/unlink_alerts_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/unlink_alerts_spec.rb
@@ -21,19 +21,21 @@ RSpec.describe 'Unlink alert from an incident', feature_category: :incident_mana
alert_id: alert_to_unlink.to_global_id.to_s
}
- graphql_mutation(:issue_unlink_alert, variables,
- <<-QL.strip_heredoc
- clientMutationId
- errors
- issue {
- iid
- alertManagementAlerts {
- nodes {
- id
- }
- }
- }
- QL
+ graphql_mutation(
+ :issue_unlink_alert,
+ variables,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ alertManagementAlerts {
+ nodes {
+ id
+ }
+ }
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb
index 7a1b3982111..ec82941b094 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb
@@ -16,11 +16,13 @@ RSpec.describe 'Setting assignees of a merge request', feature_category: :code_r
project_path: project.full_path,
iid: merge_request.iid.to_s
}
- graphql_mutation(:merge_request_reviewer_rereview, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- QL
+ graphql_mutation(
+ :merge_request_reviewer_rereview,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb
index 4a7d1083f2e..cb7bac771b3 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb
@@ -21,19 +21,21 @@ RSpec.describe 'Setting assignees of a merge request', :assume_throttled, featur
project_path: project.full_path,
iid: merge_request.iid.to_s
}
- graphql_mutation(:merge_request_set_assignees, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- mergeRequest {
- id
- assignees {
- nodes {
- username
- }
- }
- }
- QL
+ graphql_mutation(
+ :merge_request_set_assignees,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ mergeRequest {
+ id
+ assignees {
+ nodes {
+ username
+ }
+ }
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb
index 0c2e2975350..a2c5c235d25 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb
@@ -15,15 +15,17 @@ RSpec.describe 'Setting Draft status of a merge request', feature_category: :cod
project_path: project.full_path,
iid: merge_request.iid.to_s
}
- graphql_mutation(:merge_request_set_draft, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- mergeRequest {
- id
- title
- }
- QL
+ graphql_mutation(
+ :merge_request_set_draft,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ mergeRequest {
+ id
+ title
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_labels_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_labels_spec.rb
index e40a3cf7ce9..4ddd10b1734 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_labels_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_labels_spec.rb
@@ -17,19 +17,21 @@ RSpec.describe 'Setting labels of a merge request' do
project_path: project.full_path,
iid: merge_request.iid.to_s
}
- graphql_mutation(:merge_request_set_labels, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- mergeRequest {
- id
- labels {
- nodes {
- id
- }
- }
- }
- QL
+ graphql_mutation(
+ :merge_request_set_labels,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ mergeRequest {
+ id
+ labels {
+ nodes {
+ id
+ }
+ }
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb
index 73a38adf723..a6ddb9beb5c 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb
@@ -15,15 +15,17 @@ RSpec.describe 'Setting locked status of a merge request', feature_category: :co
project_path: project.full_path,
iid: merge_request.iid.to_s
}
- graphql_mutation(:merge_request_set_locked, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- mergeRequest {
- id
- discussionLocked
- }
- QL
+ graphql_mutation(
+ :merge_request_set_locked,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ mergeRequest {
+ id
+ discussionLocked
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb
index 1898ee5a62d..9debfbd474b 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb
@@ -16,17 +16,19 @@ RSpec.describe 'Setting milestone of a merge request', feature_category: :code_r
project_path: project.full_path,
iid: merge_request.iid.to_s
}
- graphql_mutation(:merge_request_set_milestone, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- mergeRequest {
- id
- milestone {
- id
- }
- }
- QL
+ graphql_mutation(
+ :merge_request_set_milestone,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ mergeRequest {
+ id
+ milestone {
+ id
+ }
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb
index fd87112be33..c9efba689c2 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb
@@ -21,19 +21,21 @@ RSpec.describe 'Setting reviewers of a merge request', :assume_throttled, featur
project_path: project.full_path,
iid: merge_request.iid.to_s
}
- graphql_mutation(:merge_request_set_reviewers, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- mergeRequest {
- id
- reviewers {
- nodes {
- username
- }
- }
- }
- QL
+ graphql_mutation(
+ :merge_request_set_reviewers,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ mergeRequest {
+ id
+ reviewers {
+ nodes {
+ username
+ }
+ }
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_time_estimate_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_time_estimate_spec.rb
index 6bc130a97cf..541cdf0660d 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_time_estimate_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_time_estimate_spec.rb
@@ -17,8 +17,11 @@ RSpec.describe 'Setting time estimate of a merge request', feature_category: :co
let(:extra_params) { { project_path: project.full_path } }
let(:input_params) { input.merge(extra_params) }
- let(:mutation) { graphql_mutation(:merge_request_update, input_params, nil, ['productAnalyticsState']) }
let(:mutation_response) { graphql_mutation_response(:merge_request_update) }
+ let(:mutation) do
+ # exclude codequalityReportsComparer because it's behind a feature flag
+ graphql_mutation(:merge_request_update, input_params, nil, %w[productAnalyticsState codequalityReportsComparer])
+ end
context 'when the user is not allowed to update a merge request' do
before_all do
diff --git a/spec/requests/api/graphql/mutations/merge_requests/update_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/update_spec.rb
index 48db23569b6..ef21f77d818 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/update_spec.rb
@@ -12,8 +12,11 @@ RSpec.describe 'Update of an existing merge request', feature_category: :code_re
let(:input) { { 'iid' => merge_request.iid.to_s } }
let(:extra_params) { { project_path: project.full_path } }
let(:input_params) { input.merge(extra_params) }
- let(:mutation) { graphql_mutation(:merge_request_update, input_params, nil, ['productAnalyticsState']) }
let(:mutation_response) { graphql_mutation_response(:merge_request_update) }
+ let(:mutation) do
+ # exclude codequalityReportsComparer because it's behind a feature flag
+ graphql_mutation(:merge_request_update, input_params, nil, %w[productAnalyticsState codequalityReportsComparer])
+ end
context 'when the user is not allowed to update the merge request' do
it_behaves_like 'a mutation that returns a top-level access error'
@@ -28,5 +31,17 @@ RSpec.describe 'Update of an existing merge request', feature_category: :code_re
let(:resource) { merge_request }
let(:mutation_name) { 'mergeRequestUpdate' }
end
+
+ context 'when required arguments are missing' do
+ let(:input_params) { {} }
+
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) do
+ include(end_with(
+ 'invalid value for projectPath (Expected value to not be null), iid (Expected value to not be null)'
+ ))
+ end
+ end
+ end
end
end
diff --git a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
index 480e184a60c..738dc3078e7 100644
--- a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
@@ -129,26 +129,6 @@ RSpec.describe 'Updating the package settings', feature_category: :package_regis
it_behaves_like 'returning a success'
it_behaves_like 'rejecting invalid regex'
-
- context 'when nuget_duplicates_option FF is disabled' do
- let(:params) do
- {
- namespace_path: namespace.full_path,
- 'nugetDuplicatesAllowed' => false
- }
- end
-
- before do
- stub_feature_flags(nuget_duplicates_option: false)
- end
-
- it 'raises an error', :aggregate_failures do
- subject
-
- expect(graphql_errors.size).to eq(1)
- expect(graphql_errors.first['message']).to include('feature flag is disabled')
- end
- end
end
RSpec.shared_examples 'accepting the mutation request creating the package settings' do
diff --git a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
index 37bcdf61d23..33d840cafd7 100644
--- a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
@@ -5,13 +5,15 @@ require 'spec_helper'
RSpec.describe 'Adding a Note', feature_category: :team_planning do
include GraphqlHelpers
- let_it_be(:current_user) { create(:user) }
-
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group).tap { |g| g.add_developer(developer) } }
+ let_it_be_with_reload(:project) { create(:project, :repository, group: group) }
+ let_it_be(:developer) { create(:user).tap { |u| group.add_developer(u) } }
let(:noteable) { create(:merge_request, source_project: project, target_project: project) }
- let(:project) { create(:project, :repository) }
let(:discussion) { nil }
let(:head_sha) { nil }
let(:body) { 'Body text' }
+ let(:current_user) { user }
let(:mutation) do
variables = {
noteable_id: GitlabSchema.id_from_object(noteable).to_s,
@@ -30,9 +32,7 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
it_behaves_like 'a Note mutation when the user does not have permission'
context 'when the user has permission' do
- before do
- project.add_developer(current_user)
- end
+ let(:current_user) { developer }
it_behaves_like 'a working GraphQL mutation'
@@ -78,8 +78,10 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
end
context 'for an issue' do
- let(:noteable) { create(:issue, project: project) }
+ let_it_be_with_reload(:issue) { create(:issue, project: project) }
+ let(:noteable) { issue }
let(:mutation) { graphql_mutation(:create_note, variables) }
+ let(:variables_extra) { {} }
let(:variables) do
{
noteable_id: GitlabSchema.id_from_object(noteable).to_s,
@@ -87,10 +89,6 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
}.merge(variables_extra)
end
- before do
- project.add_developer(current_user)
- end
-
context 'when using internal param' do
let(:variables_extra) { { internal: true } }
@@ -104,8 +102,8 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
end
context 'as work item' do
- let_it_be(:project) { create(:project) }
- let_it_be(:noteable) { create(:work_item, project: project) }
+ let_it_be_with_reload(:work_item) { create(:work_item, :task, project: project) }
+ let(:noteable) { work_item }
context 'when using internal param' do
let(:variables_extra) { { internal: true } }
@@ -120,10 +118,8 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
end
context 'without notes widget' do
- let(:variables_extra) { {} }
-
before do
- WorkItems::Type.default_by_type(:issue).widget_definitions.find_by_widget_type(:notes)
+ WorkItems::Type.default_by_type(:task).widget_definitions.find_by_widget_type(:notes)
.update!(disabled: true)
end
@@ -133,10 +129,6 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
end
context 'when body contains quick actions' do
- let_it_be(:noteable) { create(:work_item, :task, project: project) }
-
- let(:variables_extra) { {} }
-
it_behaves_like 'work item supports labels widget updates via quick actions'
it_behaves_like 'work item does not support labels widget updates via quick actions'
it_behaves_like 'work item supports assignee widget updates via quick actions'
@@ -145,6 +137,13 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
it_behaves_like 'work item does not support start and due date widget updates via quick actions'
it_behaves_like 'work item supports type change via quick actions'
end
+
+ context 'when work item is directly associated with a group' do
+ let_it_be_with_reload(:group_work_item) { create(:work_item, :group_level, :task, namespace: group) }
+ let(:noteable) { group_work_item }
+
+ it_behaves_like 'a Note mutation that creates a Note'
+ end
end
end
@@ -152,10 +151,6 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
let(:head_sha) { noteable.diff_head_sha }
let(:body) { '/merge' }
- before do
- project.add_developer(current_user)
- end
-
# NOTE: Known issue https://gitlab.com/gitlab-org/gitlab/-/issues/346557
it 'returns a nil note and info about the command in errors' do
post_graphql_mutation(mutation, current_user: current_user)
diff --git a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
index a5cd3c8b019..3f071a6d987 100644
--- a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
@@ -37,11 +37,13 @@ RSpec.describe 'Updating an image DiffNote', feature_category: :team_planning do
end
let!(:diff_note) do
- create(:image_diff_note_on_merge_request,
- noteable: noteable,
- project: noteable.project,
- note: original_body,
- position: original_position)
+ create(
+ :image_diff_note_on_merge_request,
+ noteable: noteable,
+ project: noteable.project,
+ note: original_body,
+ position: original_position
+ )
end
let(:mutation) do
diff --git a/spec/requests/api/graphql/mutations/organizations/create_spec.rb b/spec/requests/api/graphql/mutations/organizations/create_spec.rb
new file mode 100644
index 00000000000..ac6b04104ba
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/organizations/create_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Organizations::Create, feature_category: :cell do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+
+ let(:mutation) { graphql_mutation(:organization_create, params) }
+ let(:name) { 'Name' }
+ let(:path) { 'path' }
+ let(:params) do
+ {
+ name: name,
+ path: path
+ }
+ end
+
+ subject(:create_organization) { post_graphql_mutation(mutation, current_user: current_user) }
+
+ it { expect(described_class).to require_graphql_authorizations(:create_organization) }
+
+ def mutation_response
+ graphql_mutation_response(:organization_create)
+ end
+
+ context 'when the user does not have permission' do
+ let(:current_user) { nil }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+
+ it 'does not create an organization' do
+ expect { create_organization }.not_to change { Organizations::Organization.count }
+ end
+ end
+
+ context 'when the user has permission' do
+ let(:current_user) { user }
+
+ context 'when the params are invalid' do
+ let(:name) { '' }
+
+ it 'returns the validation error' do
+ create_organization
+
+ expect(mutation_response).to include('errors' => ["Name can't be blank"])
+ end
+ end
+
+ it 'creates an organization' do
+ expect { create_organization }.to change { Organizations::Organization.count }.by(1)
+ end
+
+ it 'returns the new organization' do
+ create_organization
+
+ expect(graphql_data_at(:organization_create, :organization)).to match a_hash_including(
+ 'name' => name,
+ 'path' => path
+ )
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb b/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb
index 2540e06be9a..5843109f356 100644
--- a/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb
@@ -17,14 +17,16 @@ RSpec.describe 'Updating the packages cleanup policy', feature_category: :packag
end
let(:mutation) do
- graphql_mutation(:update_packages_cleanup_policy, params,
- <<~QUERY
- packagesCleanupPolicy {
- keepNDuplicatedPackageFiles
- nextRunAt
- }
- errors
- QUERY
+ graphql_mutation(
+ :update_packages_cleanup_policy,
+ params,
+ <<~QUERY
+ packagesCleanupPolicy {
+ keepNDuplicatedPackageFiles
+ nextRunAt
+ }
+ errors
+ QUERY
)
end
diff --git a/spec/requests/api/graphql/mutations/packages/protection/rule/create_spec.rb b/spec/requests/api/graphql/mutations/packages/protection/rule/create_spec.rb
index b0c8526fa1c..ae5b6a5af95 100644
--- a/spec/requests/api/graphql/mutations/packages/protection/rule/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/packages/protection/rule/create_spec.rb
@@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe 'Creating the packages protection rule', :aggregate_failures, feature_category: :package_registry do
include GraphqlHelpers
- using RSpec::Parameterized::TableSyntax
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user, maintainer_projects: [project]) }
@@ -15,151 +14,162 @@ RSpec.describe 'Creating the packages protection rule', :aggregate_failures, fea
{
project_path: project.full_path,
package_name_pattern: package_protection_rule_attributes.package_name_pattern,
- package_type: "NPM",
- push_protected_up_to_access_level: "MAINTAINER"
+ package_type: 'NPM',
+ push_protected_up_to_access_level: 'MAINTAINER'
}
end
let(:mutation) do
graphql_mutation(:create_packages_protection_rule, kwargs,
<<~QUERY
- clientMutationId
+ packageProtectionRule {
+ id
+ packageNamePattern
+ packageType
+ pushProtectedUpToAccessLevel
+ }
errors
QUERY
)
end
- let(:mutation_response) { graphql_mutation_response(:create_packages_protection_rule) }
+ let(:mutation_response_package_protection_rule) do
+ graphql_data_at(:createPackagesProtectionRule, :packageProtectionRule)
+ end
- describe 'post graphql mutation' do
- subject { post_graphql_mutation(mutation, current_user: user) }
+ let(:mutation_response_errors) { graphql_data_at(:createPackagesProtectionRule, :errors) }
- context 'without existing packages protection rule' do
- it 'returns without error' do
- subject
+ subject { post_graphql_mutation(mutation, current_user: user) }
- expect_graphql_errors_to_be_empty
- end
+ shared_examples 'a successful response' do
+ it 'returns without error' do
+ subject
- it 'returns the created packages protection rule' do
- expect { subject }.to change { ::Packages::Protection::Rule.count }.by(1)
+ expect_graphql_errors_to_be_empty
+ expect(mutation_response_errors).to be_empty
+ end
- expect_graphql_errors_to_be_empty
- expect(Packages::Protection::Rule.where(project: project).count).to eq 1
+ it 'returns the created packages protection rule' do
+ subject
- expect(Packages::Protection::Rule.where(project: project,
- package_name_pattern: kwargs[:package_name_pattern])).to exist
- end
+ expect(mutation_response_package_protection_rule).to include(
+ 'id' => be_present,
+ 'packageNamePattern' => kwargs[:package_name_pattern],
+ 'packageType' => kwargs[:package_type],
+ 'pushProtectedUpToAccessLevel' => kwargs[:push_protected_up_to_access_level]
+ )
+ end
- context 'when invalid fields are given' do
- let(:kwargs) do
- {
- project_path: project.full_path,
- package_name_pattern: '',
- package_type: 'UNKNOWN_PACKAGE_TYPE',
- push_protected_up_to_access_level: 'UNKNOWN_ACCESS_LEVEL'
- }
- end
-
- it 'returns error about required argument' do
- subject
-
- expect_graphql_errors_to_include(/was provided invalid value for packageType/)
- expect_graphql_errors_to_include(/pushProtectedUpToAccessLevel/)
- end
- end
+ it 'creates one package protection rule' do
+ expect { subject }.to change { ::Packages::Protection::Rule.count }.by(1)
+
+ expect(Packages::Protection::Rule.last).to have_attributes(
+ project: project,
+ package_name_pattern: kwargs[:package_name_pattern],
+ package_type: kwargs[:package_type].downcase,
+ push_protected_up_to_access_level: kwargs[:push_protected_up_to_access_level].downcase
+ )
end
+ end
- context 'when user does not have permission' do
- let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
- let_it_be(:reporter) { create(:user).tap { |u| project.add_reporter(u) } }
- let_it_be(:guest) { create(:user).tap { |u| project.add_guest(u) } }
- let_it_be(:anonymous) { create(:user) }
+ shared_examples 'an erroneous response' do
+ it 'does not create one package protection rule' do
+ expect { subject }.not_to change { ::Packages::Protection::Rule.count }
+ end
+ end
- where(:user) do
- [ref(:developer), ref(:reporter), ref(:guest), ref(:anonymous)]
- end
+ it_behaves_like 'a successful response'
- with_them do
- it 'returns an error' do
- expect { subject }.not_to change { ::Packages::Protection::Rule.count }
+ context 'with invalid kwargs leading to error from graphql' do
+ let(:kwargs) do
+ super().merge!(
+ package_name_pattern: '',
+ package_type: 'UNKNOWN_PACKAGE_TYPE',
+ push_protected_up_to_access_level: 'UNKNOWN_ACCESS_LEVEL'
+ )
+ end
- expect_graphql_errors_to_include(/you don't have permission to perform this action/)
- end
- end
+ it_behaves_like 'an erroneous response'
+
+ it 'returns error about required argument' do
+ subject
+
+ expect_graphql_errors_to_include(/was provided invalid value for packageType/)
+ expect_graphql_errors_to_include(/pushProtectedUpToAccessLevel/)
end
+ end
- context 'with existing packages protection rule' do
- let_it_be(:existing_package_protection_rule) do
- create(:package_protection_rule, project: project, push_protected_up_to_access_level: Gitlab::Access::DEVELOPER)
- end
+ context 'with invalid kwargs leading to error from business model' do
+ let(:kwargs) { super().merge!(package_name_pattern: '') }
- context 'when package name pattern is slightly different' do
- let(:kwargs) do
- {
- project_path: project.full_path,
- # The field `package_name_pattern` is unique; this is why we change the value in a minimum way
- package_name_pattern: "#{existing_package_protection_rule.package_name_pattern}-unique",
- package_type: "NPM",
- push_protected_up_to_access_level: "DEVELOPER"
- }
- end
-
- it 'returns the created packages protection rule' do
- expect { subject }.to change { ::Packages::Protection::Rule.count }.by(1)
-
- expect(Packages::Protection::Rule.where(project: project).count).to eq 2
- expect(Packages::Protection::Rule.where(project: project,
- package_name_pattern: kwargs[:package_name_pattern])).to exist
- end
-
- it 'returns without error' do
- subject
-
- expect_graphql_errors_to_be_empty
- end
- end
+ it_behaves_like 'an erroneous response'
- context 'when field `package_name_pattern` is taken' do
- let(:kwargs) do
- {
- project_path: project.full_path,
- package_name_pattern: existing_package_protection_rule.package_name_pattern,
- package_type: 'NPM',
- push_protected_up_to_access_level: 'MAINTAINER'
- }
- end
-
- it 'returns without error' do
- subject
-
- expect(mutation_response).to include 'errors' => ['Package name pattern has already been taken']
- end
-
- it 'does not create new package protection rules' do
- expect { subject }.to change { Packages::Protection::Rule.count }.by(0)
-
- expect(Packages::Protection::Rule.where(project: project,
- package_name_pattern: kwargs[:package_name_pattern],
- push_protected_up_to_access_level: Gitlab::Access::MAINTAINER)).not_to exist
- end
- end
+ it 'returns an error' do
+ subject.tap { expect(mutation_response_errors).to include(/Package name pattern can't be blank/) }
end
+ end
- context "when feature flag ':packages_protected_packages' disabled" do
- before do
- stub_feature_flags(packages_protected_packages: false)
+ context 'with existing packages protection rule' do
+ let_it_be(:existing_package_protection_rule) do
+ create(:package_protection_rule, project: project, push_protected_up_to_access_level: :maintainer)
+ end
+
+ let(:kwargs) { super().merge!(package_name_pattern: existing_package_protection_rule.package_name_pattern) }
+
+ it_behaves_like 'an erroneous response'
+
+ it 'returns an error' do
+ subject.tap { expect(mutation_response_errors).to include(/Package name pattern has already been taken/) }
+ end
+
+ context 'when field `package_name_pattern` is different than existing one' do
+ let(:kwargs) do
+ # The field `package_name_pattern` is unique; this is why we change the value in a minimum way
+ super().merge!(package_name_pattern: "#{existing_package_protection_rule.package_name_pattern}-unique")
end
- it 'does not create any package protection rules' do
- expect { subject }.to change { Packages::Protection::Rule.count }.by(0)
+ it_behaves_like 'a successful response'
+ end
+
+ context 'when field `push_protected_up_to_access_level` is different than existing one' do
+ let(:kwargs) { super().merge!(push_protected_up_to_access_level: 'DEVELOPER') }
+
+ it_behaves_like 'an erroneous response'
- expect(Packages::Protection::Rule.where(project: project)).not_to exist
+ it 'returns an error' do
+ subject.tap { expect(mutation_response_errors).to include(/Package name pattern has already been taken/) }
end
+ end
+ end
- it 'returns error of disabled feature flag' do
- subject.tap { expect_graphql_errors_to_include(/'packages_protected_packages' feature flag is disabled/) }
+ context 'when user does not have permission' do
+ let_it_be(:anonymous) { create(:user) }
+ let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
+ let_it_be(:guest) { create(:user).tap { |u| project.add_guest(u) } }
+ let_it_be(:reporter) { create(:user).tap { |u| project.add_reporter(u) } }
+
+ where(:user) do
+ [ref(:developer), ref(:reporter), ref(:guest), ref(:anonymous)]
+ end
+
+ with_them do
+ it_behaves_like 'an erroneous response'
+
+ it 'returns an error' do
+ subject.tap { expect_graphql_errors_to_include(/you don't have permission to perform this action/) }
end
end
end
+
+ context "when feature flag ':packages_protected_packages' disabled" do
+ before do
+ stub_feature_flags(packages_protected_packages: false)
+ end
+
+ it_behaves_like 'an erroneous response'
+
+ it 'returns error of disabled feature flag' do
+ subject.tap { expect_graphql_errors_to_include(/'packages_protected_packages' feature flag is disabled/) }
+ end
+ end
end
diff --git a/spec/requests/api/graphql/mutations/packages/protection/rule/delete_spec.rb b/spec/requests/api/graphql/mutations/packages/protection/rule/delete_spec.rb
new file mode 100644
index 00000000000..1d94d520674
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/packages/protection/rule/delete_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Deleting a package protection rule', :aggregate_failures, feature_category: :package_registry do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be_with_refind(:package_protection_rule) { create(:package_protection_rule, project: project) }
+ let_it_be(:current_user) { create(:user, maintainer_projects: [project]) }
+
+ let(:mutation) { graphql_mutation(:delete_packages_protection_rule, input) }
+ let(:mutation_response) { graphql_mutation_response(:delete_packages_protection_rule) }
+ let(:input) { { id: package_protection_rule.to_global_id } }
+
+ subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+ shared_examples 'an erroneous reponse' do
+ it { subject.tap { expect(mutation_response).to be_blank } }
+ it { expect { subject }.not_to change { ::Packages::Protection::Rule.count } }
+ end
+
+ it_behaves_like 'a working GraphQL mutation'
+
+ it 'responds with deleted package protection rule' do
+ subject
+
+ expect(mutation_response).to include(
+ 'errors' => be_blank,
+ 'packageProtectionRule' => {
+ 'id' => package_protection_rule.to_global_id.to_s,
+ 'packageNamePattern' => package_protection_rule.package_name_pattern,
+ 'packageType' => package_protection_rule.package_type.upcase,
+ 'pushProtectedUpToAccessLevel' => package_protection_rule.push_protected_up_to_access_level.upcase
+ }
+ )
+ end
+
+ it { is_expected.tap { expect_graphql_errors_to_be_empty } }
+ it { expect { subject }.to change { ::Packages::Protection::Rule.count }.from(1).to(0) }
+
+ context 'with existing package protection rule belonging to other project' do
+ let_it_be(:package_protection_rule) do
+ create(:package_protection_rule, package_name_pattern: 'protection_rule_other_project')
+ end
+
+ it_behaves_like 'an erroneous reponse'
+
+ it { subject.tap { expect_graphql_errors_to_include(/you don't have permission to perform this action/) } }
+ end
+
+ context 'with deleted package protection rule' do
+ let!(:package_protection_rule) do
+ create(:package_protection_rule, project: project, package_name_pattern: 'protection_rule_deleted').destroy!
+ end
+
+ it_behaves_like 'an erroneous reponse'
+
+ it { subject.tap { expect_graphql_errors_to_include(/you don't have permission to perform this action/) } }
+ end
+
+ context 'when current_user does not have permission' do
+ let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
+ let_it_be(:reporter) { create(:user).tap { |u| project.add_reporter(u) } }
+ let_it_be(:guest) { create(:user).tap { |u| project.add_guest(u) } }
+ let_it_be(:anonymous) { create(:user) }
+
+ where(:current_user) do
+ [ref(:developer), ref(:reporter), ref(:guest), ref(:anonymous)]
+ end
+
+ with_them do
+ it_behaves_like 'an erroneous reponse'
+
+ it { subject.tap { expect_graphql_errors_to_include(/you don't have permission to perform this action/) } }
+ end
+ end
+
+ context "when feature flag ':packages_protected_packages' disabled" do
+ before do
+ stub_feature_flags(packages_protected_packages: false)
+ end
+
+ it_behaves_like 'an erroneous reponse'
+
+ it { subject.tap { expect_graphql_errors_to_include(/'packages_protected_packages' feature flag is disabled/) } }
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/release_asset_links/update_spec.rb b/spec/requests/api/graphql/mutations/release_asset_links/update_spec.rb
index 45028cba3ae..fdd4de865ad 100644
--- a/spec/requests/api/graphql/mutations/release_asset_links/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/release_asset_links/update_spec.rb
@@ -10,12 +10,14 @@ RSpec.describe 'Updating an existing release asset link', feature_category: :rel
let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
let_it_be(:release_link) do
- create(:release_link,
- release: release,
- name: 'link name',
- url: 'https://example.com/url',
- filepath: '/permanent/path',
- link_type: 'package')
+ create(
+ :release_link,
+ release: release,
+ name: 'link name',
+ url: 'https://example.com/url',
+ filepath: '/permanent/path',
+ link_type: 'package'
+ )
end
let(:current_user) { developer }
diff --git a/spec/requests/api/graphql/mutations/snippets/create_spec.rb b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
index a6d727ae6d3..7094cb807b2 100644
--- a/spec/requests/api/graphql/mutations/snippets/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe 'Creating a Snippet', feature_category: :source_code_management d
let(:current_user) { nil }
it_behaves_like 'a mutation that returns top-level errors',
- errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
it 'does not create the Snippet' do
expect do
@@ -122,7 +122,7 @@ RSpec.describe 'Creating a Snippet', feature_category: :source_code_management d
let(:project_path) { 'foobar' }
it_behaves_like 'a mutation that returns top-level errors',
- errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
context 'when the feature is disabled' do
@@ -131,7 +131,7 @@ RSpec.describe 'Creating a Snippet', feature_category: :source_code_management d
end
it_behaves_like 'a mutation that returns top-level errors',
- errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
it_behaves_like 'snippet edit usage data counters'
@@ -169,8 +169,8 @@ RSpec.describe 'Creating a Snippet', feature_category: :source_code_management d
end
it_behaves_like 'expected files argument', nil, nil
- it_behaves_like 'expected files argument', %w(foo bar), %w(foo bar)
- it_behaves_like 'expected files argument', 'foo', %w(foo)
+ it_behaves_like 'expected files argument', %w[foo bar], %w[foo bar]
+ it_behaves_like 'expected files argument', 'foo', %w[foo]
context 'when files has an invalid value' do
let(:uploaded_files) { [1] }
diff --git a/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb b/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
index c3f818b6627..7b0de7a9fba 100644
--- a/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe 'Destroying a Snippet', feature_category: :source_code_management
let(:current_user) { create(:user) }
it_behaves_like 'a mutation that returns top-level errors',
- errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
it 'does not destroy the Snippet' do
expect do
@@ -53,7 +53,7 @@ RSpec.describe 'Destroying a Snippet', feature_category: :source_code_management
let!(:snippet_gid) { project.to_gid.to_s }
it 'returns an error' do
- err_message = %["#{snippet_gid}" does not represent an instance of Snippet]
+ err_message = %("#{snippet_gid}" does not represent an instance of Snippet)
post_graphql_mutation(mutation, current_user: current_user)
diff --git a/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb b/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
index 9a8c027da8a..6fd41437ce4 100644
--- a/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe 'Mark snippet as spam', feature_category: :source_code_management
let(:current_user) { other_user }
it_behaves_like 'a mutation that returns top-level errors',
- errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
it_behaves_like 'does not mark the snippet as spam'
end
diff --git a/spec/requests/api/graphql/mutations/snippets/update_spec.rb b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
index 78df78cb2a0..0bc475c7105 100644
--- a/spec/requests/api/graphql/mutations/snippets/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe 'Updating a Snippet', feature_category: :source_code_management d
let(:current_user) { create(:user) }
it_behaves_like 'a mutation that returns top-level errors',
- errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
it 'does not update the Snippet' do
expect do
@@ -118,13 +118,15 @@ RSpec.describe 'Updating a Snippet', feature_category: :source_code_management d
describe 'PersonalSnippet' do
let(:snippet) do
- create(:personal_snippet,
- :private,
- :repository,
- file_name: original_file_name,
- title: original_title,
- content: original_content,
- description: original_description)
+ create(
+ :personal_snippet,
+ :private,
+ :repository,
+ file_name: original_file_name,
+ title: original_title,
+ content: original_content,
+ description: original_description
+ )
end
it_behaves_like 'graphql update actions'
@@ -139,15 +141,17 @@ RSpec.describe 'Updating a Snippet', feature_category: :source_code_management d
let_it_be(:project) { create(:project, :private) }
let(:snippet) do
- create(:project_snippet,
- :private,
- :repository,
- project: project,
- author: create(:user),
- file_name: original_file_name,
- title: original_title,
- content: original_content,
- description: original_description)
+ create(
+ :project_snippet,
+ :private,
+ :repository,
+ project: project,
+ author: create(:user),
+ file_name: original_file_name,
+ title: original_title,
+ content: original_content,
+ description: original_description
+ )
end
context 'when the author is not a member of the project' do
diff --git a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
index c611c6ee2a1..429aa06d9f1 100644
--- a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
@@ -21,12 +21,14 @@ RSpec.describe 'Marking all todos done', feature_category: :team_planning do
let(:input) { {} }
let(:mutation) do
- graphql_mutation(:todos_mark_all_done, input,
- <<-QL.strip_heredoc
- clientMutationId
- todos { id }
- errors
- QL
+ graphql_mutation(
+ :todos_mark_all_done,
+ input,
+ <<-QL.strip_heredoc
+ clientMutationId
+ todos { id }
+ errors
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
index 60700d8024c..c09f89ef567 100644
--- a/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
@@ -19,15 +19,17 @@ RSpec.describe 'Marking todos done', feature_category: :team_planning do
let(:input) { { id: todo1.to_global_id.to_s } }
let(:mutation) do
- graphql_mutation(:todo_mark_done, input,
- <<-QL.strip_heredoc
- clientMutationId
- errors
- todo {
- id
- state
- }
- QL
+ graphql_mutation(
+ :todo_mark_done,
+ input,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ todo {
+ id
+ state
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
index 9daa243cf8e..4bbfc7b2f1d 100644
--- a/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
@@ -20,15 +20,17 @@ RSpec.describe 'Restoring many Todos', feature_category: :team_planning do
let(:input) { { ids: input_ids } }
let(:mutation) do
- graphql_mutation(:todo_restore_many, input,
- <<-QL.strip_heredoc
- clientMutationId
- errors
- todos {
- id
- state
- }
- QL
+ graphql_mutation(
+ :todo_restore_many,
+ input,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ todos {
+ id
+ state
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/mutations/todos/restore_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
index 868298763ec..1ebd04432be 100644
--- a/spec/requests/api/graphql/mutations/todos/restore_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
@@ -19,15 +19,17 @@ RSpec.describe 'Restoring Todos', feature_category: :team_planning do
let(:input) { { id: todo1.to_global_id.to_s } }
let(:mutation) do
- graphql_mutation(:todo_restore, input,
- <<-QL.strip_heredoc
- clientMutationId
- errors
- todo {
- id
- state
- }
- QL
+ graphql_mutation(
+ :todo_restore,
+ input,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ todo {
+ id
+ state
+ }
+ QL
)
end
diff --git a/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb b/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb
index 7c48f324d24..c8819f1e38f 100644
--- a/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb
+++ b/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb
@@ -6,8 +6,15 @@ RSpec.describe 'rendering namespace statistics', feature_category: :metrics do
include GraphqlHelpers
let(:namespace) { user.namespace }
- let!(:statistics) { create(:namespace_root_storage_statistics, namespace: namespace, packages_size: 5.gigabytes, uploads_size: 3.gigabytes) }
let(:user) { create(:user) }
+ let!(:statistics) do
+ create(
+ :namespace_root_storage_statistics,
+ namespace: namespace,
+ packages_size: 5.gigabytes,
+ uploads_size: 3.gigabytes
+ )
+ end
let(:query) do
graphql_query_for(
diff --git a/spec/requests/api/graphql/organizations/organization_query_spec.rb b/spec/requests/api/graphql/organizations/organization_query_spec.rb
index d02158382eb..c243e0613ad 100644
--- a/spec/requests/api/graphql/organizations/organization_query_spec.rb
+++ b/spec/requests/api/graphql/organizations/organization_query_spec.rb
@@ -79,7 +79,10 @@ RSpec.describe 'getting organization information', feature_category: :cell do
<<~FIELDS
organizationUsers {
nodes {
- badges
+ badges {
+ text
+ variant
+ }
id
user {
id
@@ -94,7 +97,7 @@ RSpec.describe 'getting organization information', feature_category: :cell do
organization_user_node = graphql_data_at(:organization, :organizationUsers, :nodes).first
expected_attributes = {
- "badges" => ["It's you!"],
+ "badges" => [{ "text" => "It's you!", "variant" => 'muted' }],
"id" => organization_user.to_global_id.to_s,
"user" => { "id" => user.to_global_id.to_s }
}
diff --git a/spec/requests/api/graphql/project/base_service_spec.rb b/spec/requests/api/graphql/project/base_service_spec.rb
index b27cddea07b..646ff8dd8a8 100644
--- a/spec/requests/api/graphql/project/base_service_spec.rb
+++ b/spec/requests/api/graphql/project/base_service_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe 'query Jira service', feature_category: :system_access do
it 'retuns list of jira imports' do
service_types = services.map { |s| s['type'] }
- expect(service_types).to match_array(%w(BugzillaService JiraService RedmineService))
+ expect(service_types).to match_array(%w[BugzillaService JiraService RedmineService])
end
end
end
diff --git a/spec/requests/api/graphql/project/container_repositories_spec.rb b/spec/requests/api/graphql/project/container_repositories_spec.rb
index 9a40a972256..c86d3bdd14c 100644
--- a/spec/requests/api/graphql/project/container_repositories_spec.rb
+++ b/spec/requests/api/graphql/project/container_repositories_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe 'getting container repositories in a project', feature_category:
before do
stub_container_registry_config(enabled: true)
container_repositories.each do |repository|
- stub_container_registry_tags(repository: repository.path, tags: %w(tag1 tag2 tag3), with_manifest: false)
+ stub_container_registry_tags(repository: repository.path, tags: %w[tag1 tag2 tag3], with_manifest: false)
end
end
@@ -141,7 +141,7 @@ RSpec.describe 'getting container repositories in a project', feature_category:
end
before do
- stub_container_registry_tags(repository: container_repository.path, tags: %w(tag4 tag5 tag6), with_manifest: false)
+ stub_container_registry_tags(repository: container_repository.path, tags: %w[tag4 tag5 tag6], with_manifest: false)
end
it 'returns the searched container repository' do
@@ -175,11 +175,11 @@ RSpec.describe 'getting container repositories in a project', feature_category:
let_it_be(:container_repository5) { create(:container_repository, name: 'e', project: sort_project) }
before do
- stub_container_registry_tags(repository: container_repository1.path, tags: %w(tag1 tag1 tag3), with_manifest: false)
- stub_container_registry_tags(repository: container_repository2.path, tags: %w(tag4 tag5 tag6), with_manifest: false)
- stub_container_registry_tags(repository: container_repository3.path, tags: %w(tag7 tag8), with_manifest: false)
- stub_container_registry_tags(repository: container_repository4.path, tags: %w(tag9), with_manifest: false)
- stub_container_registry_tags(repository: container_repository5.path, tags: %w(tag10 tag11), with_manifest: false)
+ stub_container_registry_tags(repository: container_repository1.path, tags: %w[tag1 tag1 tag3], with_manifest: false)
+ stub_container_registry_tags(repository: container_repository2.path, tags: %w[tag4 tag5 tag6], with_manifest: false)
+ stub_container_registry_tags(repository: container_repository3.path, tags: %w[tag7 tag8], with_manifest: false)
+ stub_container_registry_tags(repository: container_repository4.path, tags: %w[tag9], with_manifest: false)
+ stub_container_registry_tags(repository: container_repository5.path, tags: %w[tag10 tag11], with_manifest: false)
end
def pagination_query(params)
diff --git a/spec/requests/api/graphql/project/data_transfer_spec.rb b/spec/requests/api/graphql/project/data_transfer_spec.rb
index aafa8d65eb9..79b2b10419b 100644
--- a/spec/requests/api/graphql/project/data_transfer_spec.rb
+++ b/spec/requests/api/graphql/project/data_transfer_spec.rb
@@ -68,45 +68,21 @@ RSpec.describe 'project data transfers', feature_category: :source_code_manageme
context 'when user has enough permissions' do
before do
project.add_owner(current_user)
+ subject
end
- context 'when data_transfer_monitoring_mock_data is NOT enabled' do
- before do
- stub_feature_flags(data_transfer_monitoring_mock_data: false)
- subject
- end
-
- it 'returns real results' do
- expect(response).to have_gitlab_http_status(:ok)
+ it 'returns real results' do
+ expect(response).to have_gitlab_http_status(:ok)
- expect(egress_data.count).to eq(2)
+ expect(egress_data.count).to eq(2)
- expect(egress_data.first.keys).to match_array(
- %w[date totalEgress repositoryEgress artifactsEgress packagesEgress registryEgress]
- )
+ expect(egress_data.first.keys).to match_array(
+ %w[date totalEgress repositoryEgress artifactsEgress packagesEgress registryEgress]
+ )
- expect(egress_data.pluck('repositoryEgress')).to match_array(%w[1 2])
- end
-
- it_behaves_like 'a working graphql query'
+ expect(egress_data.pluck('repositoryEgress')).to match_array(%w[1 2])
end
- context 'when data_transfer_monitoring_mock_data is enabled' do
- before do
- stub_feature_flags(data_transfer_monitoring_mock_data: true)
- subject
- end
-
- it 'returns mock results' do
- expect(response).to have_gitlab_http_status(:ok)
-
- expect(egress_data.count).to eq(12)
- expect(egress_data.first.keys).to match_array(
- %w[date totalEgress repositoryEgress artifactsEgress packagesEgress registryEgress]
- )
- end
-
- it_behaves_like 'a working graphql query'
- end
+ it_behaves_like 'a working graphql query'
end
end
diff --git a/spec/requests/api/graphql/project/environments_spec.rb b/spec/requests/api/graphql/project/environments_spec.rb
index 3a863bd3d77..94ce6b797cd 100644
--- a/spec/requests/api/graphql/project/environments_spec.rb
+++ b/spec/requests/api/graphql/project/environments_spec.rb
@@ -150,7 +150,7 @@ RSpec.describe 'Project Environments query', feature_category: :continuous_deliv
end
describe 'last deployments of environments' do
- ::Deployment.statuses.each do |status, _| # rubocop:disable RSpec/UselessDynamicDefinition
+ ::Deployment.statuses.each_key do |status| # rubocop:disable RSpec/UselessDynamicDefinition -- `status` used in `let_it_be`
let_it_be(:"production_#{status}_deployment") do
create(:deployment, status.to_sym, environment: production, project: project)
end
diff --git a/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb b/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
index 6cbc70022ed..c2910938acf 100644
--- a/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
+++ b/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
@@ -119,7 +119,7 @@ RSpec.describe 'sentry errors requests', feature_category: :error_tracking do
end
let(:error_data) { graphql_data.dig('project', 'sentryErrors', 'errors', 'nodes') }
- let(:pagination_data) { graphql_data.dig('project', 'sentryErrors', 'errors', 'pageInfo') }
+ let(:pagination_data) { graphql_data.dig('project', 'sentryErrors', 'errors', 'pageInfo') }
it_behaves_like 'a working graphql query' do
before do
diff --git a/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb b/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb
index a15e4c1e792..bc56df5b6ff 100644
--- a/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb
+++ b/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb
@@ -73,7 +73,7 @@ RSpec.describe 'Getting versions related to an issue', feature_category: :design
post_graphql(query, current_user: current_user)
keys = graphql_data.dig(*edges_path).first['node'].keys
- expect(keys).to match_array(%w(id sha createdAt author))
+ expect(keys).to match_array(%w[id sha createdAt author])
end
end
diff --git a/spec/requests/api/graphql/project/issue_spec.rb b/spec/requests/api/graphql/project/issue_spec.rb
index bc90f9e89e6..8d21a9f0394 100644
--- a/spec/requests/api/graphql/project/issue_spec.rb
+++ b/spec/requests/api/graphql/project/issue_spec.rb
@@ -108,7 +108,7 @@ RSpec.describe 'Query.project(fullPath).issue(iid)', feature_category: :team_pla
let(:object_field_name) { :design }
let(:no_argument_error) do
- custom_graphql_error(path, a_string_matching(%r/id or filename/))
+ custom_graphql_error(path, a_string_matching(%r{id or filename}))
end
let_it_be(:object_on_other_issue) { create(:design, issue: issue_b) }
@@ -134,7 +134,7 @@ RSpec.describe 'Query.project(fullPath).issue(iid)', feature_category: :team_pla
it 'raises an error' do
post_query
- expect(graphql_errors).to include(custom_graphql_error(path, a_string_matching(%r/id or sha/)))
+ expect(graphql_errors).to include(custom_graphql_error(path, a_string_matching(%r{id or sha})))
end
end
diff --git a/spec/requests/api/graphql/project/jira_import_spec.rb b/spec/requests/api/graphql/project/jira_import_spec.rb
index 25cea0238ef..a1d340b3500 100644
--- a/spec/requests/api/graphql/project/jira_import_spec.rb
+++ b/spec/requests/api/graphql/project/jira_import_spec.rb
@@ -96,7 +96,7 @@ RSpec.describe 'query Jira import data', feature_category: :importers do
total_issue_count = jira_imports.map { |ji| ji.dig('totalIssueCount') }
expect(jira_imports.size).to eq 2
- expect(jira_proket_keys).to eq %w(BB AA)
+ expect(jira_proket_keys).to eq %w[BB AA]
expect(usernames).to eq [current_user.username, current_user.username]
expect(imported_issues_count).to eq [2, 2]
expect(failed_issues_count).to eq [1, 2]
diff --git a/spec/requests/api/graphql/project/jira_projects_spec.rb b/spec/requests/api/graphql/project/jira_projects_spec.rb
index 3cd689deda5..2859e8a7c99 100644
--- a/spec/requests/api/graphql/project/jira_projects_spec.rb
+++ b/spec/requests/api/graphql/project/jira_projects_spec.rb
@@ -55,8 +55,8 @@ RSpec.describe 'query Jira projects', feature_category: :integrations do
project_ids = jira_projects.map { |jp| jp['projectId'] }
expect(jira_projects.size).to eq(2)
- expect(project_keys).to eq(%w(EX ABC))
- expect(project_names).to eq(%w(Example Alphabetical))
+ expect(project_keys).to eq(%w[EX ABC])
+ expect(project_names).to eq(%w[Example Alphabetical])
expect(project_ids).to eq([10000, 10001])
end
@@ -69,8 +69,8 @@ RSpec.describe 'query Jira projects', feature_category: :integrations do
project_ids = jira_projects.map { |jp| jp['projectId'] }
expect(jira_projects.size).to eq(1)
- expect(project_keys).to eq(%w(EX))
- expect(project_names).to eq(%w(Example))
+ expect(project_keys).to eq(%w[EX])
+ expect(project_names).to eq(%w[Example])
expect(project_ids).to eq([10000])
end
end
diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb
index c274199e65b..23be9fa5286 100644
--- a/spec/requests/api/graphql/project/merge_request_spec.rb
+++ b/spec/requests/api/graphql/project/merge_request_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe 'getting merge request information nested in a project', feature_
it_behaves_like 'a working graphql query' do
# we exclude Project.pipeline because it needs arguments,
- # codequalityReportsComparer because no pipeline exist yet
+ # codequalityReportsComparer because it is behind a feature flag
# and runners because the user is not an admin and therefore has no access
let(:excluded) { %w[jobs pipeline runners codequalityReportsComparer] }
let(:mr_fields) { all_graphql_fields_for('MergeRequest', excluded: excluded) }
diff --git a/spec/requests/api/graphql/project/merge_requests_spec.rb b/spec/requests/api/graphql/project/merge_requests_spec.rb
index 543de43bcf3..176a02df0be 100644
--- a/spec/requests/api/graphql/project/merge_requests_spec.rb
+++ b/spec/requests/api/graphql/project/merge_requests_spec.rb
@@ -48,8 +48,11 @@ RSpec.describe 'getting merge request listings nested in a project', feature_cat
end
it_behaves_like 'a working graphql query' do
+ # we exclude codequalityReportsComparer because it is behind feature flag
+ let(:excluded) { %w[codequalityReportsComparer] }
+
let(:query) do
- query_merge_requests(all_graphql_fields_for('MergeRequest', max_depth: 2))
+ query_merge_requests(all_graphql_fields_for('MergeRequest', max_depth: 2, excluded: excluded))
end
before do
diff --git a/spec/requests/api/graphql/project/release_spec.rb b/spec/requests/api/graphql/project/release_spec.rb
index 8d4a39d6b30..8206d076d2e 100644
--- a/spec/requests/api/graphql/project/release_spec.rb
+++ b/spec/requests/api/graphql/project/release_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe 'Query.project(fullPath).release(tagName)', feature_category: :re
let(:path) { path_prefix }
let(:release_fields) do
- %{
+ %(
tagName
tagPath
description
@@ -45,7 +45,7 @@ RSpec.describe 'Query.project(fullPath).release(tagName)', feature_category: :re
createdAt
releasedAt
upcomingRelease
- }
+ )
end
before do
@@ -176,14 +176,14 @@ RSpec.describe 'Query.project(fullPath).release(tagName)', feature_category: :re
let(:path) { path_prefix + %w[links] }
let(:release_fields) do
- query_graphql_field(:links, nil, %{
+ query_graphql_field(:links, nil, %(
selfUrl
openedMergeRequestsUrl
mergedMergeRequestsUrl
closedMergeRequestsUrl
openedIssuesUrl
closedIssuesUrl
- })
+ ))
end
it 'finds all release links' do
@@ -225,7 +225,7 @@ RSpec.describe 'Query.project(fullPath).release(tagName)', feature_category: :re
let(:path) { path_prefix }
let(:release_fields) do
- %{
+ %(
tagName
tagPath
description
@@ -234,7 +234,7 @@ RSpec.describe 'Query.project(fullPath).release(tagName)', feature_category: :re
createdAt
releasedAt
upcomingRelease
- }
+ )
end
before do
@@ -358,14 +358,14 @@ RSpec.describe 'Query.project(fullPath).release(tagName)', feature_category: :re
let(:path) { path_prefix + %w[links] }
let(:release_fields) do
- query_graphql_field(:links, nil, %{
+ query_graphql_field(:links, nil, %(
selfUrl
openedMergeRequestsUrl
mergedMergeRequestsUrl
closedMergeRequestsUrl
openedIssuesUrl
closedIssuesUrl
- })
+ ))
end
it 'finds only selfUrl' do
@@ -547,10 +547,10 @@ RSpec.describe 'Query.project(fullPath).release(tagName)', feature_category: :re
let(:current_user) { developer }
let(:release_fields) do
- %{
+ %(
releasedAt
upcomingRelease
- }
+ )
end
before do
@@ -588,13 +588,13 @@ RSpec.describe 'Query.project(fullPath).release(tagName)', feature_category: :re
let_it_be_with_reload(:release) { create(:release, project: project) }
let(:release_fields) do
- %{
+ %(
milestones {
nodes {
title
}
}
- }
+ )
end
let(:actual_milestone_title_order) do
diff --git a/spec/requests/api/graphql/project/terraform/state_spec.rb b/spec/requests/api/graphql/project/terraform/state_spec.rb
index 1889e7a1064..28f3868c7cf 100644
--- a/spec/requests/api/graphql/project/terraform/state_spec.rb
+++ b/spec/requests/api/graphql/project/terraform/state_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe 'query a single terraform state', feature_category: :infrastructu
query_graphql_field(
:terraformState,
{ name: terraform_state.name },
- %{
+ %(
id
name
lockedAt
@@ -45,7 +45,7 @@ RSpec.describe 'query a single terraform state', feature_category: :infrastructu
lockedByUser {
id
}
- }
+ )
)
)
end
diff --git a/spec/requests/api/graphql/project/terraform/states_spec.rb b/spec/requests/api/graphql/project/terraform/states_spec.rb
index 7a789a5d481..d6cf3a52649 100644
--- a/spec/requests/api/graphql/project/terraform/states_spec.rb
+++ b/spec/requests/api/graphql/project/terraform/states_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe 'query terraform states', feature_category: :infrastructure_as_co
graphql_query_for(
:project,
{ fullPath: project.full_path },
- %{
+ %(
terraformStates {
count
nodes {
@@ -45,7 +45,7 @@ RSpec.describe 'query terraform states', feature_category: :infrastructure_as_co
}
}
}
- }
+ )
)
end
diff --git a/spec/requests/api/graphql/project/work_items_spec.rb b/spec/requests/api/graphql/project/work_items_spec.rb
index d5d3d6c578f..d0f80bcfebe 100644
--- a/spec/requests/api/graphql/project/work_items_spec.rb
+++ b/spec/requests/api/graphql/project/work_items_spec.rb
@@ -350,7 +350,9 @@ RSpec.describe 'getting a work item list for a project', feature_category: :team
end
context 'when fetching work item linked items widget' do
- let_it_be(:related_items) { create_list(:work_item, 3, project: project, milestone: milestone1) }
+ let_it_be(:other_project) { create(:project, :repository, :public, group: group) }
+ let_it_be(:other_milestone) { create(:milestone, project: other_project) }
+ let_it_be(:related_items) { create_list(:work_item, 3, project: other_project, milestone: other_milestone) }
let(:fields) do
<<~GRAPHQL
@@ -384,21 +386,24 @@ RSpec.describe 'getting a work item list for a project', feature_category: :team
before do
create(:work_item_link, source: item1, target: related_items[0], link_type: 'relates_to')
+ create(:work_item_link, source: item2, target: related_items[0], link_type: 'relates_to')
end
it 'executes limited number of N+1 queries', :use_sql_query_cache do
+ post_graphql(query, current_user: current_user) # warm-up
+
control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
post_graphql(query, current_user: current_user)
end
- create(:work_item_link, source: item1, target: related_items[1], link_type: 'relates_to')
- create(:work_item_link, source: item1, target: related_items[2], link_type: 'relates_to')
+ [item1, item2].each do |item|
+ create(:work_item_link, source: item, target: related_items[1], link_type: 'relates_to')
+ create(:work_item_link, source: item, target: related_items[2], link_type: 'relates_to')
+ end
expect_graphql_errors_to_be_empty
- # TODO: Fix N+1 queries executed for the linked work item widgets
- # https://gitlab.com/gitlab-org/gitlab/-/issues/420605
expect { post_graphql(query, current_user: current_user) }
- .not_to exceed_all_query_limit(control).with_threshold(11)
+ .not_to exceed_all_query_limit(control)
end
end
diff --git a/spec/requests/api/graphql/projects/projects_spec.rb b/spec/requests/api/graphql/projects/projects_spec.rb
new file mode 100644
index 00000000000..84b8c2285f0
--- /dev/null
+++ b/spec/requests/api/graphql/projects/projects_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting a collection of projects', feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:group) { create(:group, name: 'public-group') }
+ let_it_be(:projects) { create_list(:project, 5, :public, group: group) }
+ let_it_be(:other_project) { create(:project, :public, group: group) }
+
+ let(:filters) { {} }
+
+ let(:query) do
+ graphql_query_for(
+ :projects,
+ filters,
+ "nodes {#{all_graphql_fields_for('Project', max_depth: 1, excluded: ['productAnalyticsState'])} }"
+ )
+ end
+
+ before_all do
+ group.add_developer(current_user)
+ end
+
+ context 'when providing full_paths filter' do
+ let(:project_full_paths) { projects.map(&:full_path) }
+ let(:filters) { { full_paths: project_full_paths } }
+
+ let(:single_project_query) do
+ graphql_query_for(
+ :projects,
+ { full_paths: [project_full_paths.first] },
+ "nodes {#{all_graphql_fields_for('Project', max_depth: 1, excluded: ['productAnalyticsState'])} }"
+ )
+ end
+
+ it_behaves_like 'a working graphql query that returns data' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+ end
+
+ it 'avoids N+1 queries', :use_sql_query_cache, :clean_gitlab_redis_cache do
+ post_graphql(single_project_query, current_user: current_user)
+
+ query_count = ActiveRecord::QueryRecorder.new do
+ post_graphql(single_project_query, current_user: current_user)
+ end.count
+
+ # There is an N+1 query for max_member_access_for_user_ids
+ expect do
+ post_graphql(query, current_user: current_user)
+ end.not_to exceed_all_query_limit(query_count + 5)
+ end
+
+ it 'returns the expected projects' do
+ post_graphql(query, current_user: current_user)
+ returned_full_paths = graphql_data_at(:projects, :nodes).pluck('fullPath')
+
+ expect(returned_full_paths).to match_array(project_full_paths)
+ end
+
+ context 'when users provides more than 50 full_paths' do
+ let(:filters) { { full_paths: Array.new(51) { other_project.full_path } } }
+
+ it 'returns an error' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_errors).to contain_exactly(
+ hash_including('message' => _('You cannot provide more than 50 full_paths'))
+ )
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/user_spec.rb b/spec/requests/api/graphql/user_spec.rb
index 41ee233dfc5..22ebc1be964 100644
--- a/spec/requests/api/graphql/user_spec.rb
+++ b/spec/requests/api/graphql/user_spec.rb
@@ -113,4 +113,36 @@ RSpec.describe 'User', feature_category: :user_profile do
end
end
end
+
+ describe 'organizations field' do
+ let_it_be(:organization_user) { create(:organization_user, user: current_user) }
+ let_it_be(:organization) { organization_user.organization }
+ let_it_be(:another_organization) { create(:organization) }
+ let_it_be(:another_user) { create(:user) }
+
+ let(:query) do
+ graphql_query_for(
+ :user,
+ { username: current_user.username.to_s.upcase },
+ 'organizations { nodes { path } }'
+ )
+ end
+
+ context 'with permission' do
+ it 'returns the relevant organization details' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data.dig('user', 'organizations', 'nodes').pluck('path'))
+ .to match_array(organization.path)
+ end
+ end
+
+ context 'without permission' do
+ it 'does not return organization details' do
+ post_graphql(query, current_user: another_user)
+
+ expect(graphql_data.dig('user', 'organizations', 'nodes')).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb
index b8575b25e0a..36a27abd982 100644
--- a/spec/requests/api/graphql/work_item_spec.rb
+++ b/spec/requests/api/graphql/work_item_spec.rb
@@ -619,6 +619,47 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
)
end
+ context 'when inaccessible links are present' do
+ let_it_be(:no_access_item) { create(:work_item, title: "PRIVATE", project: create(:project, :private)) }
+
+ before do
+ create(:work_item_link, source: work_item, target: no_access_item, link_type: 'relates_to')
+ end
+
+ it 'returns only items that the user has access to' do
+ expect(graphql_dig_at(work_item_data, :widgets, "linkedItems", "nodes", "linkId"))
+ .to match_array([link1.to_gid.to_s, link2.to_gid.to_s])
+ end
+ end
+
+ context 'when limiting the number of results' do
+ it_behaves_like 'sorted paginated query' do
+ include_context 'no sort argument'
+
+ let(:first_param) { 1 }
+ let(:all_records) { [link1, link2] }
+ let(:data_path) { ['workItem', 'widgets', "linkedItems", -1] }
+
+ def widget_fields(args)
+ query_graphql_field(
+ :widgets, {}, query_graphql_field(
+ '... on WorkItemWidgetLinkedItems', {}, query_graphql_field(
+ 'linkedItems', args, "#{page_info} nodes { linkId }"
+ )
+ )
+ )
+ end
+
+ def pagination_query(params)
+ graphql_query_for('workItem', { 'id' => global_id }, widget_fields(params))
+ end
+
+ def pagination_results_data(nodes)
+ nodes.map { |item| GlobalID::Locator.locate(item['linkId']) }
+ end
+ end
+ end
+
context 'when filtering by link type' do
let(:work_item_fields) do
<<~GRAPHQL
@@ -664,20 +705,6 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
end
describe 'notes widget' do
- let(:work_item_fields) do
- <<~GRAPHQL
- id
- widgets {
- type
- ... on WorkItemWidgetNotes {
- system: discussions(filter: ONLY_ACTIVITY, first: 10) { nodes { id notes { nodes { id system internal body } } } },
- comments: discussions(filter: ONLY_COMMENTS, first: 10) { nodes { id notes { nodes { id system internal body } } } },
- all_notes: discussions(filter: ALL_NOTES, first: 10) { nodes { id notes { nodes { id system internal body } } } }
- }
- }
- GRAPHQL
- end
-
context 'when fetching award emoji from notes' do
let(:work_item_fields) do
<<~GRAPHQL
@@ -768,6 +795,26 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
expect { post_graphql(query, current_user: developer) }.not_to exceed_query_limit(control).with_threshold(4)
expect_graphql_errors_to_be_empty
end
+
+ context 'when work item is associated with a group' do
+ let_it_be(:group_work_item) { create(:work_item, :group_level, namespace: group) }
+ let_it_be(:group_work_item_note) { create(:note, noteable: group_work_item, author: developer, project: nil) }
+ let(:global_id) { group_work_item.to_gid.to_s }
+
+ before_all do
+ create(:award_emoji, awardable: group_work_item_note, name: 'rocket', user: developer)
+ end
+
+ it 'returns notes for the group work item' do
+ all_widgets = graphql_dig_at(work_item_data, :widgets)
+ notes_widget = all_widgets.find { |x| x['type'] == 'NOTES' }
+ notes = graphql_dig_at(notes_widget['discussions'], :nodes).flat_map { |d| d['notes']['nodes'] }
+
+ expect(notes).to contain_exactly(
+ hash_including('body' => group_work_item_note.note)
+ )
+ end
+ end
end
end