diff options
Diffstat (limited to 'spec/requests/api/graphql/mutations')
20 files changed, 596 insertions, 38 deletions
diff --git a/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb index 30e7f196542..394d9ff53d1 100644 --- a/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb +++ b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'CiCdSettingsUpdate' do +RSpec.describe 'ProjectCiCdSettingsUpdate' do include GraphqlHelpers let_it_be(:project) do diff --git a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb index 12368e7e9c5..6818ba33e74 100644 --- a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb +++ b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb @@ -64,11 +64,10 @@ RSpec.describe 'RunnersRegistrationTokenReset' do context 'applied to project' do let_it_be(:project) { create_default(:project) } + let(:target) { project } let(:input) { { type: 'PROJECT_TYPE', id: project.to_global_id.to_s } } - include_context 'when unauthorized', 'project' do - let(:target) { project } - end + include_context('when unauthorized', 'project') include_context 'when authorized', 'project' do let_it_be(:user) { project.first_owner } @@ -82,11 +81,10 @@ RSpec.describe 'RunnersRegistrationTokenReset' do context 'applied to group' do let_it_be(:group) { create_default(:group) } + let(:target) { group } let(:input) { { type: 'GROUP_TYPE', id: group.to_global_id.to_s } } - include_context 'when unauthorized', 'group' do - let(:target) { group } - end + include_context('when unauthorized', 'group') include_context 'when authorized', 'group' do let_it_be(:user) { create_default(:group_member, :owner, user: create(:user), group: group ).user } @@ -99,10 +97,12 @@ RSpec.describe 'RunnersRegistrationTokenReset' do context 'applied to instance' do before do - ApplicationSetting.create_from_defaults + target stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') end + let_it_be(:target) { ApplicationSetting.create_from_defaults } + let(:input) { { type: 'INSTANCE_TYPE' } } context 'when unauthorized' do diff --git a/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb b/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb index 5f6822223ca..4891e64aab8 100644 --- a/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb +++ b/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb @@ -26,7 +26,7 @@ RSpec.describe 'Delete a cluster agent' do 'or you don\'t have permission to perform this action'] it 'does not delete cluster agent' do - expect { cluster_agent.reload }.not_to raise_error(ActiveRecord::RecordNotFound) + expect { cluster_agent.reload }.not_to raise_error end end diff --git a/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb b/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb index 0156142dc6f..ca7c1b2ce5f 100644 --- a/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb +++ b/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb @@ -135,7 +135,7 @@ RSpec.describe 'Updating the container expiration policy' do context 'with existing container expiration policy' do where(:user_role, :shared_examples_name) do :maintainer | 'accepting the mutation request updating the container expiration policy' - :developer | 'accepting the mutation request updating the container expiration policy' + :developer | 'denying the mutation request' :reporter | 'denying the mutation request' :guest | 'denying the mutation request' :anonymous | 'denying the mutation request' @@ -155,7 +155,7 @@ RSpec.describe 'Updating the container expiration policy' do where(:user_role, :shared_examples_name) do :maintainer | 'accepting the mutation request creating the container expiration policy' - :developer | 'accepting the mutation request creating the container expiration policy' + :developer | 'denying the mutation request' :reporter | 'denying the mutation request' :guest | 'denying the mutation request' :anonymous | 'denying the mutation request' diff --git a/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb b/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb index f05bf23ad27..9eb13e534ac 100644 --- a/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb +++ b/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb @@ -50,7 +50,7 @@ RSpec.describe 'Updating the dependency proxy group settings' do context 'with permission' do before do - group.add_developer(user) + group.add_maintainer(user) end it 'returns the updated dependency proxy settings', :aggregate_failures do diff --git a/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb b/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb index c9e9a22ee0b..31ba7ecdf0e 100644 --- a/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb +++ b/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb @@ -52,7 +52,7 @@ RSpec.describe 'Updating the dependency proxy image ttl policy' do context 'with permission' do before do - group.add_developer(user) + group.add_maintainer(user) end it 'returns the updated dependency proxy image ttl policy', :aggregate_failures do diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb new file mode 100644 index 00000000000..3ea8b38e20f --- /dev/null +++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Creating an incident timeline event' do + include GraphqlHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:incident) { create(:incident, project: project) } + let_it_be(:event_occurred_at) { Time.current } + let_it_be(:note) { 'demo note' } + + let(:input) { { incident_id: incident.to_global_id.to_s, note: note, occurred_at: event_occurred_at } } + let(:mutation) do + graphql_mutation(:timeline_event_create, input) do + <<~QL + clientMutationId + errors + timelineEvent { + id + author { id username } + incident { id title } + note + editable + action + occurredAt + } + QL + end + end + + let(:mutation_response) { graphql_mutation_response(:timeline_event_create) } + + before do + project.add_developer(user) + end + + it 'creates incident timeline event', :aggregate_failures do + post_graphql_mutation(mutation, current_user: user) + + timeline_event_response = mutation_response['timelineEvent'] + + expect(response).to have_gitlab_http_status(:success) + expect(timeline_event_response).to include( + 'author' => { + 'id' => user.to_global_id.to_s, + 'username' => user.username + }, + 'incident' => { + 'id' => incident.to_global_id.to_s, + 'title' => incident.title + }, + 'note' => note, + 'action' => 'comment', + 'editable' => false, + 'occurredAt' => event_occurred_at.iso8601 + ) + end +end diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb new file mode 100644 index 00000000000..faff3bfe23a --- /dev/null +++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Removing an incident timeline event' do + include GraphqlHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:incident) { create(:incident, project: project) } + let_it_be(:timeline_event) { create(:incident_management_timeline_event, incident: incident, project: project) } + + let(:variables) { { id: timeline_event.to_global_id.to_s } } + + let(:mutation) do + graphql_mutation(:timeline_event_destroy, variables) do + <<~QL + clientMutationId + errors + timelineEvent { + id + author { id username } + incident { id title } + note + noteHtml + editable + action + occurredAt + createdAt + updatedAt + } + QL + end + end + + let(:mutation_response) { graphql_mutation_response(:timeline_event_destroy) } + + before do + project.add_developer(user) + end + + it 'removes incident timeline event', :aggregate_failures do + post_graphql_mutation(mutation, current_user: user) + + timeline_event_response = mutation_response['timelineEvent'] + + expect(response).to have_gitlab_http_status(:success) + expect(timeline_event_response).to include( + 'author' => { + 'id' => timeline_event.author.to_global_id.to_s, + 'username' => timeline_event.author.username + }, + 'incident' => { + 'id' => incident.to_global_id.to_s, + 'title' => incident.title + }, + 'note' => timeline_event.note, + 'noteHtml' => timeline_event.note_html, + 'editable' => false, + 'action' => timeline_event.action, + 'occurredAt' => timeline_event.occurred_at.iso8601, + 'createdAt' => timeline_event.created_at.iso8601, + 'updatedAt' => timeline_event.updated_at.iso8601 + ) + expect { timeline_event.reload }.to raise_error ActiveRecord::RecordNotFound + end +end diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb new file mode 100644 index 00000000000..b92f6af1d3d --- /dev/null +++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Promote an incident timeline event from a comment' do + include GraphqlHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:incident) { create(:incident, project: project) } + let_it_be(:comment) { create(:note, project: project, noteable: incident) } + + let(:input) { { note_id: comment.to_global_id.to_s } } + let(:mutation) do + graphql_mutation(:timeline_event_promote_from_note, input) do + <<~QL + clientMutationId + errors + timelineEvent { + author { id username } + incident { id title } + promotedFromNote { id } + note + action + editable + occurredAt + } + QL + end + end + + let(:mutation_response) { graphql_mutation_response(:timeline_event_promote_from_note) } + + before do + project.add_developer(user) + end + + it 'creates incident timeline event from the note', :aggregate_failures do + post_graphql_mutation(mutation, current_user: user) + + timeline_event_response = mutation_response['timelineEvent'] + + expect(response).to have_gitlab_http_status(:success) + expect(timeline_event_response).to include( + 'author' => { + 'id' => user.to_global_id.to_s, + 'username' => user.username + }, + 'incident' => { + 'id' => incident.to_global_id.to_s, + 'title' => incident.title + }, + 'promotedFromNote' => { + 'id' => comment.to_global_id.to_s + }, + 'note' => comment.note, + 'action' => 'comment', + 'editable' => false, + 'occurredAt' => comment.created_at.iso8601 + ) + end +end diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb new file mode 100644 index 00000000000..1c4439cec6f --- /dev/null +++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Updating an incident timeline event' do + include GraphqlHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:incident) { create(:incident, project: project) } + let_it_be_with_reload(:timeline_event) do + create(:incident_management_timeline_event, incident: incident, project: project) + end + + let(:occurred_at) { 1.minute.ago.iso8601 } + + let(:variables) do + { + id: timeline_event.to_global_id.to_s, + note: 'Updated note', + occurred_at: occurred_at + } + end + + let(:mutation) do + graphql_mutation(:timeline_event_update, variables) do + <<~QL + clientMutationId + errors + timelineEvent { + id + author { id username } + updatedByUser { id username } + incident { id title } + note + noteHtml + occurredAt + createdAt + updatedAt + } + QL + end + end + + let(:mutation_response) { graphql_mutation_response(:timeline_event_update) } + + before do + project.add_developer(user) + end + + it 'updates the timeline event', :aggregate_failures do + post_graphql_mutation(mutation, current_user: user) + + timeline_event_response = mutation_response['timelineEvent'] + + timeline_event.reload + + expect(response).to have_gitlab_http_status(:success) + expect(timeline_event_response).to include( + 'id' => timeline_event.to_global_id.to_s, + 'author' => { + 'id' => timeline_event.author.to_global_id.to_s, + 'username' => timeline_event.author.username + }, + 'updatedByUser' => { + 'id' => user.to_global_id.to_s, + 'username' => user.username + }, + 'incident' => { + 'id' => incident.to_global_id.to_s, + 'title' => incident.title + }, + 'note' => 'Updated note', + 'noteHtml' => timeline_event.note_html, + 'occurredAt' => occurred_at, + 'createdAt' => timeline_event.created_at.iso8601, + 'updatedAt' => timeline_event.updated_at.iso8601 + ) + end +end diff --git a/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb b/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb index 02b79dac489..715507c3cc5 100644 --- a/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb +++ b/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Setting issues crm contacts' do let(:operation_mode) { Types::MutationOperationModeEnum.default_mode } let(:initial_contacts) { contacts[0..1] } let(:mutation_contacts) { contacts[1..2] } - let(:contact_ids) { contact_global_ids(mutation_contacts) } + let(:contact_ids) { mutation_contacts.map { global_id_of(_1) } } let(:does_not_exist_or_no_permission) { "The resource that you are attempting to access does not exist or you don't have permission to perform this action" } let(:mutation) do @@ -45,8 +45,8 @@ RSpec.describe 'Setting issues crm contacts' do graphql_mutation_response(:issue_set_crm_contacts) end - def contact_global_ids(contacts) - contacts.map { |contact| global_id_of(contact) } + def expected_contacts(contacts) + contacts.map { |contact| a_graphql_entity_for(contact) } end before do @@ -58,8 +58,8 @@ RSpec.describe 'Setting issues crm contacts' do it 'updates the issue with correct contacts' do post_graphql_mutation(mutation, current_user: user) - expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes, :id)) - .to match_array(contact_global_ids(mutation_contacts)) + expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes)) + .to match_array(expected_contacts(mutation_contacts)) end end @@ -70,8 +70,8 @@ RSpec.describe 'Setting issues crm contacts' do it 'updates the issue with correct contacts' do post_graphql_mutation(mutation, current_user: user) - expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes, :id)) - .to match_array(contact_global_ids(initial_contacts + mutation_contacts)) + expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes)) + .to match_array(expected_contacts(initial_contacts + mutation_contacts)) end end @@ -82,8 +82,8 @@ RSpec.describe 'Setting issues crm contacts' do it 'updates the issue with correct contacts' do post_graphql_mutation(mutation, current_user: user) - expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes, :id)) - .to match_array(contact_global_ids(initial_contacts - mutation_contacts)) + expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes)) + .to match_array(expected_contacts(initial_contacts - mutation_contacts)) end end end @@ -117,7 +117,7 @@ RSpec.describe 'Setting issues crm contacts' do it_behaves_like 'successful mutation' context 'when the contact does not exist' do - let(:contact_ids) { ["gid://gitlab/CustomerRelations::Contact/#{non_existing_record_id}"] } + let(:contact_ids) { [global_id_of(model_name: 'CustomerRelations::Contact', id: non_existing_record_id)] } it 'returns expected error' do post_graphql_mutation(mutation, current_user: user) @@ -159,7 +159,7 @@ RSpec.describe 'Setting issues crm contacts' do context 'when trying to remove non-existent contact' do let(:operation_mode) { Types::MutationOperationModeEnum.enum[:remove] } - let(:contact_ids) { ["gid://gitlab/CustomerRelations::Contact/#{non_existing_record_id}"] } + let(:contact_ids) { [global_id_of(model_name: 'CustomerRelations::Contact', id: non_existing_record_id)] } it 'raises expected error' do post_graphql_mutation(mutation, current_user: user) diff --git a/spec/requests/api/graphql/mutations/merge_requests/request_attention_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/request_attention_spec.rb new file mode 100644 index 00000000000..9c751913827 --- /dev/null +++ b/spec/requests/api/graphql/mutations/merge_requests/request_attention_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Request attention' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:user) { create(:user) } + let_it_be(:merge_request) { create(:merge_request, reviewers: [user]) } + let_it_be(:project) { merge_request.project } + + let(:input) { { user_id: global_id_of(user) } } + + let(:mutation) do + variables = { + project_path: project.full_path, + iid: merge_request.iid.to_s + } + graphql_mutation(:merge_request_request_attention, variables.merge(input), + <<-QL.strip_heredoc + clientMutationId + errors + QL + ) + end + + def mutation_response + graphql_mutation_response(:merge_request_request_attention) + end + + def mutation_errors + mutation_response['errors'] + end + + before_all do + project.add_developer(current_user) + project.add_developer(user) + end + + it 'is successful' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_errors).to be_empty + end + + context 'when current user is not allowed to update the merge request' do + it 'returns an error' do + post_graphql_mutation(mutation, current_user: create(:user)) + + expect(graphql_errors).not_to be_empty + end + end + + context 'when user is not a reviewer' do + let(:input) { { user_id: global_id_of(create(:user)) } } + + it 'returns an error' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_errors).not_to be_empty + end + end + + context 'feature flag is disabled' do + before do + stub_feature_flags(mr_attention_requests: false) + end + + it 'returns an error' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(graphql_errors[0]["message"]).to eq "Feature disabled" + end + end +end diff --git a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb index d335642d321..194e42bf59d 100644 --- a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb +++ b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb @@ -109,7 +109,7 @@ RSpec.describe 'Updating the package settings' do where(:user_role, :shared_examples_name) do :maintainer | 'accepting the mutation request updating the package settings' - :developer | 'accepting the mutation request updating the package settings' + :developer | 'denying the mutation request' :reporter | 'denying the mutation request' :guest | 'denying the mutation request' :anonymous | 'denying the mutation request' @@ -131,7 +131,7 @@ RSpec.describe 'Updating the package settings' do where(:user_role, :shared_examples_name) do :maintainer | 'accepting the mutation request creating the package settings' - :developer | 'accepting the mutation request creating the package settings' + :developer | 'denying the mutation request' :reporter | 'denying the mutation request' :guest | 'denying the mutation request' :anonymous | 'denying the mutation request' diff --git a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb index 63b94dccca0..22b5f2d5112 100644 --- a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb +++ b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb @@ -64,7 +64,7 @@ RSpec.describe 'Adding a Note' do it 'creates a Note in a discussion' do post_graphql_mutation(mutation, current_user: current_user) - expect(mutation_response['note']['discussion']['id']).to eq(discussion.to_global_id.to_s) + expect(mutation_response['note']['discussion']).to match a_graphql_entity_for(discussion) end context 'when the discussion_id is not for a Discussion' do @@ -109,7 +109,7 @@ RSpec.describe 'Adding a Note' do post_graphql_mutation(mutation, current_user: current_user) expect(mutation_response).to include( - 'errors' => [/Merged this merge request/], + 'errors' => include(/Merged this merge request/), 'note' => nil ) end diff --git a/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb index 89e3a71280f..0f7ccac3179 100644 --- a/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb +++ b/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb @@ -39,7 +39,7 @@ RSpec.describe 'Repositioning an ImageDiffNote' do post_graphql_mutation(mutation, current_user: current_user) end.to change { note.reset.position.x }.to(10) - expect(mutation_response['note']).to eq('id' => global_id_of(note)) + expect(mutation_response['note']).to match a_graphql_entity_for(note) expect(mutation_response['errors']).to be_empty end @@ -59,7 +59,7 @@ RSpec.describe 'Repositioning an ImageDiffNote' do post_graphql_mutation(mutation, current_user: current_user) end.not_to change { note.reset.position.x } - expect(mutation_response['note']).to eq('id' => global_id_of(note)) + expect(mutation_response['note']).to match a_graphql_entity_for(note) expect(mutation_response['errors']).to be_empty end end diff --git a/spec/requests/api/graphql/mutations/remove_attention_request_spec.rb b/spec/requests/api/graphql/mutations/remove_attention_request_spec.rb new file mode 100644 index 00000000000..053559b039d --- /dev/null +++ b/spec/requests/api/graphql/mutations/remove_attention_request_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Remove attention request' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:user) { create(:user) } + let_it_be(:merge_request) { create(:merge_request, reviewers: [user]) } + let_it_be(:project) { merge_request.project } + + let(:input) { { user_id: global_id_of(user) } } + + let(:mutation) do + variables = { + project_path: project.full_path, + iid: merge_request.iid.to_s + } + graphql_mutation(:merge_request_remove_attention_request, variables.merge(input), + <<-QL.strip_heredoc + clientMutationId + errors + QL + ) + end + + def mutation_response + graphql_mutation_response(:merge_request_remove_attention_request) + end + + def mutation_errors + mutation_response['errors'] + end + + before_all do + project.add_developer(current_user) + project.add_developer(user) + end + + it 'is successful' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_errors).to be_empty + end + + context 'when current user is not allowed to update the merge request' do + it 'returns an error' do + post_graphql_mutation(mutation, current_user: create(:user)) + + expect(graphql_errors).not_to be_empty + end + end + + context 'when user is not a reviewer' do + let(:input) { { user_id: global_id_of(create(:user)) } } + + it 'returns an error' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_errors).not_to be_empty + end + end + + context 'feature flag is disabled' do + before do + stub_feature_flags(mr_attention_requests: false) + end + + it 'returns an error' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(graphql_errors[0]["message"]).to eq "Feature disabled" + end + end +end diff --git a/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb b/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb new file mode 100644 index 00000000000..b674e77f093 --- /dev/null +++ b/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Delete a timelog' do + include GraphqlHelpers + let_it_be(:author) { create(:user) } + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800)} + + let(:current_user) { nil } + let(:mutation) { graphql_mutation(:timelogDelete, { 'id' => timelog.to_global_id.to_s }) } + let(:mutation_response) { graphql_mutation_response(:timelog_delete) } + + context 'when the user is not allowed to delete a timelog' do + let(:current_user) { create(:user) } + + before do + post_graphql_mutation(mutation, current_user: current_user) + end + + it_behaves_like 'a mutation that returns a top-level access error' + end + + context 'when user has permissions to delete a timelog' do + let(:current_user) { author } + + it 'deletes the timelog' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + end.to change(Timelog, :count).by(-1) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['timelog']).to include('id' => timelog.to_global_id.to_s) + end + end +end diff --git a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb index c5c34e16717..dc20fde8e3c 100644 --- a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb +++ b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb @@ -46,8 +46,8 @@ RSpec.describe 'Marking all todos done' do expect(todo3.reload.state).to eq('done') expect(other_user_todo.reload.state).to eq('pending') - updated_todo_ids = mutation_response['todos'].map { |todo| todo['id'] } - expect(updated_todo_ids).to contain_exactly(global_id_of(todo1), global_id_of(todo3)) + updated_todos = mutation_response['todos'] + expect(updated_todos).to contain_exactly(a_graphql_entity_for(todo1), a_graphql_entity_for(todo3)) end context 'when target_id is given', :aggregate_failures do @@ -66,8 +66,8 @@ RSpec.describe 'Marking all todos done' do expect(todo1.reload.state).to eq('pending') expect(todo3.reload.state).to eq('pending') - updated_todo_ids = mutation_response['todos'].map { |todo| todo['id'] } - expect(updated_todo_ids).to contain_exactly(global_id_of(target_todo1), global_id_of(target_todo2)) + updated_todos = mutation_response['todos'] + expect(updated_todos).to contain_exactly(a_graphql_entity_for(target_todo1), a_graphql_entity_for(target_todo2)) end context 'when target does not exist' do diff --git a/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb index 70e3cc7f5cd..4316bd060c1 100644 --- a/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb +++ b/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb @@ -11,8 +11,8 @@ RSpec.describe 'Restoring many Todos' do let_it_be(:author) { create(:user) } let_it_be(:other_user) { create(:user) } - let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :done, target: issue) } - let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done, target: issue) } + let_it_be_with_reload(:todo1) { create(:todo, user: current_user, author: author, state: :done, target: issue) } + let_it_be_with_reload(:todo2) { create(:todo, user: current_user, author: author, state: :done, target: issue) } let_it_be(:other_user_todo) { create(:todo, user: other_user, author: author, state: :done) } @@ -50,8 +50,8 @@ RSpec.describe 'Restoring many Todos' do expect(mutation_response).to include( 'errors' => be_empty, 'todos' => contain_exactly( - { 'id' => global_id_of(todo1), 'state' => 'pending' }, - { 'id' => global_id_of(todo2), 'state' => 'pending' } + a_graphql_entity_for(todo1, 'state' => 'pending'), + a_graphql_entity_for(todo2, 'state' => 'pending') ) ) end diff --git a/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb b/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb new file mode 100644 index 00000000000..05d3587d342 --- /dev/null +++ b/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe "Delete a task in a work item's description" do + include GraphqlHelpers + + let_it_be(:project) { create(:project) } + let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } } + let_it_be(:task) { create(:work_item, :task, project: project, author: developer) } + let_it_be(:work_item, refind: true) do + create(:work_item, project: project, description: "- [ ] #{task.to_reference}+", lock_version: 3) + end + + before_all do + create(:issue_link, source_id: work_item.id, target_id: task.id) + end + + let(:lock_version) { work_item.lock_version } + let(:input) do + { + 'id' => work_item.to_global_id.to_s, + 'lockVersion' => lock_version, + 'taskData' => { + 'id' => task.to_global_id.to_s, + 'lineNumberStart' => 1, + 'lineNumberEnd' => 1 + } + } + end + + let(:mutation) { graphql_mutation(:workItemDeleteTask, input) } + let(:mutation_response) { graphql_mutation_response(:work_item_delete_task) } + + context 'the user is not allowed to update a work item' do + let(:current_user) { create(:user) } + + it_behaves_like 'a mutation that returns a top-level access error' + end + + context 'when user can update the description but not delete the task' do + let(:current_user) { create(:user).tap { |u| project.add_developer(u) } } + + it_behaves_like 'a mutation that returns a top-level access error' + end + + context 'when user has permissions to remove a task' do + let(:current_user) { developer } + + it 'removes the task from the work item' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + work_item.reload + end.to change(WorkItem, :count).by(-1).and( + change(IssueLink, :count).by(-1) + ).and( + change(work_item, :description).from("- [ ] #{task.to_reference}+").to('') + ) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['workItem']).to include('id' => work_item.to_global_id.to_s) + end + + context 'when removing the task fails' do + let(:lock_version) { 2 } + + it 'makes no changes to the DB and returns an error message' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + work_item.reload + end.to not_change(WorkItem, :count).and( + not_change(work_item, :description) + ) + + expect(mutation_response['errors']).to contain_exactly('Stale work item. Check lock version') + end + end + + context 'when the work_items feature flag is disabled' do + before do + stub_feature_flags(work_items: false) + end + + it 'does nothing and returns and error' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + end.to not_change(WorkItem, :count) + + expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project') + end + end + end +end |