diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
commit | 8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch) | |
tree | a77e7fe7a93de11213032ed4ab1f33a3db51b738 /spec/graphql/mutations | |
parent | 00b35af3db1abfe813a778f643dad221aad51fca (diff) | |
download | gitlab-ce-8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781.tar.gz |
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'spec/graphql/mutations')
15 files changed, 695 insertions, 32 deletions
diff --git a/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb b/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb new file mode 100644 index 00000000000..a025b3d344a --- /dev/null +++ b/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb @@ -0,0 +1,167 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Mutations::AlertManagement::Alerts::SetAssignees do + let_it_be(:starting_assignee) { create(:user) } + let_it_be(:unassigned_user) { create(:user) } + let_it_be(:alert) { create(:alert_management_alert, assignees: [starting_assignee]) } + let_it_be(:project) { alert.project } + + let(:current_user) { starting_assignee } + let(:assignee_usernames) { [unassigned_user.username] } + let(:operation_mode) { nil } + + let(:args) do + { + project_path: project.full_path, + iid: alert.iid, + assignee_usernames: assignee_usernames, + operation_mode: operation_mode + } + end + + before_all do + project.add_developer(starting_assignee) + project.add_developer(unassigned_user) + end + + specify { expect(described_class).to require_graphql_authorizations(:update_alert_management_alert) } + + describe '#resolve' do + let(:expected_assignees) { [unassigned_user] } + + subject(:resolve) { mutation_for(project, current_user).resolve(args) } + + shared_examples 'successful resolution' do + after do + alert.assignees = [starting_assignee] + end + + it 'successfully resolves' do + expect(resolve).to eq(alert: alert.reload, errors: []) + expect(alert.assignees).to eq(expected_assignees) + end + end + + shared_examples 'noop' do + it 'makes no changes' do + original_assignees = alert.assignees + + expect(resolve).to eq(alert: alert.reload, errors: []) + expect(alert.assignees).to eq(original_assignees) + end + end + + context 'when operation mode is not specified' do + it_behaves_like 'successful resolution' + end + + context 'when user does not have permission to update alerts' do + let(:current_user) { create(:user) } + + it 'raises an error if the resource is not accessible to the user' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'for APPEND operation' do + let(:operation_mode) { Types::MutationOperationModeEnum.enum[:append] } + + # Only allow a single assignee + context 'when a different user is already assigned' do + it_behaves_like 'noop' + end + + context 'when no users are specified' do + let(:assignee_usernames) { [] } + + it_behaves_like 'noop' + end + + context 'when a user is specified and no user is assigned' do + before do + alert.assignees = [] + end + + it_behaves_like 'successful resolution' + end + + context 'when the specified user is already assigned to the alert' do + let(:assignee_usernames) { [starting_assignee.username] } + + it_behaves_like 'noop' + end + end + + context 'for REPLACE operation' do + let(:operation_mode) { Types::MutationOperationModeEnum.enum[:replace] } + + context 'when a different user is already assigned' do + it_behaves_like 'successful resolution' + end + + context 'when no users are specified' do + let(:assignee_usernames) { [] } + let(:expected_assignees) { [] } + + it_behaves_like 'successful resolution' + end + + context 'when a user is specified and no user is assigned' do + before do + alert.assignees = [] + end + + it_behaves_like 'successful resolution' + end + + context 'when the specified user is already assigned to the alert' do + let(:assignee_usernames) { [starting_assignee.username] } + + it_behaves_like 'noop' + end + + context 'when multiple users are specified' do + let(:assignees) { [starting_assignee, unassigned_user] } + let(:assignee_usernames) { assignees.map(&:username) } + let(:expected_assignees) { [assignees.last] } + + it_behaves_like 'successful resolution' + end + end + + context 'for REMOVE operation' do + let(:operation_mode) { Types::MutationOperationModeEnum.enum[:remove] } + + context 'when a different user is already assigned' do + it_behaves_like 'noop' + end + + context 'when no users are specified' do + let(:assignee_usernames) { [] } + + it_behaves_like 'noop' + end + + context 'when a user is specified and no user is assigned' do + before do + alert.assignees = [] + end + + it_behaves_like 'noop' + end + + context 'when the specified user is already assigned to the alert' do + let(:assignee_usernames) { [starting_assignee.username] } + let(:expected_assignees) { [] } + + it_behaves_like 'successful resolution' + end + end + end + + def mutation_for(project, user) + described_class.new(object: project, context: { current_user: user }, field: nil) + end +end diff --git a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb index 1e51767cf0e..fa5a84b4fcc 100644 --- a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb +++ b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Mutations::AlertManagement::CreateAlertIssue do +RSpec.describe Mutations::AlertManagement::CreateAlertIssue do let_it_be(:current_user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:alert) { create(:alert_management_alert, project: project, status: 'triggered') } diff --git a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb index 8b9abd9497d..68513c02040 100644 --- a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb +++ b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Mutations::AlertManagement::UpdateAlertStatus do +RSpec.describe Mutations::AlertManagement::UpdateAlertStatus do let_it_be(:current_user) { create(:user) } let_it_be(:alert) { create(:alert_management_alert, :triggered) } let_it_be(:project) { alert.project } @@ -33,7 +33,7 @@ describe Mutations::AlertManagement::UpdateAlertStatus do context 'error occurs when updating' do it 'returns the alert with errors' do # Stub an error on the alert - allow_next_instance_of(Resolvers::AlertManagementAlertResolver) do |resolver| + allow_next_instance_of(Resolvers::AlertManagement::AlertResolver) do |resolver| allow(resolver).to receive(:resolve).and_return(alert) end diff --git a/spec/graphql/mutations/branches/create_spec.rb b/spec/graphql/mutations/branches/create_spec.rb index 744f8f1f2bc..e378a8e3d41 100644 --- a/spec/graphql/mutations/branches/create_spec.rb +++ b/spec/graphql/mutations/branches/create_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Mutations::Branches::Create do +RSpec.describe Mutations::Branches::Create do subject(:mutation) { described_class.new(object: nil, context: context, field: nil) } let_it_be(:project) { create(:project, :public, :repository) } diff --git a/spec/graphql/mutations/commits/create_spec.rb b/spec/graphql/mutations/commits/create_spec.rb new file mode 100644 index 00000000000..bb0b8c577b0 --- /dev/null +++ b/spec/graphql/mutations/commits/create_spec.rb @@ -0,0 +1,180 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Commits::Create do + subject(:mutation) { described_class.new(object: nil, context: context, field: nil) } + + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:user) { create(:user) } + let(:context) do + GraphQL::Query::Context.new( + query: OpenStruct.new(schema: nil), + values: { current_user: user }, + object: nil + ) + end + + specify { expect(described_class).to require_graphql_authorizations(:push_code) } + + describe '#resolve' do + subject { mutation.resolve(project_path: project.full_path, branch: branch, message: message, actions: actions) } + + let(:branch) { 'master' } + let(:message) { 'Commit message' } + let(:actions) do + [ + { + action: 'create', + file_path: 'NEW_FILE.md', + content: 'Hello' + } + ] + end + + let(:mutated_commit) { subject[:commit] } + + 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 user does not have enough permissions' do + before do + project.add_guest(user) + end + + it 'raises an error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when user is a maintainer of a different project' do + before do + create(:project_empty_repo).add_maintainer(user) + end + + it 'raises an error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when the user can create a commit' do + let(:deltas) { mutated_commit.raw_deltas } + + before_all do + project.add_developer(user) + end + + context 'when service successfully creates a new commit' do + it 'returns a new commit' do + expect(mutated_commit).to have_attributes(message: message, project: project) + expect(subject[:errors]).to be_empty + + expect_to_contain_deltas([ + a_hash_including(a_mode: '0', b_mode: '100644', new_file: true, new_path: 'NEW_FILE.md') + ]) + end + end + + context 'when request has multiple actions' do + let(:actions) do + [ + { + action: 'create', + file_path: 'foo/foobar', + content: 'some content' + }, + { + action: 'delete', + file_path: 'README.md' + }, + { + action: 'move', + file_path: "LICENSE.md", + previous_path: "LICENSE", + content: "some content" + }, + { + action: 'update', + file_path: 'VERSION', + content: 'new content' + }, + { + action: 'chmod', + file_path: 'CHANGELOG', + execute_filemode: true + } + ] + end + + it 'returns a new commit' do + expect(mutated_commit).to have_attributes(message: message, project: project) + expect(subject[:errors]).to be_empty + + expect_to_contain_deltas([ + a_hash_including(a_mode: '0', b_mode: '100644', new_path: 'foo/foobar'), + a_hash_including(deleted_file: true, new_path: 'README.md'), + a_hash_including(deleted_file: true, new_path: 'LICENSE'), + a_hash_including(new_file: true, new_path: 'LICENSE.md'), + a_hash_including(new_file: false, new_path: 'VERSION'), + a_hash_including(a_mode: '100644', b_mode: '100755', new_path: 'CHANGELOG') + ]) + end + end + + context 'when actions are not defined' do + let(:actions) { [] } + + it 'returns a new commit' do + expect(mutated_commit).to have_attributes(message: message, project: project) + expect(subject[:errors]).to be_empty + + expect_to_contain_deltas([]) + end + end + + context 'when branch does not exist' do + let(:branch) { 'unknown' } + + it 'returns errors' do + expect(mutated_commit).to be_nil + expect(subject[:errors]).to eq(['You can only create or edit files when you are on a branch']) + end + end + + context 'when message is not set' do + let(:message) { nil } + + it 'returns errors' do + expect(mutated_commit).to be_nil + expect(subject[:errors]).to eq(['3:UserCommitFiles: empty CommitMessage']) + end + end + + context 'when actions are incorrect' do + let(:actions) { [{ action: 'unknown', file_path: 'test.md', content: '' }] } + + it 'returns errors' do + expect(mutated_commit).to be_nil + expect(subject[:errors]).to eq(['Unknown action \'unknown\'']) + end + end + + context 'when branch is protected' do + before do + create(:protected_branch, project: project, name: branch) + end + + it 'returns errors' do + expect(mutated_commit).to be_nil + expect(subject[:errors]).to eq(['You are not allowed to push into this branch']) + end + end + end + end + + def expect_to_contain_deltas(expected_deltas) + expect(deltas.count).to eq(expected_deltas.count) + expect(deltas).to include(*expected_deltas) + end +end diff --git a/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb b/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb index 51d3c4f5d6b..6bed3a752ed 100644 --- a/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb +++ b/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Mutations::ResolvesGroup do +RSpec.describe Mutations::ResolvesGroup do let(:mutation_class) do Class.new(Mutations::BaseMutation) do include Mutations::ResolvesGroup diff --git a/spec/graphql/mutations/concerns/mutations/resolves_issuable_spec.rb b/spec/graphql/mutations/concerns/mutations/resolves_issuable_spec.rb index 145e42e2a51..706a54931ea 100644 --- a/spec/graphql/mutations/concerns/mutations/resolves_issuable_spec.rb +++ b/spec/graphql/mutations/concerns/mutations/resolves_issuable_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Mutations::ResolvesIssuable do +RSpec.describe Mutations::ResolvesIssuable do let_it_be(:mutation_class) do Class.new(Mutations::BaseMutation) do include Mutations::ResolvesIssuable diff --git a/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb b/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb deleted file mode 100644 index b5c349f6284..00000000000 --- a/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Mutations::ResolvesProject do - let(:mutation_class) do - Class.new(Mutations::BaseMutation) do - include Mutations::ResolvesProject - end - end - - let(:context) { double } - - subject(:mutation) { mutation_class.new(object: nil, context: context, field: nil) } - - it 'uses the ProjectsResolver to resolve projects by path' do - project = create(:project) - - expect(Resolvers::ProjectResolver).to receive(:new).with(object: nil, context: context, field: nil).and_call_original - expect(mutation.resolve_project(full_path: project.full_path).sync).to eq(project) - end -end diff --git a/spec/graphql/mutations/container_expiration_policies/update_spec.rb b/spec/graphql/mutations/container_expiration_policies/update_spec.rb new file mode 100644 index 00000000000..fc90f437576 --- /dev/null +++ b/spec/graphql/mutations/container_expiration_policies/update_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Mutations::ContainerExpirationPolicies::Update do + using RSpec::Parameterized::TableSyntax + + let_it_be(:project, reload: true) { create(:project) } + let_it_be(:user) { create(:user) } + + let(:container_expiration_policy) { project.container_expiration_policy } + let(:params) { { project_path: project.full_path, cadence: '3month', keep_n: 100, older_than: '14d' } } + + specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) } + + describe '#resolve' do + subject { described_class.new(object: project, context: { current_user: user }, field: nil).resolve(params) } + + RSpec.shared_examples 'returning a success' do + it 'returns the container expiration policy with no errors' do + expect(subject).to eq( + container_expiration_policy: container_expiration_policy, + errors: [] + ) + end + end + + RSpec.shared_examples 'updating the container expiration policy' do + it_behaves_like 'updating the container expiration policy attributes', mode: :update, from: { cadence: '1d', keep_n: 10, older_than: '90d' }, to: { cadence: '3month', keep_n: 100, older_than: '14d' } + + it_behaves_like 'returning a success' + + context 'with invalid params' do + let_it_be(:params) { { project_path: project.full_path, cadence: '20d' } } + + it_behaves_like 'not creating the container expiration policy' + + it "doesn't update the cadence" do + expect { subject } + .not_to change { container_expiration_policy.reload.cadence } + end + + it 'returns an error' do + expect(subject).to eq( + container_expiration_policy: nil, + errors: ['Cadence is not included in the list'] + ) + end + end + end + + RSpec.shared_examples 'denying access to container expiration policy' do + it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'with existing container expiration policy' do + where(:user_role, :shared_examples_name) do + :maintainer | 'updating the container expiration policy' + :developer | 'updating the container expiration policy' + :reporter | 'denying access to container expiration policy' + :guest | 'denying access to container expiration policy' + :anonymous | 'denying access to container expiration policy' + end + + with_them do + before do + project.send("add_#{user_role}", user) unless user_role == :anonymous + end + + it_behaves_like params[:shared_examples_name] + end + end + + context 'without existing container expiration policy' do + let_it_be(:project, reload: true) { create(:project, :without_container_expiration_policy) } + + where(:user_role, :shared_examples_name) do + :maintainer | 'creating the container expiration policy' + :developer | 'creating the container expiration policy' + :reporter | 'denying access to container expiration policy' + :guest | 'denying access to container expiration policy' + :anonymous | 'denying access to container expiration policy' + end + + with_them do + before do + project.send("add_#{user_role}", user) unless user_role == :anonymous + end + + it_behaves_like params[:shared_examples_name] + end + end + end +end diff --git a/spec/graphql/mutations/design_management/delete_spec.rb b/spec/graphql/mutations/design_management/delete_spec.rb index 60be6dad62a..3efa865c64b 100644 --- a/spec/graphql/mutations/design_management/delete_spec.rb +++ b/spec/graphql/mutations/design_management/delete_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Mutations::DesignManagement::Delete do +RSpec.describe Mutations::DesignManagement::Delete do include DesignManagementTestHelpers let(:issue) { create(:issue) } diff --git a/spec/graphql/mutations/design_management/upload_spec.rb b/spec/graphql/mutations/design_management/upload_spec.rb index 783af70448c..326d88cea80 100644 --- a/spec/graphql/mutations/design_management/upload_spec.rb +++ b/spec/graphql/mutations/design_management/upload_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Mutations::DesignManagement::Upload do +RSpec.describe Mutations::DesignManagement::Upload do include DesignManagementTestHelpers include ConcurrentHelpers diff --git a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb new file mode 100644 index 00000000000..9ac4d6ab165 --- /dev/null +++ b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb @@ -0,0 +1,155 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Discussions::ToggleResolve do + subject(:mutation) do + described_class.new(object: nil, context: { current_user: user }, field: nil) + end + + let_it_be(:project) { create(:project, :repository) } + + describe '#resolve' do + subject do + mutation.resolve({ id: id_arg, resolve: resolve_arg }) + end + + let(:id_arg) { discussion.to_global_id.to_s } + let(:resolve_arg) { true } + let(:mutated_discussion) { subject[:discussion] } + let(:errors) { subject[:errors] } + + shared_examples 'a working resolve method' do + context 'when the user does not have permission' do + let_it_be(:user) { create(:user) } + + it 'raises an error if the resource is not accessible to the user' do + expect { subject }.to raise_error( + Gitlab::Graphql::Errors::ResourceNotAvailable, + "The resource that you are attempting to access does not exist or you don't have permission to perform this action" + ) + end + end + + context 'when the user has permission' do + let_it_be(:user) { create(:user, developer_projects: [project]) } + + context 'when discussion cannot be found' do + let(:id_arg) { "#{discussion.to_global_id}foo" } + + it 'raises an error' do + expect { subject }.to raise_error( + Gitlab::Graphql::Errors::ResourceNotAvailable, + "The resource that you are attempting to access does not exist or you don't have permission to perform this action" + ) + end + end + + context 'when discussion is not a Discussion' do + let(:discussion) { create(:note, noteable: noteable, project: project) } + + it 'raises an error' do + expect { subject }.to raise_error( + Gitlab::Graphql::Errors::ArgumentError, + "#{discussion.to_global_id} is not a valid id for Discussion." + ) + end + end + + shared_examples 'returns a resolved discussion without errors' do + it 'returns a resolved discussion' do + expect(mutated_discussion).to be_resolved + end + + it 'returns empty errors' do + expect(errors).to be_empty + end + end + + shared_examples 'returns an unresolved discussion without errors' do + it 'returns an unresolved discussion' do + expect(mutated_discussion).not_to be_resolved + end + + it 'returns empty errors' do + expect(errors).to be_empty + end + end + + context 'when the `resolve` argument is true' do + include_examples 'returns a resolved discussion without errors' + + context 'when the discussion is already resolved' do + before do + discussion.resolve!(user) + end + + include_examples 'returns a resolved discussion without errors' + end + + context 'when the service raises an `ActiveRecord::RecordNotSaved` error' do + before do + allow_next_instance_of(::Discussions::ResolveService) do |service| + allow(service).to receive(:execute).and_raise(ActiveRecord::RecordNotSaved) + end + end + + it 'does not resolve the discussion' do + expect(mutated_discussion).not_to be_resolved + end + + it 'returns errors' do + expect(errors).to contain_exactly('Discussion failed to be resolved') + end + end + end + + context 'when the `resolve` argument is false' do + let(:resolve_arg) { false } + + context 'when the discussion is resolved' do + before do + discussion.resolve!(user) + end + + include_examples 'returns an unresolved discussion without errors' + + context 'when the service raises an `ActiveRecord::RecordNotSaved` error' do + before do + allow_next_instance_of(discussion.class) do |instance| + allow(instance).to receive(:unresolve!).and_raise(ActiveRecord::RecordNotSaved) + end + end + + it 'does not unresolve the discussion' do + expect(mutated_discussion).to be_resolved + end + + it 'returns errors' do + expect(errors).to contain_exactly('Discussion failed to be unresolved') + end + end + end + + context 'when the discussion is already unresolved' do + include_examples 'returns an unresolved discussion without errors' + end + end + end + end + + context 'when discussion is on a merge request' do + let_it_be(:noteable) { create(:merge_request, source_project: project) } + let(:discussion) { create(:diff_note_on_merge_request, noteable: noteable, project: project).to_discussion } + + it_behaves_like 'a working resolve method' + end + + context 'when discussion is on a design' do + let_it_be(:noteable) { create(:design, :with_file, issue: create(:issue, project: project)) } + let(:discussion) { create(:diff_note_on_design, noteable: noteable, project: project).to_discussion } + + it_behaves_like 'a working resolve method' + end + end +end diff --git a/spec/graphql/mutations/issues/set_confidential_spec.rb b/spec/graphql/mutations/issues/set_confidential_spec.rb index c90ce2658d6..820f9aa5e17 100644 --- a/spec/graphql/mutations/issues/set_confidential_spec.rb +++ b/spec/graphql/mutations/issues/set_confidential_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Mutations::Issues::SetConfidential do +RSpec.describe Mutations::Issues::SetConfidential do let(:issue) { create(:issue) } let(:user) { create(:user) } diff --git a/spec/graphql/mutations/issues/set_due_date_spec.rb b/spec/graphql/mutations/issues/set_due_date_spec.rb index 84df6fce7c7..a638971d966 100644 --- a/spec/graphql/mutations/issues/set_due_date_spec.rb +++ b/spec/graphql/mutations/issues/set_due_date_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Mutations::Issues::SetDueDate do +RSpec.describe Mutations::Issues::SetDueDate do let(:issue) { create(:issue) } let(:user) { create(:user) } diff --git a/spec/graphql/mutations/merge_requests/create_spec.rb b/spec/graphql/mutations/merge_requests/create_spec.rb new file mode 100644 index 00000000000..88acd3ed5b6 --- /dev/null +++ b/spec/graphql/mutations/merge_requests/create_spec.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Mutations::MergeRequests::Create do + subject(:mutation) { described_class.new(object: nil, context: context, field: nil) } + + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:user) { create(:user) } + let_it_be(:context) do + GraphQL::Query::Context.new( + query: OpenStruct.new(schema: nil), + values: { current_user: user }, + object: nil + ) + end + + describe '#resolve' do + subject do + mutation.resolve( + project_path: project.full_path, + title: title, + source_branch: source_branch, + target_branch: target_branch, + description: description + ) + end + + let(:title) { 'MergeRequest' } + let(:source_branch) { 'feature' } + let(:target_branch) { 'master' } + let(:description) { nil } + + let(:mutated_merge_request) { subject[:merge_request] } + + 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 user does not have enough permissions to create a merge request' do + before do + project.add_guest(user) + 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 + end + + context 'when the user can create a merge request' do + before_all do + project.add_developer(user) + end + + it 'creates a new merge request' do + expect { mutated_merge_request }.to change(MergeRequest, :count).by(1) + end + + it 'returns a new merge request' do + expect(mutated_merge_request.title).to eq(title) + expect(subject[:errors]).to be_empty + end + + context 'when optional description field is set' do + let(:description) { 'content' } + + it 'returns a new merge request with a description' do + expect(mutated_merge_request.description).to eq(description) + expect(subject[:errors]).to be_empty + end + end + + context 'when service cannot create a merge request' do + let(:title) { nil } + + it 'does not create a new merge request' do + expect { mutated_merge_request }.not_to change(MergeRequest, :count) + end + + it 'returns errors' do + expect(mutated_merge_request).to be_nil + expect(subject[:errors]).to eq(['Title can\'t be blank']) + end + end + end + end +end |