summaryrefslogtreecommitdiff
path: root/spec/graphql
diff options
context:
space:
mode:
Diffstat (limited to 'spec/graphql')
-rw-r--r--spec/graphql/features/authorization_spec.rb3
-rw-r--r--spec/graphql/mutations/boards/issues/issue_move_list_spec.rb90
-rw-r--r--spec/graphql/mutations/boards/lists/create_spec.rb80
-rw-r--r--spec/graphql/mutations/boards/lists/update_spec.rb56
-rw-r--r--spec/graphql/mutations/commits/create_spec.rb2
-rw-r--r--spec/graphql/mutations/design_management/move_spec.rb81
-rw-r--r--spec/graphql/mutations/issues/set_assignees_spec.rb9
-rw-r--r--spec/graphql/mutations/issues/set_subscription_spec.rb10
-rw-r--r--spec/graphql/mutations/issues/update_spec.rb79
-rw-r--r--spec/graphql/mutations/merge_requests/create_spec.rb13
-rw-r--r--spec/graphql/mutations/merge_requests/set_assignees_spec.rb103
-rw-r--r--spec/graphql/mutations/merge_requests/set_subscription_spec.rb42
-rw-r--r--spec/graphql/resolvers/alert_management/alert_resolver_spec.rb16
-rw-r--r--spec/graphql/resolvers/board_list_issues_resolver_spec.rb58
-rw-r--r--spec/graphql/resolvers/board_lists_resolver_spec.rb24
-rw-r--r--spec/graphql/resolvers/ci_configuration/sast_resolver_spec.rb28
-rw-r--r--spec/graphql/resolvers/commit_pipelines_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/group_issues_resolver_spec.rb43
-rw-r--r--spec/graphql/resolvers/group_milestones_resolver_spec.rb123
-rw-r--r--spec/graphql/resolvers/issue_status_counts_resolver_spec.rb64
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb16
-rw-r--r--spec/graphql/resolvers/merge_requests_resolver_spec.rb18
-rw-r--r--spec/graphql/resolvers/milestone_resolver_spec.rb113
-rw-r--r--spec/graphql/resolvers/project_milestones_resolver_spec.rb117
-rw-r--r--spec/graphql/resolvers/project_pipeline_resolver_spec.rb17
-rw-r--r--spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb28
-rw-r--r--spec/graphql/resolvers/todo_resolver_spec.rb14
-rw-r--r--spec/graphql/types/alert_management/alert_type_spec.rb4
-rw-r--r--spec/graphql/types/board_list_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/group_type_spec.rb17
-rw-r--r--spec/graphql/types/ci/job_type_spec.rb16
-rw-r--r--spec/graphql/types/ci/stage_type_spec.rb16
-rw-r--r--spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb11
-rw-r--r--spec/graphql/types/ci_configuration/sast/entity_type_spec.rb11
-rw-r--r--spec/graphql/types/ci_configuration/sast/options_entity_spec.rb11
-rw-r--r--spec/graphql/types/ci_configuration/sast/type_spec.rb11
-rw-r--r--spec/graphql/types/commit_type_spec.rb4
-rw-r--r--spec/graphql/types/countable_connection_type_spec.rb (renamed from spec/graphql/types/issue_connection_type_spec.rb)0
-rw-r--r--spec/graphql/types/design_management/design_at_version_type_spec.rb1
-rw-r--r--spec/graphql/types/environment_type_spec.rb67
-rw-r--r--spec/graphql/types/group_type_spec.rb2
-rw-r--r--spec/graphql/types/issue_status_count_type_spec.rb17
-rw-r--r--spec/graphql/types/issue_type_enum_spec.rb13
-rw-r--r--spec/graphql/types/issue_type_spec.rb12
-rw-r--r--spec/graphql/types/merge_request_type_spec.rb4
-rw-r--r--spec/graphql/types/project_type_spec.rb106
-rw-r--r--spec/graphql/types/prometheus_alert_type_spec.rb17
-rw-r--r--spec/graphql/types/query_type_spec.rb1
-rw-r--r--spec/graphql/types/snippet_type_spec.rb2
-rw-r--r--spec/graphql/types/snippets/blob_action_enum_spec.rb (renamed from spec/graphql/types/snippets/file_input_action_enum_spec.rb)4
-rw-r--r--spec/graphql/types/snippets/blob_action_input_type_spec.rb (renamed from spec/graphql/types/snippets/file_input_type_spec.rb)8
-rw-r--r--spec/graphql/types/snippets/blob_viewer_type_spec.rb4
-rw-r--r--spec/graphql/types/time_type_spec.rb10
-rw-r--r--spec/graphql/types/tree/blob_type_spec.rb2
-rw-r--r--spec/graphql/types/tree/tree_entry_type_spec.rb2
-rw-r--r--spec/graphql/types/user_status_type_spec.rb17
-rw-r--r--spec/graphql/types/user_type_spec.rb3
57 files changed, 1180 insertions, 464 deletions
diff --git a/spec/graphql/features/authorization_spec.rb b/spec/graphql/features/authorization_spec.rb
index 6e5a8b9f4be..e40c44925e2 100644
--- a/spec/graphql/features/authorization_spec.rb
+++ b/spec/graphql/features/authorization_spec.rb
@@ -257,6 +257,7 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
type.field :id, GraphQL::ID_TYPE, null: false
end
end
+
let(:project_type) do |type|
type_factory do |type|
type.graphql_name 'FakeProjectType'
@@ -264,11 +265,13 @@ RSpec.describe 'Gitlab::Graphql::Authorization' do
resolve: -> (_, _, _) { Issue.where(project: [visible_project, other_project]).order(id: :asc) }
end
end
+
let(:query_type) do
query_factory do |query|
query.field :test_project, project_type, null: false, resolve: -> (_, _, _) { visible_project }
end
end
+
let(:query_string) do
<<~QRY
{ testProject { testIssues(first: 3) { edges { node { id } } } } }
diff --git a/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb b/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb
new file mode 100644
index 00000000000..71c43ed826c
--- /dev/null
+++ b/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Boards::Issues::IssueMoveList do
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:board) { create(:board, group: group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:guest) { create(:user) }
+ let_it_be(:development) { create(:label, project: project, name: 'Development') }
+ let_it_be(:testing) { create(:label, project: project, name: 'Testing') }
+ let_it_be(:list1) { create(:list, board: board, label: development, position: 0) }
+ let_it_be(:list2) { create(:list, board: board, label: testing, position: 1) }
+ let_it_be(:issue1) { create(:labeled_issue, project: project, labels: [development]) }
+ let_it_be(:existing_issue1) { create(:labeled_issue, project: project, labels: [testing], relative_position: 10) }
+ let_it_be(:existing_issue2) { create(:labeled_issue, project: project, labels: [testing], relative_position: 50) }
+
+ let(:current_user) { user }
+ let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
+ let(:params) { { board: board, project_path: project.full_path, iid: issue1.iid } }
+ let(:move_params) do
+ {
+ from_list_id: list1.id,
+ to_list_id: list2.id,
+ move_before_id: existing_issue2.id,
+ move_after_id: existing_issue1.id
+ }
+ end
+
+ before_all do
+ group.add_maintainer(user)
+ group.add_guest(guest)
+ end
+
+ subject do
+ mutation.resolve(params.merge(move_params))
+ end
+
+ describe '#ready?' do
+ it 'raises an error if required arguments are missing' do
+ expect { mutation.ready?(params) }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError, "At least one of the arguments " \
+ "fromListId, toListId, afterId or beforeId is required")
+ end
+
+ it 'raises an error if only one of fromListId and toListId is present' do
+ expect { mutation.ready?(params.merge(from_list_id: list1.id)) }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError,
+ 'Both fromListId and toListId must be present'
+ )
+ end
+ end
+
+ describe '#resolve' do
+ context 'when user have access to resources' do
+ it 'moves and repositions issue' do
+ subject
+
+ expect(issue1.reload.labels).to eq([testing])
+ expect(issue1.relative_position).to be < existing_issue2.relative_position
+ expect(issue1.relative_position).to be > existing_issue1.relative_position
+ end
+ end
+
+ context 'when user have no access to resources' do
+ shared_examples 'raises a resource not available error' do
+ it { expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) }
+ end
+
+ context 'when user cannot update issue' do
+ let(:current_user) { guest }
+
+ it_behaves_like 'raises a resource not available error'
+ end
+
+ context 'when user cannot access board' do
+ let(:board) { create(:board, group: create(:group, :private)) }
+
+ it_behaves_like 'raises a resource not available error'
+ end
+
+ context 'when passing board_id as nil' do
+ let(:board) { nil }
+
+ it_behaves_like 'raises a resource not available error'
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/boards/lists/create_spec.rb b/spec/graphql/mutations/boards/lists/create_spec.rb
new file mode 100644
index 00000000000..1a881ac81e8
--- /dev/null
+++ b/spec/graphql/mutations/boards/lists/create_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Boards::Lists::Create do
+ include GraphqlHelpers
+
+ let_it_be(:group) { create(:group, :private) }
+ let_it_be(:board) { create(:board, group: group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:guest) { create(:user) }
+
+ let(:current_user) { user }
+ let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
+ let(:list_create_params) { {} }
+
+ before_all do
+ group.add_reporter(user)
+ group.add_guest(guest)
+ end
+
+ subject { mutation.resolve(board_id: board.to_global_id.to_s, **list_create_params) }
+
+ describe '#ready?' do
+ it 'raises an error if required arguments are missing' do
+ expect { mutation.ready?({ board_id: 'some id' }) }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError,
+ 'one and only one of backlog or labelId is required')
+ end
+
+ it 'raises an error if too many required arguments are specified' do
+ expect { mutation.ready?({ board_id: 'some id', backlog: true, label_id: 'some label' }) }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError,
+ 'one and only one of backlog or labelId is required')
+ end
+ end
+
+ describe '#resolve' do
+ context 'with proper permissions' do
+ describe 'backlog list' do
+ let(:list_create_params) { { backlog: true } }
+
+ it 'creates one and only one backlog' do
+ expect { subject }.to change { board.lists.backlog.count }.from(0).to(1)
+ expect(board.lists.backlog.first.list_type).to eq 'backlog'
+
+ backlog_id = board.lists.backlog.first.id
+
+ expect { subject }.not_to change { board.lists.backlog.count }
+ expect(board.lists.backlog.last.id).to eq backlog_id
+ end
+ end
+
+ describe 'label list' do
+ let_it_be(:dev_label) do
+ create(:group_label, title: 'Development', color: '#FFAABB', group: group)
+ end
+
+ let(:list_create_params) { { label_id: dev_label.to_global_id.to_s } }
+
+ it 'creates a new issue board list for labels' do
+ expect { subject }.to change { board.lists.count }.from(1).to(2)
+
+ new_list = subject[:list]
+
+ expect(new_list.title).to eq dev_label.title
+ expect(new_list.position).to eq 0
+ end
+ end
+ end
+
+ context 'without proper permissions' do
+ let(:current_user) { guest }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/boards/lists/update_spec.rb b/spec/graphql/mutations/boards/lists/update_spec.rb
new file mode 100644
index 00000000000..d5d8a2af6bf
--- /dev/null
+++ b/spec/graphql/mutations/boards/lists/update_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Boards::Lists::Update do
+ let_it_be(:group) { create(:group, :private) }
+ let_it_be(:board) { create(:board, group: group) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:guest) { create(:user) }
+ let_it_be(:list) { create(:list, board: board, position: 0) }
+ let_it_be(:list2) { create(:list, board: board) }
+ let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
+ let(:list_update_params) { { position: 1, collapsed: true } }
+
+ before_all do
+ group.add_reporter(reporter)
+ group.add_guest(guest)
+ list.update_preferences_for(reporter, collapsed: false)
+ end
+
+ subject { mutation.resolve(list: list, **list_update_params) }
+
+ describe '#resolve' do
+ context 'with permission to admin board lists' do
+ let(:current_user) { reporter }
+
+ it 'updates the list position and collapsed state as expected' do
+ subject
+
+ reloaded_list = list.reload
+ expect(reloaded_list.position).to eq(1)
+ expect(reloaded_list.collapsed?(current_user)).to eq(true)
+ end
+ end
+
+ context 'with permission to read board lists' do
+ let(:current_user) { guest }
+
+ it 'updates the list collapsed state but not the list position' do
+ subject
+
+ reloaded_list = list.reload
+ expect(reloaded_list.position).to eq(0)
+ expect(reloaded_list.collapsed?(current_user)).to eq(true)
+ end
+ end
+
+ context 'without permission to read board lists' do
+ let(:current_user) { create(:user) }
+
+ it 'raises Resource Not Found error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/commits/create_spec.rb b/spec/graphql/mutations/commits/create_spec.rb
index bb0b8c577b0..fb1baafe7bd 100644
--- a/spec/graphql/mutations/commits/create_spec.rb
+++ b/spec/graphql/mutations/commits/create_spec.rb
@@ -147,7 +147,7 @@ RSpec.describe Mutations::Commits::Create do
it 'returns errors' do
expect(mutated_commit).to be_nil
- expect(subject[:errors]).to eq(['3:UserCommitFiles: empty CommitMessage'])
+ expect(subject[:errors].to_s).to match(/3:UserCommitFiles: empty CommitMessage/)
end
end
diff --git a/spec/graphql/mutations/design_management/move_spec.rb b/spec/graphql/mutations/design_management/move_spec.rb
new file mode 100644
index 00000000000..7519347d07c
--- /dev/null
+++ b/spec/graphql/mutations/design_management/move_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::DesignManagement::Move do
+ include DesignManagementTestHelpers
+
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:designs) { create_list(:design, 3, issue: issue) }
+ let_it_be(:developer) { create(:user, developer_projects: [issue.project]) }
+
+ let(:user) { developer }
+
+ let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
+
+ let(:current_design) { designs.first }
+ let(:previous_design) { designs.second }
+ let(:next_design) { designs.third }
+
+ before do
+ enable_design_management
+ end
+
+ describe "#resolve" do
+ subject(:resolve) do
+ args = {
+ current_design: current_design.to_global_id,
+ previous_design: previous_design&.to_global_id,
+ next_design: next_design&.to_global_id
+ }.compact
+
+ mutation.resolve(args)
+ end
+
+ shared_examples "resource not available" do
+ it "raises an error" do
+ expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when the feature is not available' do
+ before do
+ enable_design_management(false)
+ end
+
+ it_behaves_like 'resource not available'
+ end
+
+ %i[current_design previous_design next_design].each do |binding|
+ context "When #{binding} cannot be found" do
+ let(binding) { build_stubbed(:design) }
+
+ it_behaves_like 'resource not available'
+ end
+ end
+
+ context 'the service runs' do
+ before do
+ expect_next_instance_of(::DesignManagement::MoveDesignsService) do |service|
+ expect(service).to receive(:execute).and_return(service_result)
+ end
+ end
+
+ context 'raising an error' do
+ let(:service_result) { ServiceResponse.error(message: 'bang!') }
+
+ it 'reports the service-level error' do
+ expect(resolve).to include(errors: ['bang!'], design_collection: eq(issue.design_collection))
+ end
+ end
+
+ context 'successfully' do
+ let(:service_result) { ServiceResponse.success }
+
+ it 'reports the service-level error' do
+ expect(resolve).to include(errors: be_empty, design_collection: eq(issue.design_collection))
+ end
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/issues/set_assignees_spec.rb b/spec/graphql/mutations/issues/set_assignees_spec.rb
new file mode 100644
index 00000000000..77ba511b715
--- /dev/null
+++ b/spec/graphql/mutations/issues/set_assignees_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Issues::SetAssignees do
+ it_behaves_like 'an assignable resource' do
+ let_it_be(:resource, reload: true) { create(:issue) }
+ end
+end
diff --git a/spec/graphql/mutations/issues/set_subscription_spec.rb b/spec/graphql/mutations/issues/set_subscription_spec.rb
new file mode 100644
index 00000000000..9e05a136c0b
--- /dev/null
+++ b/spec/graphql/mutations/issues/set_subscription_spec.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Issues::SetSubscription do
+ it_behaves_like 'a subscribeable graphql resource' do
+ let_it_be(:resource) { create(:issue) }
+ let(:permission_name) { :update_issue }
+ end
+end
diff --git a/spec/graphql/mutations/issues/update_spec.rb b/spec/graphql/mutations/issues/update_spec.rb
index 9a847476e2e..15c15afd9b7 100644
--- a/spec/graphql/mutations/issues/update_spec.rb
+++ b/spec/graphql/mutations/issues/update_spec.rb
@@ -3,16 +3,23 @@
require 'spec_helper'
RSpec.describe Mutations::Issues::Update do
- let(:issue) { create(:issue) }
- let(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project_label) { create(:label, project: project) }
+ let_it_be(:issue) { create(:issue, project: project, labels: [project_label]) }
+ let_it_be(:milestone) { create(:milestone, project: project) }
+
let(:expected_attributes) do
{
title: 'new title',
description: 'new description',
confidential: true,
- due_date: Date.tomorrow
+ due_date: Date.tomorrow,
+ discussion_locked: true,
+ milestone_id: milestone.id
}
end
+
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
let(:mutated_issue) { subject[:issue] }
@@ -21,20 +28,22 @@ RSpec.describe Mutations::Issues::Update do
describe '#resolve' do
let(:mutation_params) do
{
- project_path: issue.project.full_path,
+ project_path: project.full_path,
iid: issue.iid
}.merge(expected_attributes)
end
subject { mutation.resolve(mutation_params) }
- it 'raises an error if the resource is not accessible to the user' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ context 'when the user cannot access the issue' do
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
end
context 'when the user can update the issue' do
before do
- issue.project.add_developer(user)
+ project.add_developer(user)
end
it 'updates issue with correct values' do
@@ -50,6 +59,62 @@ RSpec.describe Mutations::Issues::Update do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
+
+ context 'when setting milestone to nil' do
+ let(:expected_attributes) { { milestone_id: nil } }
+
+ it 'changes the milestone corrrectly' do
+ issue.update_column(:milestone_id, milestone.id)
+
+ expect { subject }.to change { issue.reload.milestone }.from(milestone).to(nil)
+ end
+ end
+
+ context 'when changing labels' do
+ let_it_be(:label_1) { create(:label, project: project) }
+ let_it_be(:label_2) { create(:label, project: project) }
+ let_it_be(:external_label) { create(:label, project: create(:project)) }
+
+ it 'adds and removes labels correctly' do
+ mutation_params[:add_label_ids] = [label_1.id, label_2.id]
+ mutation_params[:remove_label_ids] = [project_label.id]
+
+ subject
+
+ expect(issue.reload.labels).to match_array([label_1, label_2])
+ end
+
+ it 'does not add label if label id is nil' do
+ mutation_params[:add_label_ids] = [nil, label_2.id]
+
+ subject
+
+ expect(issue.reload.labels).to match_array([project_label, label_2])
+ end
+
+ it 'does not add label if label is not found' do
+ mutation_params[:add_label_ids] = [external_label.id, label_2.id]
+
+ subject
+
+ expect(issue.reload.labels).to match_array([project_label, label_2])
+ end
+
+ it 'does not modify labels if label is already present' do
+ mutation_params[:add_label_ids] = [project_label.id]
+
+ expect(issue.reload.labels).to match_array([project_label])
+ end
+
+ it 'does not modify labels if label is addded and removed in the same request' do
+ mutation_params[:add_label_ids] = [label_1.id, label_2.id]
+ mutation_params[:remove_label_ids] = [label_1.id]
+
+ subject
+
+ expect(issue.reload.labels).to match_array([project_label, label_2])
+ end
+ end
end
end
end
diff --git a/spec/graphql/mutations/merge_requests/create_spec.rb b/spec/graphql/mutations/merge_requests/create_spec.rb
index ae31790f1f9..ba0ac3cbe66 100644
--- a/spec/graphql/mutations/merge_requests/create_spec.rb
+++ b/spec/graphql/mutations/merge_requests/create_spec.rb
@@ -22,7 +22,8 @@ RSpec.describe Mutations::MergeRequests::Create do
title: title,
source_branch: source_branch,
target_branch: target_branch,
- description: description
+ description: description,
+ labels: labels
)
end
@@ -30,6 +31,7 @@ RSpec.describe Mutations::MergeRequests::Create do
let(:source_branch) { 'feature' }
let(:target_branch) { 'master' }
let(:description) { nil }
+ let(:labels) { nil }
let(:mutated_merge_request) { subject[:merge_request] }
@@ -70,6 +72,15 @@ RSpec.describe Mutations::MergeRequests::Create do
end
end
+ context 'when optional labels field is set' do
+ let(:labels) { %w[label-1 label-2] }
+
+ it 'returns a new merge request with labels' do
+ expect(mutated_merge_request.labels.map(&:title)).to eq(labels)
+ expect(subject[:errors]).to be_empty
+ end
+ end
+
context 'when service cannot create a merge request' do
let(:title) { nil }
diff --git a/spec/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/graphql/mutations/merge_requests/set_assignees_spec.rb
index 0e7abb849c4..4ac40fc09c6 100644
--- a/spec/graphql/mutations/merge_requests/set_assignees_spec.rb
+++ b/spec/graphql/mutations/merge_requests/set_assignees_spec.rb
@@ -3,106 +3,7 @@
require 'spec_helper'
RSpec.describe Mutations::MergeRequests::SetAssignees do
- let(:merge_request) { create(:merge_request) }
- let(:user) { create(:user) }
-
- subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
-
- describe '#resolve' do
- let(:assignee) { create(:user) }
- let(:assignee2) { create(:user) }
- let(:assignee_usernames) { [assignee.username] }
- let(:mutated_merge_request) { subject[:merge_request] }
-
- subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, assignee_usernames: assignee_usernames) }
-
- before do
- merge_request.project.add_developer(assignee)
- merge_request.project.add_developer(assignee2)
- end
-
- it 'raises an error if the resource is not accessible to the user' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
- end
-
- context 'when the user can update the merge request' do
- before do
- merge_request.project.add_developer(user)
- end
-
- it 'replaces the assignee' do
- merge_request.assignees = [assignee2]
- merge_request.save!
-
- expect(mutated_merge_request).to eq(merge_request)
- expect(mutated_merge_request.assignees).to contain_exactly(assignee)
- expect(subject[:errors]).to be_empty
- end
-
- it 'returns errors merge request could not be updated' do
- # Make the merge request invalid
- merge_request.allow_broken = true
- merge_request.update!(source_project: nil)
-
- expect(subject[:errors]).not_to be_empty
- end
-
- context 'when passing an empty assignee list' do
- let(:assignee_usernames) { [] }
-
- before do
- merge_request.assignees = [assignee]
- merge_request.save!
- end
-
- it 'removes all assignees' do
- expect(mutated_merge_request).to eq(merge_request)
- expect(mutated_merge_request.assignees).to eq([])
- expect(subject[:errors]).to be_empty
- end
- end
-
- context 'when passing "append" as true' do
- subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, assignee_usernames: assignee_usernames, operation_mode: Types::MutationOperationModeEnum.enum[:append]) }
-
- before do
- merge_request.assignees = [assignee2]
- merge_request.save!
-
- # In CE, APPEND is a NOOP as you can't have multiple assignees
- # We test multiple assignment in EE specs
- stub_licensed_features(multiple_merge_request_assignees: false)
- end
-
- it 'is a NO-OP in FOSS' do
- expect(mutated_merge_request).to eq(merge_request)
- expect(mutated_merge_request.assignees).to contain_exactly(assignee2)
- expect(subject[:errors]).to be_empty
- end
- end
-
- context 'when passing "remove" as true' do
- before do
- merge_request.assignees = [assignee]
- merge_request.save!
- end
-
- it 'removes named assignee' do
- mutated_merge_request = mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, assignee_usernames: assignee_usernames, operation_mode: Types::MutationOperationModeEnum.enum[:remove])[:merge_request]
-
- expect(mutated_merge_request).to eq(merge_request)
- expect(mutated_merge_request.assignees).to eq([])
- expect(subject[:errors]).to be_empty
- end
-
- it 'does not remove unnamed assignee' do
- mutated_merge_request = mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, assignee_usernames: [assignee2.username], operation_mode: Types::MutationOperationModeEnum.enum[:remove])[:merge_request]
-
- expect(mutated_merge_request).to eq(merge_request)
- expect(mutated_merge_request.assignees).to contain_exactly(assignee)
- expect(subject[:errors]).to be_empty
- end
- end
- end
+ it_behaves_like 'an assignable resource' do
+ let_it_be(:resource, reload: true) { create(:merge_request) }
end
end
diff --git a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
index 20cfed9dd3d..600053637c9 100644
--- a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
+++ b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
@@ -3,44 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::MergeRequests::SetSubscription do
- let(:merge_request) { create(:merge_request) }
- let(:project) { merge_request.project }
- let(:user) { create(:user) }
-
- subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
-
- specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) }
-
- describe '#resolve' do
- let(:subscribe) { true }
- let(:mutated_merge_request) { subject[:merge_request] }
-
- subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, subscribed_state: subscribe) }
-
- it 'raises an error if the resource is not accessible to the user' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
- end
-
- context 'when the user can update the merge request' do
- before do
- merge_request.project.add_developer(user)
- end
-
- it 'returns the merge request as discussion locked' do
- expect(mutated_merge_request).to eq(merge_request)
- expect(mutated_merge_request.subscribed?(user, project)).to eq(true)
- expect(subject[:errors]).to be_empty
- end
-
- context 'when passing subscribe as false' do
- let(:subscribe) { false }
-
- it 'unsubscribes from the discussion' do
- merge_request.subscribe(user, project)
-
- expect(mutated_merge_request.subscribed?(user, project)).to eq(false)
- end
- end
- end
+ it_behaves_like 'a subscribeable graphql resource' do
+ let_it_be(:resource) { create(:merge_request) }
+ let(:permission_name) { :update_merge_request }
end
end
diff --git a/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb b/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
index 0c1ba5aab2c..42830f0024d 100644
--- a/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
+++ b/spec/graphql/resolvers/alert_management/alert_resolver_spec.rb
@@ -7,8 +7,8 @@ RSpec.describe Resolvers::AlertManagement::AlertResolver do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
- let_it_be(:alert_1) { create(:alert_management_alert, :resolved, project: project, ended_at: 1.year.ago, events: 2, severity: :high) }
- let_it_be(:alert_2) { create(:alert_management_alert, :ignored, project: project, events: 1, severity: :critical) }
+ let_it_be(:resolved_alert) { create(:alert_management_alert, :resolved, project: project, ended_at: 1.year.ago, events: 2, severity: :high) }
+ let_it_be(:ignored_alert) { create(:alert_management_alert, :ignored, project: project, events: 1, severity: :critical) }
let_it_be(:alert_other_proj) { create(:alert_management_alert) }
let(:args) { {} }
@@ -24,18 +24,18 @@ RSpec.describe Resolvers::AlertManagement::AlertResolver do
project.add_developer(current_user)
end
- it { is_expected.to contain_exactly(alert_1, alert_2) }
+ it { is_expected.to contain_exactly(resolved_alert, ignored_alert) }
context 'finding by iid' do
- let(:args) { { iid: alert_1.iid } }
+ let(:args) { { iid: resolved_alert.iid } }
- it { is_expected.to contain_exactly(alert_1) }
+ it { is_expected.to contain_exactly(resolved_alert) }
end
context 'finding by status' do
let(:args) { { status: [Types::AlertManagement::StatusEnum.values['IGNORED'].value] } }
- it { is_expected.to contain_exactly(alert_2) }
+ it { is_expected.to contain_exactly(ignored_alert) }
end
describe 'sorting' do
@@ -45,11 +45,11 @@ RSpec.describe Resolvers::AlertManagement::AlertResolver do
let_it_be(:alert_count_3) { create(:alert_management_alert, project: project, events: 3) }
it 'sorts alerts ascending' do
- expect(resolve_alerts(sort: :event_count_asc)).to eq [alert_2, alert_1, alert_count_3, alert_count_6]
+ expect(resolve_alerts(sort: :event_count_asc)).to eq [ignored_alert, resolved_alert, alert_count_3, alert_count_6]
end
it 'sorts alerts descending' do
- expect(resolve_alerts(sort: :event_count_desc)).to eq [alert_count_6, alert_count_3, alert_1, alert_2]
+ expect(resolve_alerts(sort: :event_count_desc)).to eq [alert_count_6, alert_count_3, resolved_alert, ignored_alert]
end
end
end
diff --git a/spec/graphql/resolvers/board_list_issues_resolver_spec.rb b/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
new file mode 100644
index 00000000000..e23a37b3d69
--- /dev/null
+++ b/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::BoardListIssuesResolver do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:unauth_user) { create(:user) }
+ let_it_be(:user_project) { create(:project, creator_id: user.id, namespace: user.namespace ) }
+ let_it_be(:group) { create(:group, :private) }
+
+ shared_examples_for 'group and project board list issues resolver' do
+ let!(:board) { create(:board, resource_parent: board_parent) }
+
+ before do
+ board_parent.add_developer(user)
+ end
+
+ # auth is handled by the parent object
+ context 'when authorized' do
+ let!(:list) { create(:list, board: board, label: label) }
+
+ it 'returns the issues in the correct order' do
+ issue1 = create(:issue, project: project, labels: [label], relative_position: 10)
+ issue2 = create(:issue, project: project, labels: [label], relative_position: 12)
+ issue3 = create(:issue, project: project, labels: [label], relative_position: 10)
+
+ # by relative_position and then ID
+ issues = resolve_board_list_issues.items
+
+ expect(issues.map(&:id)).to eq [issue3.id, issue1.id, issue2.id]
+ end
+ end
+ end
+
+ describe '#resolve' do
+ context 'when project boards' do
+ let(:board_parent) { user_project }
+ let!(:label) { create(:label, project: project, name: 'project label') }
+ let(:project) { user_project }
+
+ it_behaves_like 'group and project board list issues resolver'
+ end
+
+ context 'when group boards' do
+ let(:board_parent) { group }
+ let!(:label) { create(:group_label, group: group, name: 'group label') }
+ let!(:project) { create(:project, :private, group: group) }
+
+ it_behaves_like 'group and project board list issues resolver'
+ end
+ end
+
+ def resolve_board_list_issues(args: {}, current_user: user)
+ resolve(described_class, obj: list, args: args, ctx: { current_user: current_user })
+ end
+end
diff --git a/spec/graphql/resolvers/board_lists_resolver_spec.rb b/spec/graphql/resolvers/board_lists_resolver_spec.rb
index f662e9a0f62..fb6a5ccb781 100644
--- a/spec/graphql/resolvers/board_lists_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_lists_resolver_spec.rb
@@ -57,6 +57,30 @@ RSpec.describe Resolvers::BoardListsResolver do
expect(lists.count).to eq 3
end
end
+
+ context 'when querying for a single list' do
+ it 'returns specified list' do
+ list = resolve_board_lists(args: { id: global_id_of(label_list) }).items
+
+ expect(list).to eq [label_list]
+ end
+
+ it 'returns empty result if list is not found' do
+ external_group = create(:group, :private)
+ external_board = create(:board, resource_parent: external_group )
+ external_label = create(:group_label, group: group)
+ external_list = create(:list, board: external_board, label: external_label)
+
+ list = resolve_board_lists(args: { id: global_id_of(external_list) }).items
+
+ expect(list).to eq List.none
+ end
+
+ it 'raises an argument error if list ID is not valid' do
+ expect { resolve_board_lists(args: { id: 'test' }).items }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ end
+ end
end
end
diff --git a/spec/graphql/resolvers/ci_configuration/sast_resolver_spec.rb b/spec/graphql/resolvers/ci_configuration/sast_resolver_spec.rb
deleted file mode 100644
index de69ad5d450..00000000000
--- a/spec/graphql/resolvers/ci_configuration/sast_resolver_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Resolvers::CiConfiguration::SastResolver do
- include GraphqlHelpers
-
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
-
- describe '#resolve' do
- subject(:sast_config) { resolve(described_class, ctx: { current_user: user }, obj: project) }
-
- it 'returns global variable informations related to SAST' do
- expect(sast_config['global'].first['field']).to eql("SECURE_ANALYZERS_PREFIX")
- expect(sast_config['global'].first['label']).to eql("Image prefix")
- expect(sast_config['global'].first['type']).to eql("string")
-
- expect(sast_config['pipeline'].first['field']).to eql("stage")
- expect(sast_config['pipeline'].first['label']).to eql("Stage")
- expect(sast_config['pipeline'].first['type']).to eql("dropdown")
-
- expect(sast_config['analyzers'].first['name']).to eql("brakeman")
- expect(sast_config['analyzers'].first['label']).to eql("Brakeman")
- expect(sast_config['analyzers'].first['enabled']).to be true
- end
- end
-end
diff --git a/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb b/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb
index 20a0cb842a4..a408981c08e 100644
--- a/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb
+++ b/spec/graphql/resolvers/commit_pipelines_resolver_spec.rb
@@ -18,6 +18,7 @@ RSpec.describe Resolvers::CommitPipelinesResolver do
status: 'success'
)
end
+
let!(:pipeline2) do
create(
:ci_pipeline,
@@ -27,6 +28,7 @@ RSpec.describe Resolvers::CommitPipelinesResolver do
status: 'failed'
)
end
+
let!(:pipeline3) do
create(
:ci_pipeline,
diff --git a/spec/graphql/resolvers/group_issues_resolver_spec.rb b/spec/graphql/resolvers/group_issues_resolver_spec.rb
new file mode 100644
index 00000000000..463cdca699b
--- /dev/null
+++ b/spec/graphql/resolvers/group_issues_resolver_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::GroupIssuesResolver do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:other_project) { create(:project, group: group) }
+ let_it_be(:subgroup) { create(:group, parent: group) }
+ let_it_be(:subproject) { create(:project, group: subgroup) }
+
+ let_it_be(:issue1) { create(:incident, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago) }
+ let_it_be(:issue2) { create(:issue, project: project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago) }
+ let_it_be(:issue3) { create(:issue, project: other_project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago) }
+ let_it_be(:issue4) { create(:issue) }
+
+ let_it_be(:subissue1) { create(:issue, project: subproject) }
+ let_it_be(:subissue2) { create(:issue, project: subproject) }
+ let_it_be(:subissue3) { create(:issue, project: subproject) }
+
+ before_all do
+ group.add_developer(current_user)
+ subgroup.add_developer(current_user)
+ end
+
+ describe '#resolve' do
+ it 'finds all group issues' do
+ result = resolve(described_class, obj: group, ctx: { current_user: current_user })
+
+ expect(result).to contain_exactly(issue1, issue2, issue3)
+ end
+
+ it 'finds all group and subgroup issues' do
+ result = resolve(described_class, obj: group, args: { include_subgroups: true }, ctx: { current_user: current_user })
+
+ expect(result).to contain_exactly(issue1, issue2, issue3, subissue1, subissue2, subissue3)
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/group_milestones_resolver_spec.rb b/spec/graphql/resolvers/group_milestones_resolver_spec.rb
new file mode 100644
index 00000000000..05d0ec38192
--- /dev/null
+++ b/spec/graphql/resolvers/group_milestones_resolver_spec.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::GroupMilestonesResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:current_user) { create(:user) }
+
+ def resolve_group_milestones(args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: group, args: args, ctx: context)
+ end
+
+ let_it_be(:now) { Time.now }
+ let_it_be(:group) { create(:group, :private) }
+
+ before_all do
+ group.add_developer(current_user)
+ end
+
+ it 'calls MilestonesFinder#execute' do
+ expect_next_instance_of(MilestonesFinder) do |finder|
+ expect(finder).to receive(:execute)
+ end
+
+ resolve_group_milestones
+ end
+
+ context 'without parameters' do
+ it 'calls MilestonesFinder to retrieve all milestones' do
+ expect(MilestonesFinder).to receive(:new)
+ .with(ids: nil, group_ids: group.id, state: 'all', start_date: nil, end_date: nil)
+ .and_call_original
+
+ resolve_group_milestones
+ end
+ end
+
+ context 'with parameters' do
+ it 'calls MilestonesFinder with correct parameters' do
+ start_date = now
+ end_date = start_date + 1.hour
+
+ expect(MilestonesFinder).to receive(:new)
+ .with(ids: nil, group_ids: group.id, state: 'closed', start_date: start_date, end_date: end_date)
+ .and_call_original
+
+ resolve_group_milestones(start_date: start_date, end_date: end_date, state: 'closed')
+ end
+ end
+
+ context 'by ids' do
+ it 'calls MilestonesFinder with correct parameters' do
+ milestone = create(:milestone, group: group)
+
+ expect(MilestonesFinder).to receive(:new)
+ .with(ids: [milestone.id.to_s], group_ids: group.id, state: 'all', start_date: nil, end_date: nil)
+ .and_call_original
+
+ resolve_group_milestones(ids: [milestone.to_global_id])
+ end
+ end
+
+ context 'by timeframe' do
+ context 'when start_date and end_date are present' do
+ context 'when start date is after end_date' do
+ it 'raises error' do
+ expect do
+ resolve_group_milestones(start_date: now, end_date: now - 2.days)
+ end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, "startDate is after endDate")
+ end
+ end
+ end
+
+ context 'when only start_date is present' do
+ it 'raises error' do
+ expect do
+ resolve_group_milestones(start_date: now)
+ end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /Both startDate and endDate/)
+ end
+ end
+
+ context 'when only end_date is present' do
+ it 'raises error' do
+ expect do
+ resolve_group_milestones(end_date: now)
+ end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /Both startDate and endDate/)
+ end
+ end
+ end
+
+ context 'when user cannot read milestones' do
+ it 'raises error' do
+ unauthorized_user = create(:user)
+
+ expect do
+ resolve_group_milestones({}, { current_user: unauthorized_user })
+ end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when including descendant milestones in a public group' do
+ let_it_be(:group) { create(:group, :public) }
+ let(:args) { { include_descendants: true } }
+
+ it 'finds milestones only in accessible projects and groups' do
+ accessible_group = create(:group, :private, parent: group)
+ accessible_project = create(:project, group: accessible_group)
+ accessible_group.add_developer(current_user)
+ inaccessible_group = create(:group, :private, parent: group)
+ inaccessible_project = create(:project, :private, group: group)
+ milestone1 = create(:milestone, group: group)
+ milestone2 = create(:milestone, group: accessible_group)
+ milestone3 = create(:milestone, project: accessible_project)
+ create(:milestone, group: inaccessible_group)
+ create(:milestone, project: inaccessible_project)
+
+ expect(resolve_group_milestones(args)).to match_array([milestone1, milestone2, milestone3])
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/issue_status_counts_resolver_spec.rb b/spec/graphql/resolvers/issue_status_counts_resolver_spec.rb
new file mode 100644
index 00000000000..d2412db35c6
--- /dev/null
+++ b/spec/graphql/resolvers/issue_status_counts_resolver_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::IssueStatusCountsResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:issue) { create(:issue, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago) }
+ let_it_be(:incident) { create(:incident, project: project, state: :closed, created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago) }
+
+ let(:args) { {} }
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ subject { resolve_issue_status_counts(args) }
+
+ it { is_expected.to be_a(Gitlab::IssuablesCountForState) }
+ specify { expect(subject.project).to eq(project) }
+
+ it 'returns expected results' do
+ result = resolve_issue_status_counts
+
+ expect(result.all).to eq 2
+ expect(result.opened).to eq 1
+ expect(result.closed).to eq 1
+ end
+
+ it 'filters by search', :aggregate_failures do
+ result = resolve_issue_status_counts(search: issue.title)
+
+ expect(result.all).to eq 1
+ expect(result.opened).to eq 1
+ expect(result.closed).to eq 0
+ end
+
+ it 'filters by issue type', :aggregate_failures do
+ result = resolve_issue_status_counts(issue_types: ['incident'])
+
+ expect(result.all).to eq 1
+ expect(result.opened).to eq 0
+ expect(result.closed).to eq 1
+ end
+
+ # The state param is ignored in IssuableFinder#count_by_state
+ it 'ignores state filter', :aggregate_failures do
+ result = resolve_issue_status_counts(state: 'closed')
+
+ expect(result.all).to eq 2
+ expect(result.opened).to eq 1
+ expect(result.closed).to eq 1
+ end
+
+ private
+
+ def resolve_issue_status_counts(args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: project, args: args, ctx: context)
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index eb17e94a450..db5d009f0e7 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Resolvers::IssuesResolver do
let_it_be(:milestone) { create(:milestone, project: project) }
let_it_be(:assignee) { create(:user) }
- let_it_be(:issue1) { create(:issue, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago, milestone: milestone) }
+ let_it_be(:issue1) { create(:incident, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago, milestone: milestone) }
let_it_be(:issue2) { create(:issue, project: project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) }
let_it_be(:issue3) { create(:issue, project: other_project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) }
let_it_be(:issue4) { create(:issue) }
@@ -95,6 +95,20 @@ RSpec.describe Resolvers::IssuesResolver do
end
end
+ describe 'filters by issue_type' do
+ it 'filters by a single type' do
+ expect(resolve_issues(issue_types: ['incident'])).to contain_exactly(issue1)
+ end
+
+ it 'filters by more than one type' do
+ expect(resolve_issues(issue_types: %w(incident issue))).to contain_exactly(issue1, issue2)
+ end
+
+ it 'ignores the filter if none given' do
+ expect(resolve_issues(issue_types: [])).to contain_exactly(issue1, issue2)
+ end
+ end
+
context 'when searching issues' do
it 'returns correct issues' do
expect(resolve_issues(search: 'foo')).to contain_exactly(issue2)
diff --git a/spec/graphql/resolvers/merge_requests_resolver_spec.rb b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
index 0a8fd82613a..e939edae779 100644
--- a/spec/graphql/resolvers/merge_requests_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
@@ -161,6 +161,24 @@ RSpec.describe Resolvers::MergeRequestsResolver do
end
end
+ context 'by merged_after and merged_before' do
+ before do
+ merge_request_1.metrics.update!(merged_at: 10.days.ago)
+ end
+
+ it 'returns merge requests merged between the given period' do
+ result = resolve_mr(project, merged_after: 20.days.ago, merged_before: 5.days.ago)
+
+ expect(result).to eq([merge_request_1])
+ end
+
+ it 'does not return anything' do
+ result = resolve_mr(project, merged_after: 2.days.ago)
+
+ expect(result).to be_empty
+ end
+ end
+
describe 'combinations' do
it 'requires all filters' do
create(:merge_request, :closed, source_project: project, target_project: project, source_branch: merge_request_4.source_branch)
diff --git a/spec/graphql/resolvers/milestone_resolver_spec.rb b/spec/graphql/resolvers/milestone_resolver_spec.rb
deleted file mode 100644
index 36dd5ef03e2..00000000000
--- a/spec/graphql/resolvers/milestone_resolver_spec.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Resolvers::MilestoneResolver do
- include GraphqlHelpers
-
- describe '#resolve' do
- let_it_be(:current_user) { create(:user) }
-
- def resolve_group_milestones(args = {}, context = { current_user: current_user })
- resolve(described_class, obj: group, args: args, ctx: context)
- end
-
- context 'for group milestones' do
- let_it_be(:now) { Time.now }
- let_it_be(:group) { create(:group, :private) }
-
- before do
- group.add_developer(current_user)
- end
-
- it 'calls MilestonesFinder#execute' do
- expect_next_instance_of(MilestonesFinder) do |finder|
- expect(finder).to receive(:execute)
- end
-
- resolve_group_milestones
- end
-
- context 'without parameters' do
- it 'calls MilestonesFinder to retrieve all milestones' do
- expect(MilestonesFinder).to receive(:new)
- .with(group_ids: group.id, state: 'all', start_date: nil, end_date: nil)
- .and_call_original
-
- resolve_group_milestones
- end
- end
-
- context 'with parameters' do
- it 'calls MilestonesFinder with correct parameters' do
- start_date = now
- end_date = start_date + 1.hour
-
- expect(MilestonesFinder).to receive(:new)
- .with(group_ids: group.id, state: 'closed', start_date: start_date, end_date: end_date)
- .and_call_original
-
- resolve_group_milestones(start_date: start_date, end_date: end_date, state: 'closed')
- end
- end
-
- context 'by timeframe' do
- context 'when start_date and end_date are present' do
- context 'when start date is after end_date' do
- it 'raises error' do
- expect do
- resolve_group_milestones(start_date: now, end_date: now - 2.days)
- end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, "startDate is after endDate")
- end
- end
- end
-
- context 'when only start_date is present' do
- it 'raises error' do
- expect do
- resolve_group_milestones(start_date: now)
- end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /Both startDate and endDate/)
- end
- end
-
- context 'when only end_date is present' do
- it 'raises error' do
- expect do
- resolve_group_milestones(end_date: now)
- end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /Both startDate and endDate/)
- end
- end
- end
-
- context 'when user cannot read milestones' do
- it 'raises error' do
- unauthorized_user = create(:user)
-
- expect do
- resolve_group_milestones({}, { current_user: unauthorized_user })
- end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
- end
- end
- end
-
- context 'when including descendant milestones in a public group' do
- let_it_be(:group) { create(:group, :public) }
- let(:args) { { include_descendants: true } }
-
- it 'finds milestones only in accessible projects and groups' do
- accessible_group = create(:group, :private, parent: group)
- accessible_project = create(:project, group: accessible_group)
- accessible_group.add_developer(current_user)
- inaccessible_group = create(:group, :private, parent: group)
- inaccessible_project = create(:project, :private, group: group)
- milestone1 = create(:milestone, group: group)
- milestone2 = create(:milestone, group: accessible_group)
- milestone3 = create(:milestone, project: accessible_project)
- create(:milestone, group: inaccessible_group)
- create(:milestone, project: inaccessible_project)
-
- expect(resolve_group_milestones(args)).to match_array([milestone1, milestone2, milestone3])
- end
- end
- end
-end
diff --git a/spec/graphql/resolvers/project_milestones_resolver_spec.rb b/spec/graphql/resolvers/project_milestones_resolver_spec.rb
new file mode 100644
index 00000000000..e0b250cfe7c
--- /dev/null
+++ b/spec/graphql/resolvers/project_milestones_resolver_spec.rb
@@ -0,0 +1,117 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::ProjectMilestonesResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:current_user) { create(:user) }
+
+ before_all do
+ project.add_developer(current_user)
+ end
+
+ def resolve_project_milestones(args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: project, args: args, ctx: context)
+ end
+
+ it 'calls MilestonesFinder to retrieve all milestones' do
+ expect(MilestonesFinder).to receive(:new)
+ .with(ids: nil, project_ids: project.id, state: 'all', start_date: nil, end_date: nil)
+ .and_call_original
+
+ resolve_project_milestones
+ end
+
+ context 'when including ancestor milestones' do
+ let(:parent_group) { create(:group) }
+ let(:group) { create(:group, parent: parent_group) }
+ let(:project) { create(:project, group: group) }
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'calls MilestonesFinder with correct parameters' do
+ expect(MilestonesFinder).to receive(:new)
+ .with(ids: nil, project_ids: project.id, group_ids: contain_exactly(group, parent_group), state: 'all', start_date: nil, end_date: nil)
+ .and_call_original
+
+ resolve_project_milestones(include_ancestors: true)
+ end
+ end
+
+ context 'by ids' do
+ it 'calls MilestonesFinder with correct parameters' do
+ milestone = create(:milestone, project: project)
+
+ expect(MilestonesFinder).to receive(:new)
+ .with(ids: [milestone.id.to_s], project_ids: project.id, state: 'all', start_date: nil, end_date: nil)
+ .and_call_original
+
+ resolve_project_milestones(ids: [milestone.to_global_id])
+ end
+ end
+
+ context 'by state' do
+ it 'calls MilestonesFinder with correct parameters' do
+ expect(MilestonesFinder).to receive(:new)
+ .with(ids: nil, project_ids: project.id, state: 'closed', start_date: nil, end_date: nil)
+ .and_call_original
+
+ resolve_project_milestones(state: 'closed')
+ end
+ end
+
+ context 'by timeframe' do
+ context 'when start_date and end_date are present' do
+ it 'calls MilestonesFinder with correct parameters' do
+ start_date = Time.now
+ end_date = Time.now + 5.days
+
+ expect(MilestonesFinder).to receive(:new)
+ .with(ids: nil, project_ids: project.id, state: 'all', start_date: start_date, end_date: end_date)
+ .and_call_original
+
+ resolve_project_milestones(start_date: start_date, end_date: end_date)
+ end
+
+ context 'when start date is after end_date' do
+ it 'raises error' do
+ expect do
+ resolve_project_milestones(start_date: Time.now, end_date: Time.now - 2.days)
+ end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, "startDate is after endDate")
+ end
+ end
+ end
+
+ context 'when only start_date is present' do
+ it 'raises error' do
+ expect do
+ resolve_project_milestones(start_date: Time.now)
+ end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /Both startDate and endDate/)
+ end
+ end
+
+ context 'when only end_date is present' do
+ it 'raises error' do
+ expect do
+ resolve_project_milestones(end_date: Time.now)
+ end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /Both startDate and endDate/)
+ end
+ end
+ end
+
+ context 'when user cannot read milestones' do
+ it 'raises error' do
+ unauthorized_user = create(:user)
+
+ expect do
+ resolve_project_milestones({}, { current_user: unauthorized_user })
+ end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/project_pipeline_resolver_spec.rb b/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
index a659b3bdb6e..fada2f9193c 100644
--- a/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
@@ -33,4 +33,21 @@ RSpec.describe Resolvers::ProjectPipelineResolver do
it 'errors when no iid is passed' do
expect { resolve_pipeline(project, {}) }.to raise_error(ArgumentError)
end
+
+ context 'when the pipeline is not a ci_config_source' do
+ let(:pipeline) do
+ config_source_value = Ci::PipelineEnums.non_ci_config_source_values.first
+ config_source = Ci::PipelineEnums.config_sources.key(config_source_value)
+
+ create(:ci_pipeline, config_source: config_source, project: project)
+ end
+
+ it 'resolves pipeline for the passed iid' do
+ result = batch_sync do
+ resolve_pipeline(project, { iid: pipeline.iid.to_s })
+ end
+
+ expect(result).to eq(pipeline)
+ end
+ end
end
diff --git a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
index 4038bcb3e5d..840aea8b8c4 100644
--- a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Resolvers::Projects::JiraProjectsResolver do
end
end
- context 'when project has no jira service' do
+ context 'when project has no Jira service' do
let_it_be(:jira_service) { nil }
context 'when user is a maintainer' do
@@ -29,7 +29,7 @@ RSpec.describe Resolvers::Projects::JiraProjectsResolver do
end
end
- context 'when project has jira service' do
+ context 'when project has Jira service' do
let(:jira_service) { create(:jira_service, project: project) }
context 'when user is a developer' do
@@ -46,10 +46,11 @@ RSpec.describe Resolvers::Projects::JiraProjectsResolver do
end
context 'when Jira connection is valid' do
- include_context 'jira projects request context'
+ include_context 'Jira projects request context'
- it 'returns jira projects' do
- jira_projects = resolve_jira_projects
+ it 'returns Jira projects', :aggregate_failures do
+ resolver = resolve_jira_projects
+ jira_projects = resolver.items
project_keys = jira_projects.map(&:key)
project_names = jira_projects.map(&:name)
project_ids = jira_projects.map(&:id)
@@ -58,6 +59,23 @@ RSpec.describe Resolvers::Projects::JiraProjectsResolver do
expect(project_keys).to eq(%w(EX ABC))
expect(project_names).to eq(%w(Example Alphabetical))
expect(project_ids).to eq(%w(10000 10001))
+ expect(resolver.max_page_size).to eq(2)
+ end
+
+ context 'when filtering projects by name' do
+ it 'returns Jira projects', :aggregate_failures do
+ resolver = resolve_jira_projects({ name: 'ABC' })
+ jira_projects = resolver.items
+ project_keys = jira_projects.map(&:key)
+ project_names = jira_projects.map(&:name)
+ project_ids = jira_projects.map(&:id)
+
+ expect(jira_projects.size).to eq 1
+ expect(project_keys).to eq(%w(ABC))
+ expect(project_names).to eq(%w(Alphabetical))
+ expect(project_ids).to eq(%w(10001))
+ expect(resolver.max_page_size).to eq(1)
+ end
end
end
diff --git a/spec/graphql/resolvers/todo_resolver_spec.rb b/spec/graphql/resolvers/todo_resolver_spec.rb
index 0775cb8dae7..83e3140b676 100644
--- a/spec/graphql/resolvers/todo_resolver_spec.rb
+++ b/spec/graphql/resolvers/todo_resolver_spec.rb
@@ -99,7 +99,7 @@ RSpec.describe Resolvers::TodoResolver do
end
end
- context 'when no user is provided' do
+ context 'when no target is provided' do
it 'returns no todos' do
todos = resolve(described_class, obj: nil, args: {}, ctx: { current_user: current_user })
@@ -107,7 +107,7 @@ RSpec.describe Resolvers::TodoResolver do
end
end
- context 'when provided user is not current user' do
+ context 'when target user is not the current user' do
it 'returns no todos' do
other_user = create(:user)
@@ -116,6 +116,16 @@ RSpec.describe Resolvers::TodoResolver do
expect(todos).to be_empty
end
end
+
+ context 'when request is for a todo target' do
+ it 'returns only the todos for the target' do
+ target = issue_todo_pending.target
+
+ todos = resolve(described_class, obj: target, args: {}, ctx: { current_user: current_user })
+
+ expect(todos).to contain_exactly(issue_todo_pending)
+ end
+ end
end
def resolve_todos(args = {}, context = { current_user: current_user })
diff --git a/spec/graphql/types/alert_management/alert_type_spec.rb b/spec/graphql/types/alert_management/alert_type_spec.rb
index 45ac673986d..e14c189d4b6 100644
--- a/spec/graphql/types/alert_management/alert_type_spec.rb
+++ b/spec/graphql/types/alert_management/alert_type_spec.rb
@@ -28,6 +28,10 @@ RSpec.describe GitlabSchema.types['AlertManagementAlert'] do
notes
discussions
metrics_dashboard_url
+ runbook
+ todos
+ details_url
+ prometheus_alert
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/board_list_type_spec.rb b/spec/graphql/types/board_list_type_spec.rb
index 046d1e92bfa..7976936fc1f 100644
--- a/spec/graphql/types/board_list_type_spec.rb
+++ b/spec/graphql/types/board_list_type_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe GitlabSchema.types['BoardList'] do
specify { expect(described_class.graphql_name).to eq('BoardList') }
it 'has specific fields' do
- expected_fields = %w[id list_type position label]
+ expected_fields = %w[id list_type position label issues_count issues]
expect(described_class).to include_graphql_fields(*expected_fields)
end
diff --git a/spec/graphql/types/ci/group_type_spec.rb b/spec/graphql/types/ci/group_type_spec.rb
new file mode 100644
index 00000000000..8d547b19af3
--- /dev/null
+++ b/spec/graphql/types/ci/group_type_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::GroupType do
+ specify { expect(described_class.graphql_name).to eq('CiGroup') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ name
+ size
+ jobs
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/job_type_spec.rb b/spec/graphql/types/ci/job_type_spec.rb
new file mode 100644
index 00000000000..faf3a95cf25
--- /dev/null
+++ b/spec/graphql/types/ci/job_type_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::JobType do
+ specify { expect(described_class.graphql_name).to eq('CiJob') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ name
+ needs
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/stage_type_spec.rb b/spec/graphql/types/ci/stage_type_spec.rb
new file mode 100644
index 00000000000..0c352ed27aa
--- /dev/null
+++ b/spec/graphql/types/ci/stage_type_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::StageType do
+ specify { expect(described_class.graphql_name).to eq('CiStage') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ name
+ groups
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb b/spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb
deleted file mode 100644
index 34a22feeaf5..00000000000
--- a/spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe GitlabSchema.types['SastCiConfigurationAnalyzersEntity'] do
- let(:fields) { %i[name label enabled description] }
-
- it { expect(described_class.graphql_name).to eq('SastCiConfigurationAnalyzersEntity') }
-
- it { expect(described_class).to have_graphql_fields(fields) }
-end
diff --git a/spec/graphql/types/ci_configuration/sast/entity_type_spec.rb b/spec/graphql/types/ci_configuration/sast/entity_type_spec.rb
deleted file mode 100644
index 7c6ad013d4a..00000000000
--- a/spec/graphql/types/ci_configuration/sast/entity_type_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe GitlabSchema.types['SastCiConfigurationEntity'] do
- let(:fields) { %i[field label description type options default_value value] }
-
- it { expect(described_class.graphql_name).to eq('SastCiConfigurationEntity') }
-
- it { expect(described_class).to have_graphql_fields(fields) }
-end
diff --git a/spec/graphql/types/ci_configuration/sast/options_entity_spec.rb b/spec/graphql/types/ci_configuration/sast/options_entity_spec.rb
deleted file mode 100644
index c60c8b9c84a..00000000000
--- a/spec/graphql/types/ci_configuration/sast/options_entity_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe GitlabSchema.types['SastCiConfigurationOptionsEntity'] do
- let(:fields) { %i[label value] }
-
- it { expect(described_class.graphql_name).to eq('SastCiConfigurationOptionsEntity') }
-
- it { expect(described_class).to have_graphql_fields(fields) }
-end
diff --git a/spec/graphql/types/ci_configuration/sast/type_spec.rb b/spec/graphql/types/ci_configuration/sast/type_spec.rb
deleted file mode 100644
index e7a8cd436e4..00000000000
--- a/spec/graphql/types/ci_configuration/sast/type_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe GitlabSchema.types['SastCiConfiguration'] do
- let(:fields) { %i[global pipeline analyzers] }
-
- it { expect(described_class.graphql_name).to eq('SastCiConfiguration') }
-
- it { expect(described_class).to have_graphql_fields(fields) }
-end
diff --git a/spec/graphql/types/commit_type_spec.rb b/spec/graphql/types/commit_type_spec.rb
index 75984786972..d222287270d 100644
--- a/spec/graphql/types/commit_type_spec.rb
+++ b/spec/graphql/types/commit_type_spec.rb
@@ -9,8 +9,8 @@ RSpec.describe GitlabSchema.types['Commit'] do
it 'contains attributes related to commit' do
expect(described_class).to have_graphql_fields(
- :id, :sha, :title, :description, :message, :title_html, :authored_date,
- :author_name, :author_gravatar, :author, :web_url, :latest_pipeline,
+ :id, :sha, :title, :description, :description_html, :message, :title_html, :authored_date,
+ :author_name, :author_gravatar, :author, :web_url, :web_path, :latest_pipeline,
:pipelines, :signature_html
)
end
diff --git a/spec/graphql/types/issue_connection_type_spec.rb b/spec/graphql/types/countable_connection_type_spec.rb
index af34611ecfe..af34611ecfe 100644
--- a/spec/graphql/types/issue_connection_type_spec.rb
+++ b/spec/graphql/types/countable_connection_type_spec.rb
diff --git a/spec/graphql/types/design_management/design_at_version_type_spec.rb b/spec/graphql/types/design_management/design_at_version_type_spec.rb
index 5a6292c924a..4d61ecf62cc 100644
--- a/spec/graphql/types/design_management/design_at_version_type_spec.rb
+++ b/spec/graphql/types/design_management/design_at_version_type_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe GitlabSchema.types['DesignAtVersion'] do
version = design.versions.first
GitlabSchema.id_from_object(create(:design_at_version, design: design, version: version))
end
+
let_it_be(:object_id_b) { GitlabSchema.id_from_object(create(:design_at_version)) }
let(:object_type) { ::Types::DesignManagement::DesignAtVersionType }
end
diff --git a/spec/graphql/types/environment_type_spec.rb b/spec/graphql/types/environment_type_spec.rb
index f7522cb3e2c..abeeeba543f 100644
--- a/spec/graphql/types/environment_type_spec.rb
+++ b/spec/graphql/types/environment_type_spec.rb
@@ -7,11 +7,76 @@ RSpec.describe GitlabSchema.types['Environment'] do
it 'has the expected fields' do
expected_fields = %w[
- name id state metrics_dashboard
+ name id state metrics_dashboard latest_opened_most_severe_alert
]
expect(described_class).to have_graphql_fields(*expected_fields)
end
specify { expect(described_class).to require_graphql_authorizations(:read_environment) }
+
+ context 'when there is an environment' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:environment) { create(:environment, project: project) }
+ let_it_be(:user) { create(:user) }
+
+ subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ environment(name: "#{environment.name}") {
+ name
+ state
+ }
+ }
+ }
+ )
+ end
+
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns an environment' do
+ expect(subject['data']['project']['environment']['name']).to eq(environment.name)
+ end
+
+ context 'when query alert data for the environment' do
+ let_it_be(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ environment(name: "#{environment.name}") {
+ name
+ state
+ latestOpenedMostSevereAlert {
+ severity
+ title
+ detailsUrl
+ prometheusAlert {
+ humanizedText
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ it 'does not return alert information' do
+ expect(subject['data']['project']['environment']['latestOpenedMostSevereAlert']).to be_nil
+ end
+
+ context 'when alert is raised on the environment' do
+ let!(:prometheus_alert) { create(:prometheus_alert, project: project, environment: environment) }
+ let!(:alert) { create(:alert_management_alert, :triggered, :prometheus, project: project, environment: environment, prometheus_alert: prometheus_alert) }
+
+ it 'returns alert information' do
+ expect(subject['data']['project']['environment']['latestOpenedMostSevereAlert']['severity']).to eq(alert.severity.upcase)
+ end
+ end
+ end
+ end
end
diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb
index fb79e9bb85b..0b87805c2ef 100644
--- a/spec/graphql/types/group_type_spec.rb
+++ b/spec/graphql/types/group_type_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe GitlabSchema.types['Group'] do
web_url avatar_url share_with_group_lock project_creation_level
subgroup_creation_level require_two_factor_authentication
two_factor_grace_period auto_devops_enabled emails_disabled
- mentions_disabled parent boards
+ mentions_disabled parent boards milestones
]
expect(described_class).to include_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/issue_status_count_type_spec.rb b/spec/graphql/types/issue_status_count_type_spec.rb
new file mode 100644
index 00000000000..4e273d6415a
--- /dev/null
+++ b/spec/graphql/types/issue_status_count_type_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['IssueStatusCountsType'] do
+ specify { expect(described_class.graphql_name).to eq('IssueStatusCountsType') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ all
+ opened
+ closed
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/issue_type_enum_spec.rb b/spec/graphql/types/issue_type_enum_spec.rb
new file mode 100644
index 00000000000..7ae5eb76f28
--- /dev/null
+++ b/spec/graphql/types/issue_type_enum_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::IssueTypeEnum do
+ specify { expect(described_class.graphql_name).to eq('IssueType') }
+
+ it 'exposes all the existing issue type values' do
+ expect(described_class.values.keys).to include(
+ *%w[ISSUE INCIDENT]
+ )
+ end
+end
diff --git a/spec/graphql/types/issue_type_spec.rb b/spec/graphql/types/issue_type_spec.rb
index 4a86b07ab1c..24353f8fe3a 100644
--- a/spec/graphql/types/issue_type_spec.rb
+++ b/spec/graphql/types/issue_type_spec.rb
@@ -132,14 +132,14 @@ RSpec.describe GitlabSchema.types['Issue'] do
let(:query) do
%(
query {
- project(fullPath:"#{project.full_path}"){
- issue(iid:"#{issue.iid}"){
+ project(fullPath: "#{project.full_path}") {
+ issue(iid: "#{issue.iid}") {
descriptionHtml
- notes{
- edges{
- node{
+ notes {
+ edges {
+ node {
bodyHtml
- author{
+ author {
username
}
body
diff --git a/spec/graphql/types/merge_request_type_spec.rb b/spec/graphql/types/merge_request_type_spec.rb
index b3dccde8ce3..b11951190e0 100644
--- a/spec/graphql/types/merge_request_type_spec.rb
+++ b/spec/graphql/types/merge_request_type_spec.rb
@@ -24,9 +24,11 @@ RSpec.describe GitlabSchema.types['MergeRequest'] do
source_branch_exists target_branch_exists
upvotes downvotes head_pipeline pipelines task_completion_status
milestone assignees participants subscribed labels discussion_locked time_estimate
- total_time_spent reference author merged_at
+ total_time_spent reference author merged_at commit_count
]
+ expected_fields << 'approved_by' if Gitlab.ee?
+
expect(described_class).to have_graphql_fields(*expected_fields)
end
end
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index ea88ed6a3f5..8a5d0cdf12d 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -22,11 +22,12 @@ RSpec.describe GitlabSchema.types['Project'] do
only_allow_merge_if_pipeline_succeeds request_access_enabled
only_allow_merge_if_all_discussions_are_resolved printing_merge_request_link_enabled
namespace group statistics repository merge_requests merge_request issues
- issue pipelines removeSourceBranchAfterMerge sentryDetailedError snippets
+ issue milestones pipelines removeSourceBranchAfterMerge sentryDetailedError snippets
grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments
- boards jira_import_status jira_imports services releases release
+ environment boards jira_import_status jira_imports services releases release
alert_management_alerts alert_management_alert alert_management_alert_status_counts
- container_expiration_policy sast_ci_configuration service_desk_enabled service_desk_address
+ container_expiration_policy service_desk_enabled service_desk_address
+ issue_status_counts
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -69,7 +70,9 @@ RSpec.describe GitlabSchema.types['Project'] do
:before,
:after,
:first,
- :last
+ :last,
+ :merged_after,
+ :merged_before
)
end
end
@@ -95,6 +98,13 @@ RSpec.describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_resolver(Resolvers::EnvironmentsResolver) }
end
+ describe 'environment field' do
+ subject { described_class.fields['environment'] }
+
+ it { is_expected.to have_graphql_type(Types::EnvironmentType) }
+ it { is_expected.to have_graphql_resolver(Resolvers::EnvironmentsResolver.single) }
+ end
+
describe 'members field' do
subject { described_class.fields['projectMembers'] }
@@ -140,93 +150,5 @@ RSpec.describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_type(Types::ContainerExpirationPolicyType) }
end
- describe 'sast_ci_configuration' do
- let_it_be(:project) { create(:project) }
- let_it_be(:user) { create(:user) }
- let_it_be(:query) do
- %(
- query {
- project(fullPath: "#{project.full_path}") {
- sastCiConfiguration {
- global {
- nodes {
- type
- options {
- nodes {
- label
- value
- }
- }
- field
- label
- defaultValue
- value
- }
- }
- pipeline {
- nodes {
- type
- options {
- nodes {
- label
- value
- }
- }
- field
- label
- defaultValue
- value
- }
- }
- analyzers {
- nodes {
- name
- label
- enabled
- }
- }
- }
- }
- }
- )
- end
-
- subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
-
- before do
- project.add_developer(user)
- end
-
- it "returns the project's sast configuration for global variables" do
- query_result = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes')
- first_config = query_result.first
- fourth_config = query_result[3]
- expect(first_config['type']).to eq('string')
- expect(first_config['field']).to eq('SECURE_ANALYZERS_PREFIX')
- expect(first_config['label']).to eq('Image prefix')
- expect(first_config['defaultValue']).to eq('registry.gitlab.com/gitlab-org/security-products/analyzers')
- expect(first_config['value']).to eq('')
- expect(first_config['options']).to be_nil
- expect(fourth_config['options']['nodes']).to match([{ "value" => "true", "label" => "true (disables SAST)" },
- { "value" => "false", "label" => "false (enables SAST)" }])
- end
-
- it "returns the project's sast configuration for pipeline variables" do
- configuration = subject.dig('data', 'project', 'sastCiConfiguration', 'pipeline', 'nodes').first
- expect(configuration['type']).to eq('dropdown')
- expect(configuration['field']).to eq('stage')
- expect(configuration['label']).to eq('Stage')
- expect(configuration['defaultValue']).to eq('test')
- expect(configuration['value']).to eq('')
- end
-
- it "returns the project's sast configuration for analyzer variables" do
- configuration = subject.dig('data', 'project', 'sastCiConfiguration', 'analyzers', 'nodes').first
- expect(configuration['name']).to eq('brakeman')
- expect(configuration['label']).to eq('Brakeman')
- expect(configuration['enabled']).to eq(true)
- end
- end
-
it_behaves_like 'a GraphQL type with labels'
end
diff --git a/spec/graphql/types/prometheus_alert_type_spec.rb b/spec/graphql/types/prometheus_alert_type_spec.rb
new file mode 100644
index 00000000000..716537ea716
--- /dev/null
+++ b/spec/graphql/types/prometheus_alert_type_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['PrometheusAlert'] do
+ specify { expect(described_class.graphql_name).to eq('PrometheusAlert') }
+
+ it 'has the expected fields' do
+ expected_fields = %w[
+ id humanized_text
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+
+ specify { expect(described_class).to require_graphql_authorizations(:read_prometheus_alerts) }
+end
diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb
index 081f99a8307..ab13162b406 100644
--- a/spec/graphql/types/query_type_spec.rb
+++ b/spec/graphql/types/query_type_spec.rb
@@ -17,6 +17,7 @@ RSpec.describe GitlabSchema.types['Query'] do
current_user
snippets
design_management
+ milestone
user
users
]
diff --git a/spec/graphql/types/snippet_type_spec.rb b/spec/graphql/types/snippet_type_spec.rb
index 0341ca2c733..86af69f1294 100644
--- a/spec/graphql/types/snippet_type_spec.rb
+++ b/spec/graphql/types/snippet_type_spec.rb
@@ -33,6 +33,7 @@ RSpec.describe GitlabSchema.types['Snippet'] do
}
)
end
+
let(:response) { subject.dig('data', 'snippets', 'nodes')[0] }
subject { GitlabSchema.execute(query, context: { current_user: current_user }).as_json }
@@ -97,6 +98,7 @@ RSpec.describe GitlabSchema.types['Snippet'] do
}
)
end
+
let(:response) { subject.dig('data', 'snippets', 'nodes')[0] }
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
diff --git a/spec/graphql/types/snippets/file_input_action_enum_spec.rb b/spec/graphql/types/snippets/blob_action_enum_spec.rb
index ff9b706240b..9c641bd5446 100644
--- a/spec/graphql/types/snippets/file_input_action_enum_spec.rb
+++ b/spec/graphql/types/snippets/blob_action_enum_spec.rb
@@ -2,8 +2,8 @@
require 'spec_helper'
-RSpec.describe Types::Snippets::FileInputActionEnum do
- specify { expect(described_class.graphql_name).to eq('SnippetFileInputActionEnum') }
+RSpec.describe Types::Snippets::BlobActionEnum do
+ specify { expect(described_class.graphql_name).to eq('SnippetBlobActionEnum') }
it 'exposes all file input action types' do
expect(described_class.values.keys).to eq(%w[create update delete move])
diff --git a/spec/graphql/types/snippets/file_input_type_spec.rb b/spec/graphql/types/snippets/blob_action_input_type_spec.rb
index c7d4909b542..5d6bd81fb77 100644
--- a/spec/graphql/types/snippets/file_input_type_spec.rb
+++ b/spec/graphql/types/snippets/blob_action_input_type_spec.rb
@@ -2,14 +2,14 @@
require 'spec_helper'
-RSpec.describe Types::Snippets::FileInputType do
- specify { expect(described_class.graphql_name).to eq('SnippetFileInputType') }
+RSpec.describe Types::Snippets::BlobActionInputType do
+ specify { expect(described_class.graphql_name).to eq('SnippetBlobActionInputType') }
it 'has the correct arguments' do
expect(described_class.arguments.keys).to match_array(%w[filePath action previousPath content])
end
- it 'sets the type of action argument to FileInputActionEnum' do
- expect(described_class.arguments['action'].type.of_type).to eq(Types::Snippets::FileInputActionEnum)
+ it 'sets the type of action argument to BlobActionEnum' do
+ expect(described_class.arguments['action'].type.of_type).to eq(Types::Snippets::BlobActionEnum)
end
end
diff --git a/spec/graphql/types/snippets/blob_viewer_type_spec.rb b/spec/graphql/types/snippets/blob_viewer_type_spec.rb
index 8210eb9a95c..295df992c67 100644
--- a/spec/graphql/types/snippets/blob_viewer_type_spec.rb
+++ b/spec/graphql/types/snippets/blob_viewer_type_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe GitlabSchema.types['SnippetBlobViewer'] do
let(:query) do
%(
query {
- snippets(ids:"#{snippet.to_global_id}"){
+ snippets(ids: "#{snippet.to_global_id}") {
edges {
node {
blob {
@@ -70,7 +70,7 @@ RSpec.describe GitlabSchema.types['SnippetBlobViewer'] do
let(:query) do
%(
query {
- snippets(ids:"#{snippet.to_global_id}"){
+ snippets(ids: "#{snippet.to_global_id}") {
edges {
node {
blob {
diff --git a/spec/graphql/types/time_type_spec.rb b/spec/graphql/types/time_type_spec.rb
index 68d346766c2..3b0d257e1d7 100644
--- a/spec/graphql/types/time_type_spec.rb
+++ b/spec/graphql/types/time_type_spec.rb
@@ -15,4 +15,14 @@ RSpec.describe GitlabSchema.types['Time'] do
it 'coerces an ISO-time into Time object' do
expect(described_class.coerce_isolated_input(iso)).to eq(time)
end
+
+ it 'rejects invalid input' do
+ expect { described_class.coerce_isolated_input('not valid') }
+ .to raise_error(GraphQL::CoercionError)
+ end
+
+ it 'rejects nil' do
+ expect { described_class.coerce_isolated_input(nil) }
+ .to raise_error(GraphQL::CoercionError)
+ end
end
diff --git a/spec/graphql/types/tree/blob_type_spec.rb b/spec/graphql/types/tree/blob_type_spec.rb
index 73d61d4860c..2b08b528e38 100644
--- a/spec/graphql/types/tree/blob_type_spec.rb
+++ b/spec/graphql/types/tree/blob_type_spec.rb
@@ -5,5 +5,5 @@ require 'spec_helper'
RSpec.describe Types::Tree::BlobType do
specify { expect(described_class.graphql_name).to eq('Blob') }
- specify { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url, :lfs_oid, :mode) }
+ specify { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url, :web_path, :lfs_oid, :mode) }
end
diff --git a/spec/graphql/types/tree/tree_entry_type_spec.rb b/spec/graphql/types/tree/tree_entry_type_spec.rb
index 0e5caf66854..82e05b299fc 100644
--- a/spec/graphql/types/tree/tree_entry_type_spec.rb
+++ b/spec/graphql/types/tree/tree_entry_type_spec.rb
@@ -5,5 +5,5 @@ require 'spec_helper'
RSpec.describe Types::Tree::TreeEntryType do
specify { expect(described_class.graphql_name).to eq('TreeEntry') }
- specify { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url) }
+ specify { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url, :web_path) }
end
diff --git a/spec/graphql/types/user_status_type_spec.rb b/spec/graphql/types/user_status_type_spec.rb
new file mode 100644
index 00000000000..c4421a9cc10
--- /dev/null
+++ b/spec/graphql/types/user_status_type_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::UserStatusType do
+ specify { expect(described_class.graphql_name).to eq('UserStatus') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ emoji
+ message
+ message_html
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/user_type_spec.rb b/spec/graphql/types/user_type_spec.rb
index 6cc3f7bcaa1..7710b8efefe 100644
--- a/spec/graphql/types/user_type_spec.rb
+++ b/spec/graphql/types/user_type_spec.rb
@@ -14,10 +14,13 @@ RSpec.describe GitlabSchema.types['User'] do
snippets
name
username
+ email
avatarUrl
webUrl
+ webPath
todos
state
+ status
authoredMergeRequests
assignedMergeRequests
groupMemberships