diff options
Diffstat (limited to 'spec/requests/api/graphql/mutations')
14 files changed, 391 insertions, 64 deletions
diff --git a/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb b/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb new file mode 100644 index 00000000000..e24ab0b07f2 --- /dev/null +++ b/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Reposition and move issue within board lists' do + include GraphqlHelpers + + let_it_be(:group) { create(:group, :private) } + 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(: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(: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_it_be(:issue1) { create(:labeled_issue, project: project, labels: [development]) } + + let(:mutation_class) { Mutations::Boards::Issues::IssueMoveList } + let(:mutation_name) { mutation_class.graphql_name } + let(:mutation_result_identifier) { mutation_name.camelize(:lower) } + let(:current_user) { user } + let(:params) { { board_id: board.to_global_id.to_s, project_path: project.full_path, iid: issue1.iid.to_s } } + let(:issue_move_params) do + { + from_list_id: list1.id, + to_list_id: list2.id + } + end + + before_all do + group.add_maintainer(user) + end + + shared_examples 'returns an error' do + it 'fails with error' do + message = "The resource that you are attempting to access does not exist or you don't have "\ + "permission to perform this action" + + post_graphql_mutation(mutation(params), current_user: current_user) + + expect(graphql_errors).to include(a_hash_including('message' => message)) + end + end + + context 'when user has access to resources' do + context 'when repositioning an issue' do + let(:issue_move_params) { { move_after_id: existing_issue1.id, move_before_id: existing_issue2.id } } + + it 'repositions an issue' do + post_graphql_mutation(mutation(params), current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + response_issue = json_response['data'][mutation_result_identifier]['issue'] + expect(response_issue['iid']).to eq(issue1.iid.to_s) + expect(response_issue['relativePosition']).to be > existing_issue1.relative_position + expect(response_issue['relativePosition']).to be < existing_issue2.relative_position + end + end + + context 'when moving an issue to a different list' do + let(:issue_move_params) { { from_list_id: list1.id, to_list_id: list2.id } } + + it 'moves issue to a different list' do + post_graphql_mutation(mutation(params), current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + response_issue = json_response['data'][mutation_result_identifier]['issue'] + expect(response_issue['iid']).to eq(issue1.iid.to_s) + expect(response_issue['labels']['edges'][0]['node']['title']).to eq(testing.title) + end + end + end + + context 'when user has no access to resources' do + context 'the user is not allowed to update the issue' do + let(:current_user) { create(:user) } + + it_behaves_like 'returns an error' + end + + context 'when the user can not read board' do + let(:board) { create(:board, group: create(:group, :private)) } + + it_behaves_like 'returns an error' + end + end + + def mutation(additional_params = {}) + graphql_mutation(mutation_name, issue_move_params.merge(additional_params), + <<-QL.strip_heredoc + clientMutationId + issue { + iid, + relativePosition + labels { + edges { + node{ + title + } + } + } + } + errors + QL + ) + end +end diff --git a/spec/requests/api/graphql/mutations/boards/lists/update_spec.rb b/spec/requests/api/graphql/mutations/boards/lists/update_spec.rb new file mode 100644 index 00000000000..8a6d2cb3994 --- /dev/null +++ b/spec/requests/api/graphql/mutations/boards/lists/update_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Update of an existing board list' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:group) { create(:group, :private) } + let_it_be(:board) { create(:board, group: group) } + let_it_be(:list) { create(:list, board: board, position: 0) } + let_it_be(:list2) { create(:list, board: board) } + let_it_be(:input) { { list_id: list.to_global_id.to_s, position: 1, collapsed: true } } + let(:mutation) { graphql_mutation(:update_board_list, input) } + let(:mutation_response) { graphql_mutation_response(:update_board_list) } + + context 'the user is not allowed to read board lists' do + it_behaves_like 'a mutation that returns top-level errors', + errors: ['The resource that you are attempting to access does not exist or you don\'t have permission to perform this action'] + end + + before do + list.update_preferences_for(current_user, collapsed: false) + end + + context 'when user has permissions to admin board lists' do + before do + group.add_reporter(current_user) + end + + it 'updates the list position and collapsed state' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['list']).to include( + 'position' => 1, + 'collapsed' => true + ) + end + end + + context 'when user has permissions to read board lists' do + before do + group.add_guest(current_user) + end + + it 'updates the list collapsed state but not the list position' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['list']).to include( + 'position' => 0, + 'collapsed' => true + ) + end + 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 bc1b42d68e6..7bef812bfec 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 @@ -18,6 +18,7 @@ RSpec.describe 'Updating the container expiration policy' do older_than: 'FOURTEEN_DAYS' } end + let(:mutation) do graphql_mutation(:update_container_expiration_policy, params, <<~QL @@ -32,6 +33,7 @@ RSpec.describe 'Updating the container expiration policy' do QL ) end + let(:mutation_response) { graphql_mutation_response(:update_container_expiration_policy) } let(:container_expiration_policy_response) { mutation_response['containerExpirationPolicy'] } diff --git a/spec/requests/api/graphql/mutations/design_management/move_spec.rb b/spec/requests/api/graphql/mutations/design_management/move_spec.rb new file mode 100644 index 00000000000..dd121ec733e --- /dev/null +++ b/spec/requests/api/graphql/mutations/design_management/move_spec.rb @@ -0,0 +1,122 @@ +# frozen_string_literal: true +require "spec_helper" + +RSpec.describe "moving designs" do + include GraphqlHelpers + include DesignManagementTestHelpers + + let_it_be(:issue) { create(:issue) } + let_it_be(:designs) { create_list(:design, 3, :with_versions, :with_relative_position, issue: issue) } + let_it_be(:developer) { create(:user, developer_projects: [issue.project]) } + + let(:user) { developer } + + let(:current_design) { designs.first } + let(:previous_design) { designs.second } + let(:next_design) { designs.third } + let(:mutation_name) { :design_management_move } + + let(:mutation) do + input = { + id: current_design.to_global_id.to_s, + previous: previous_design&.to_global_id&.to_s, + next: next_design&.to_global_id&.to_s + }.compact + + graphql_mutation(mutation_name, input, <<~FIELDS) + errors + designCollection { + designs { + nodes { + filename + } + } + } + FIELDS + end + + let(:move_designs) { post_graphql_mutation(mutation, current_user: user) } + let(:mutation_response) { graphql_mutation_response(mutation_name) } + + before do + enable_design_management + designs.each(&:reset) + issue.reset + end + + shared_examples 'a successful move' do + it 'does not error, and reports the current order' do + move_designs + + expect(graphql_errors).not_to be_present + + expect(mutation_response).to eq( + 'errors' => [], + 'designCollection' => { + 'designs' => { + 'nodes' => new_order.map { |d| { 'filename' => d.filename } } + } + } + ) + end + end + + context 'the user is not allowed to move designs' do + let(:user) { create(:user) } + + it 'returns an error' do + move_designs + + expect(graphql_errors).to be_present + end + end + + context 'the neighbors do not have positions' do + let!(:previous_design) { create(:design, :with_versions, issue: issue) } + let!(:next_design) { create(:design, :with_versions, issue: issue) } + + let(:new_order) do + [ + designs.second, + designs.third, + previous_design, current_design, next_design + ] + end + + it_behaves_like 'a successful move' + + it 'maintains the correct order in the presence of other unpositioned designs' do + other_design = create(:design, :with_versions, issue: issue) + + move_designs + moved_designs = mutation_response.dig('designCollection', 'designs', 'nodes') + + expect(moved_designs.map { |d| d['filename'] }) + .to eq([*new_order.map(&:filename), other_design.filename]) + end + end + + context 'moving a design between two others' do + let(:new_order) { [designs.second, designs.first, designs.third] } + + it_behaves_like 'a successful move' + end + + context 'moving a design to the start' do + let(:current_design) { designs.last } + let(:next_design) { designs.first } + let(:previous_design) { nil } + let(:new_order) { [designs.last, designs.first, designs.second] } + + it_behaves_like 'a successful move' + end + + context 'moving a design to the end' do + let(:current_design) { designs.first } + let(:next_design) { nil } + let(:previous_design) { designs.last } + let(:new_order) { [designs.second, designs.third, designs.first] } + + it_behaves_like 'a successful move' + end +end diff --git a/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb b/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb index e83da830935..457c37e900b 100644 --- a/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb +++ b/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb @@ -10,9 +10,11 @@ RSpec.describe 'Toggling the resolve status of a discussion' do let(:discussion) do create(:diff_note_on_merge_request, noteable: noteable, project: project).to_discussion end + let(:mutation) do graphql_mutation(:discussion_toggle_resolve, { id: discussion.to_global_id.to_s, resolve: true }) end + let(:mutation_response) { graphql_mutation_response(:discussion_toggle_resolve) } context 'when the user does not have permission' do diff --git a/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb b/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb index 3dd1225db5a..b3c9b9d4995 100644 --- a/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb +++ b/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb @@ -49,13 +49,13 @@ RSpec.describe 'Setting Due Date of an issue' do expect(mutation_response['issue']['dueDate']).to eq(2.days.since.to_date.to_s) end - context 'when passing due date without a date value' do + context 'when the due date value is not a valid time' do let(:input) { { due_date: 'test' } } - it 'returns internal server error' do + it 'returns a coercion error' do post_graphql_mutation(mutation, current_user: current_user) - expect(graphql_errors).to include(a_hash_including('message' => 'Internal server error')) + expect(graphql_errors).to include(a_hash_including('message' => /provided invalid value for dueDate/)) end end end diff --git a/spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb b/spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb new file mode 100644 index 00000000000..1edc1e0553b --- /dev/null +++ b/spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Setting subscribed status of an issue' do + include GraphqlHelpers + + it_behaves_like 'a subscribable resource api' do + let_it_be(:resource) { create(:issue) } + let(:mutation_name) { :issue_set_subscription } + end +end diff --git a/spec/requests/api/graphql/mutations/issues/update_spec.rb b/spec/requests/api/graphql/mutations/issues/update_spec.rb new file mode 100644 index 00000000000..fd983c683be --- /dev/null +++ b/spec/requests/api/graphql/mutations/issues/update_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Update of an existing issue' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let(:input) do + { + project_path: project.full_path, + iid: issue.iid.to_s, + locked: true + } + end + + let(:mutation) { graphql_mutation(:update_issue, input) } + let(:mutation_response) { graphql_mutation_response(:update_issue) } + + context 'the user is not allowed to update issue' do + it_behaves_like 'a mutation that returns top-level errors', + errors: ['The resource that you are attempting to access does not exist or you don\'t have permission to perform this action'] + end + + context 'when user has permissions to update issue' do + before do + project.add_developer(current_user) + end + + it 'updates the issue' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['issue']).to include( + 'discussionLocked' => true + ) + end + end +end diff --git a/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb index d4ac639e226..9297ca054c7 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb @@ -15,6 +15,7 @@ RSpec.describe 'Creation of a new merge request' do target_branch: target_branch } end + let(:title) { 'MergeRequest' } let(:source_branch) { 'new_branch' } let(:target_branch) { 'master' } diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb index 6b3035fbf48..d90faa605c0 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb @@ -5,59 +5,8 @@ require 'spec_helper' RSpec.describe 'Setting subscribed status of a merge request' do include GraphqlHelpers - let(:current_user) { create(:user) } - let(:merge_request) { create(:merge_request) } - let(:project) { merge_request.project } - let(:input) { { subscribed_state: true } } - - let(:mutation) do - variables = { - project_path: project.full_path, - iid: merge_request.iid.to_s - } - graphql_mutation(:merge_request_set_subscription, variables.merge(input), - <<-QL.strip_heredoc - clientMutationId - errors - mergeRequest { - id - subscribed - } - QL - ) - end - - def mutation_response - graphql_mutation_response(:merge_request_set_subscription)['mergeRequest']['subscribed'] - end - - before do - project.add_developer(current_user) - end - - it 'returns an error if the user is not allowed to update the merge request' do - post_graphql_mutation(mutation, current_user: create(:user)) - - expect(graphql_errors).not_to be_empty - end - - it 'marks the merge request as WIP' do - post_graphql_mutation(mutation, current_user: current_user) - - expect(response).to have_gitlab_http_status(:success) - expect(mutation_response).to eq(true) - end - - context 'when passing subscribe false as input' do - let(:input) { { subscribed_state: false } } - - it 'unmarks the merge request as subscribed' do - merge_request.subscribe(current_user, project) - - post_graphql_mutation(mutation, current_user: current_user) - - expect(response).to have_gitlab_http_status(:success) - expect(mutation_response).to eq(false) - end + it_behaves_like 'a subscribable resource api' do + let_it_be(:resource) { create(:merge_request) } + let(:mutation_name) { :merge_request_set_subscription } end end diff --git a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb index f7be671e5f3..463a872d95d 100644 --- a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb +++ b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb @@ -33,6 +33,7 @@ RSpec.describe 'Updating an image DiffNote' do y: updated_y } end + let!(:diff_note) do create(:image_diff_note_on_merge_request, noteable: noteable, @@ -40,6 +41,7 @@ RSpec.describe 'Updating an image DiffNote' do note: original_body, position: original_position) end + let(:mutation) do variables = { id: GitlabSchema.id_from_object(diff_note).to_s, diff --git a/spec/requests/api/graphql/mutations/notes/update/note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/note_spec.rb index 38378310d9f..0d93afe9434 100644 --- a/spec/requests/api/graphql/mutations/notes/update/note_spec.rb +++ b/spec/requests/api/graphql/mutations/notes/update/note_spec.rb @@ -8,11 +8,9 @@ RSpec.describe 'Updating a Note' do let!(:note) { create(:note, note: original_body) } let(:original_body) { 'Initial body text' } let(:updated_body) { 'Updated body text' } + let(:params) { { body: updated_body, confidential: true } } let(:mutation) do - variables = { - id: GitlabSchema.id_from_object(note).to_s, - body: updated_body - } + variables = params.merge(id: GitlabSchema.id_from_object(note).to_s) graphql_mutation(:update_note, variables) end @@ -31,6 +29,7 @@ RSpec.describe 'Updating a Note' do post_graphql_mutation(mutation, current_user: current_user) expect(note.reload.note).to eq(original_body) + expect(note.confidential).to be_falsey end end @@ -43,12 +42,40 @@ RSpec.describe 'Updating a Note' do post_graphql_mutation(mutation, current_user: current_user) expect(note.reload.note).to eq(updated_body) + expect(note.confidential).to be_truthy end it 'returns the updated Note' do post_graphql_mutation(mutation, current_user: current_user) expect(mutation_response['note']['body']).to eq(updated_body) + expect(mutation_response['note']['confidential']).to be_truthy + end + + context 'when only confidential param is present' do + let(:params) { { confidential: true } } + + it 'updates only the note confidentiality' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(note.reload.note).to eq(original_body) + expect(note.confidential).to be_truthy + end + end + + context 'when only body param is present' do + let(:params) { { body: updated_body } } + + before do + note.update_column(:confidential, true) + end + + it 'updates only the note body' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(note.reload.note).to eq(updated_body) + expect(note.confidential).to be_truthy + end end context 'when there are ActiveRecord validation errors' do @@ -60,12 +87,14 @@ RSpec.describe 'Updating a Note' do post_graphql_mutation(mutation, current_user: current_user) expect(note.reload.note).to eq(original_body) + expect(note.confidential).to be_falsey end - it 'returns the Note with its original body' do + it 'returns the original Note' do post_graphql_mutation(mutation, current_user: current_user) expect(mutation_response['note']['body']).to eq(original_body) + expect(mutation_response['note']['confidential']).to be_falsey end end diff --git a/spec/requests/api/graphql/mutations/snippets/create_spec.rb b/spec/requests/api/graphql/mutations/snippets/create_spec.rb index e2474e1bcce..56a5f4907c1 100644 --- a/spec/requests/api/graphql/mutations/snippets/create_spec.rb +++ b/spec/requests/api/graphql/mutations/snippets/create_spec.rb @@ -149,7 +149,7 @@ RSpec.describe 'Creating a Snippet' do visibility_level: visibility_level, project_path: project_path, title: title, - files: actions + blob_actions: actions } end diff --git a/spec/requests/api/graphql/mutations/snippets/update_spec.rb b/spec/requests/api/graphql/mutations/snippets/update_spec.rb index 3b2f9dc0f19..3f39c0ab851 100644 --- a/spec/requests/api/graphql/mutations/snippets/update_spec.rb +++ b/spec/requests/api/graphql/mutations/snippets/update_spec.rb @@ -26,6 +26,7 @@ RSpec.describe 'Updating a Snippet' do title: updated_title } end + let(:mutation) do graphql_mutation(:update_snippet, mutation_vars) end @@ -157,7 +158,7 @@ RSpec.describe 'Updating a Snippet' do let(:mutation_vars) do { id: snippet_gid, - files: [ + blob_actions: [ { action: :update, filePath: updated_file, content: updated_content }, { action: :delete, filePath: deleted_file } ] |