diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-20 18:42:06 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-20 18:42:06 +0000 |
commit | 6e4e1050d9dba2b7b2523fdd1768823ab85feef4 (patch) | |
tree | 78be5963ec075d80116a932011d695dd33910b4e /spec/graphql | |
parent | 1ce776de4ae122aba3f349c02c17cebeaa8ecf07 (diff) | |
download | gitlab-ce-6e4e1050d9dba2b7b2523fdd1768823ab85feef4.tar.gz |
Add latest changes from gitlab-org/gitlab@13-3-stable-ee
Diffstat (limited to 'spec/graphql')
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 |