diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-20 14:10:13 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-20 14:10:13 +0300 |
commit | 0ea3fcec397b69815975647f5e2aa5fe944a8486 (patch) | |
tree | 7979381b89d26011bcf9bdc989a40fcc2f1ed4ff /spec/requests/api/graphql/mutations | |
parent | 72123183a20411a36d607d70b12d57c484394c8e (diff) |
Add latest changes from gitlab-org/gitlab@15-1-stable-eev15.1.0-rc42
Diffstat (limited to 'spec/requests/api/graphql/mutations')
18 files changed, 435 insertions, 61 deletions
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb index 37656ab4eea..7abd5ca8772 100644 --- a/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb +++ b/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb @@ -28,4 +28,21 @@ RSpec.describe 'PipelineDestroy' do expect(response).to have_gitlab_http_status(:success) expect { pipeline.reload }.to raise_error(ActiveRecord::RecordNotFound) end + + context 'when project is undergoing stats refresh' do + before do + create(:project_build_artifacts_size_refresh, :pending, project: pipeline.project) + end + + it 'returns an error and does not destroy the pipeline' do + expect(Gitlab::ProjectStatsRefreshConflictsLogger) + .to receive(:warn_request_rejected_during_stats_refresh) + .with(pipeline.project.id) + + post_graphql_mutation(mutation, current_user: user) + + expect(graphql_mutation_response(:pipeline_destroy)['errors']).not_to be_empty + expect(pipeline.reload).to be_persisted + end + end end diff --git a/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb b/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb index decb2e7bccc..ef00f45ef18 100644 --- a/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb +++ b/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb @@ -91,7 +91,7 @@ RSpec.describe 'Destroying a container repository tags' do it 'returns too many tags error' do expect { subject }.not_to change { ::Packages::Event.count } - explanation = graphql_errors.dig(0, 'extensions', 'problems', 0, 'explanation') + explanation = graphql_errors.dig(0, 'message') expect(explanation).to eq(Mutations::ContainerRepositories::DestroyTags::TOO_MANY_TAGS_ERROR_MESSAGE) end end diff --git a/spec/requests/api/graphql/mutations/design_management/delete_spec.rb b/spec/requests/api/graphql/mutations/design_management/delete_spec.rb index 1f43f113e65..e2ab08b301b 100644 --- a/spec/requests/api/graphql/mutations/design_management/delete_spec.rb +++ b/spec/requests/api/graphql/mutations/design_management/delete_spec.rb @@ -47,7 +47,7 @@ RSpec.describe "deleting designs" do context 'the designs list is empty' do it_behaves_like 'a failed request' do let(:designs) { [] } - let(:the_error) { a_string_matching %r/was provided invalid value/ } + let(:the_error) { a_string_matching %r/no filenames/ } end end 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 index 3ea8b38e20f..923e12a3c06 100644 --- 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 @@ -53,7 +53,7 @@ RSpec.describe 'Creating an incident timeline event' do }, 'note' => note, 'action' => 'comment', - 'editable' => false, + 'editable' => true, 'occurredAt' => event_occurred_at.iso8601 ) 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 index faff3bfe23a..85208869ad9 100644 --- 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 @@ -56,7 +56,7 @@ RSpec.describe 'Removing an incident timeline event' do }, 'note' => timeline_event.note, 'noteHtml' => timeline_event.note_html, - 'editable' => false, + 'editable' => true, 'action' => timeline_event.action, 'occurredAt' => timeline_event.occurred_at.iso8601, 'createdAt' => timeline_event.created_at.iso8601, 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 index b92f6af1d3d..9272e218172 100644 --- 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 @@ -55,7 +55,7 @@ RSpec.describe 'Promote an incident timeline event from a comment' do }, 'note' => comment.note, 'action' => 'comment', - 'editable' => false, + 'editable' => true, 'occurredAt' => comment.created_at.iso8601 ) 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 715507c3cc5..395a490bfc3 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 @@ -102,18 +102,6 @@ RSpec.describe 'Setting issues crm contacts' do group.add_reporter(user) end - context 'when the feature is disabled' do - before do - stub_feature_flags(customer_relations: false) - end - - it 'raises expected error' do - post_graphql_mutation(mutation, current_user: user) - - expect(graphql_errors).to include(a_hash_including('message' => 'Feature disabled')) - end - end - it_behaves_like 'successful mutation' context 'when the contact does not exist' do diff --git a/spec/requests/api/graphql/mutations/issues/set_escalation_status_spec.rb b/spec/requests/api/graphql/mutations/issues/set_escalation_status_spec.rb index 0166871502b..a81364d37b2 100644 --- a/spec/requests/api/graphql/mutations/issues/set_escalation_status_spec.rb +++ b/spec/requests/api/graphql/mutations/issues/set_escalation_status_spec.rb @@ -49,14 +49,6 @@ RSpec.describe 'Setting the escalation status of an incident' do it_behaves_like 'a mutation that returns top-level errors', errors: ['Feature unavailable for provided issue'] end - context 'with feature disabled' do - before do - stub_feature_flags(incident_escalations: false) - end - - it_behaves_like 'a mutation that returns top-level errors', errors: ['Feature unavailable for provided issue'] - end - it 'sets given escalation_policy to the escalation status for the issue' do post_graphql_mutation(mutation, current_user: current_user) diff --git a/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb b/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb index 45cc70f09fd..b438e1ba881 100644 --- a/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb +++ b/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Importing Jira Users' do - include JiraServiceHelper + include JiraIntegrationHelpers include GraphqlHelpers let_it_be(:user) { create(:user) } diff --git a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb index b14305281af..1508ba31e37 100644 --- a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb +++ b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Starting a Jira Import' do - include JiraServiceHelper + include JiraIntegrationHelpers include GraphqlHelpers let_it_be(:user) { create(:user) } diff --git a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb index 5bc3c68cf26..9ef443af76a 100644 --- a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb +++ b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb @@ -76,7 +76,6 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do context 'when environment_id is missing' do let(:mutation) do variables = { - environment_id: nil, starting_at: starting_at, ending_at: ending_at, dashboard_path: dashboard_path, @@ -147,7 +146,6 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do context 'when cluster_id is missing' do let(:mutation) do variables = { - cluster_id: nil, starting_at: starting_at, ending_at: ending_at, dashboard_path: dashboard_path, 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 0f7ccac3179..c4674155aa0 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 @@ -68,15 +68,7 @@ RSpec.describe 'Repositioning an ImageDiffNote' do let(:new_position) { { x: nil } } it_behaves_like 'a mutation that returns top-level errors' do - let(:match_errors) { include(/RepositionImageDiffNoteInput! was provided invalid value/) } - end - - it 'contains an explanation for the error' do - post_graphql_mutation(mutation, current_user: current_user) - - explanation = graphql_errors.first['extensions']['problems'].first['explanation'] - - expect(explanation).to eq('At least one property of `UpdateDiffImagePositionInput` must be set') + let(:match_errors) { include(/At least one property of `UpdateDiffImagePositionInput` must be set/) } end end end diff --git a/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb b/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb new file mode 100644 index 00000000000..7e00f3ca53a --- /dev/null +++ b/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Updating the packages cleanup policy' do + include GraphqlHelpers + using RSpec::Parameterized::TableSyntax + + let_it_be(:project, reload: true) { create(:project) } + let_it_be(:user) { create(:user) } + + let(:params) do + { + project_path: project.full_path, + keep_n_duplicated_package_files: 'TWENTY_PACKAGE_FILES' + } + end + + let(:mutation) do + graphql_mutation(:update_packages_cleanup_policy, params, + <<~QUERY + packagesCleanupPolicy { + keepNDuplicatedPackageFiles + nextRunAt + } + errors + QUERY + ) + end + + let(:mutation_response) { graphql_mutation_response(:update_packages_cleanup_policy) } + let(:packages_cleanup_policy_response) { mutation_response['packagesCleanupPolicy'] } + + shared_examples 'accepting the mutation request and updates the existing policy' do + it 'returns the updated packages cleanup policy' do + expect { subject }.not_to change { ::Packages::Cleanup::Policy.count } + + expect(project.packages_cleanup_policy.keep_n_duplicated_package_files).to eq('20') + expect_graphql_errors_to_be_empty + expect(packages_cleanup_policy_response['keepNDuplicatedPackageFiles']) + .to eq(params[:keep_n_duplicated_package_files]) + expect(packages_cleanup_policy_response['nextRunAt']).not_to eq(nil) + end + end + + shared_examples 'accepting the mutation request and creates a policy' do + it 'returns the created packages cleanup policy' do + expect { subject }.to change { ::Packages::Cleanup::Policy.count }.by(1) + + expect(project.packages_cleanup_policy.keep_n_duplicated_package_files).to eq('20') + expect_graphql_errors_to_be_empty + expect(packages_cleanup_policy_response['keepNDuplicatedPackageFiles']) + .to eq(params[:keep_n_duplicated_package_files]) + expect(packages_cleanup_policy_response['nextRunAt']).not_to eq(nil) + end + end + + shared_examples 'denying the mutation request' do + it 'returns an error' do + expect { subject }.not_to change { ::Packages::Cleanup::Policy.count } + + expect(project.packages_cleanup_policy.keep_n_duplicated_package_files).not_to eq('20') + expect(mutation_response).to be_nil + expect_graphql_errors_to_include(/you don't have permission to perform this action/) + end + end + + describe 'post graphql mutation' do + subject { post_graphql_mutation(mutation, current_user: user) } + + context 'with existing packages cleanup policy' do + let_it_be(:project_packages_cleanup_policy) { create(:packages_cleanup_policy, project: project) } + + where(:user_role, :shared_examples_name) do + :maintainer | 'accepting the mutation request and updates the existing policy' + :developer | 'denying the mutation request' + :reporter | 'denying the mutation request' + :guest | 'denying the mutation request' + :anonymous | 'denying the mutation request' + 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 packages cleanup policy' do + where(:user_role, :shared_examples_name) do + :maintainer | 'accepting the mutation request and creates a policy' + :developer | 'denying the mutation request' + :reporter | 'denying the mutation request' + :guest | 'denying the mutation request' + :anonymous | 'denying the mutation request' + 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/requests/api/graphql/mutations/packages/destroy_files_spec.rb b/spec/requests/api/graphql/mutations/packages/destroy_files_spec.rb new file mode 100644 index 00000000000..002cd634ebd --- /dev/null +++ b/spec/requests/api/graphql/mutations/packages/destroy_files_spec.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Destroying multiple package files' do + using RSpec::Parameterized::TableSyntax + + include GraphqlHelpers + + let_it_be_with_reload(:package) { create(:maven_package) } + let_it_be(:user) { create(:user) } + let_it_be(:project) { package.project } + + let(:ids) { package.package_files.first(2).map { |pf| pf.to_global_id.to_s } } + + let(:query) do + <<~GQL + errors + GQL + end + + let(:params) do + { + project_path: project.full_path, + ids: ids + } + end + + let(:mutation) { graphql_mutation(:destroy_package_files, params, query) } + + describe 'post graphql mutation' do + subject(:mutation_request) { post_graphql_mutation(mutation, current_user: user) } + + shared_examples 'destroying the package files' do + it 'marks the package file as pending destruction' do + expect { mutation_request }.to change { ::Packages::PackageFile.pending_destruction.count }.by(2) + end + + it_behaves_like 'returning response status', :success + end + + shared_examples 'denying the mutation request' do |response = "you don't have permission to perform this action"| + it 'does not mark the package file as pending destruction' do + expect { mutation_request }.not_to change { ::Packages::PackageFile.pending_destruction.count } + + expect_graphql_errors_to_include(response) + end + + it_behaves_like 'returning response status', :success + end + + context 'with valid params' do + where(:user_role, :shared_examples_name) do + :maintainer | 'destroying the package files' + :developer | 'denying the mutation request' + :reporter | 'denying the mutation request' + :guest | 'denying the mutation request' + :anonymous | 'denying the mutation request' + 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 + + context 'with more than 100 files' do + let(:ids) { package.package_files.map { |pf| pf.to_global_id.to_s } } + + before do + project.add_maintainer(user) + create_list(:package_file, 99, package: package) + end + + it_behaves_like 'denying the mutation request', 'Cannot delete more than 100 files' + end + + context 'with files outside of the project' do + let_it_be(:package2) { create(:maven_package) } + + let(:ids) { super().push(package2.package_files.first.to_global_id.to_s) } + + before do + project.add_maintainer(user) + end + + it_behaves_like 'denying the mutation request', 'All files must be in the requested project' + end + end + + context 'with invalid params' do + let(:params) { { id: 'foo' } } + + before do + project.add_maintainer(user) + end + + it_behaves_like 'denying the mutation request', 'invalid value for id' + end + end +end diff --git a/spec/requests/api/graphql/mutations/releases/create_spec.rb b/spec/requests/api/graphql/mutations/releases/create_spec.rb index 86995c10f10..1e62942c29d 100644 --- a/spec/requests/api/graphql/mutations/releases/create_spec.rb +++ b/spec/requests/api/graphql/mutations/releases/create_spec.rb @@ -17,6 +17,7 @@ RSpec.describe 'Creation of a new release' do let(:mutation_name) { :release_create } let(:tag_name) { 'v7.12.5'} + let(:tag_message) { nil } let(:ref) { 'master'} let(:name) { 'Version 7.12.5'} let(:description) { 'Release 7.12.5 :rocket:' } @@ -29,6 +30,7 @@ RSpec.describe 'Creation of a new release' do { projectPath: project.full_path, tagName: tag_name, + tagMessage: tag_message, ref: ref, name: name, description: description, @@ -191,10 +193,26 @@ RSpec.describe 'Creation of a new release' do context 'when the provided tag does not already exist' do let(:tag_name) { 'v7.12.5-alpha' } + after do + project.repository.rm_tag(developer, tag_name) + end + it_behaves_like 'no errors' - it 'creates a new tag' do + it 'creates a new lightweight tag' do expect { create_release }.to change { Project.find_by_id(project.id).repository.tag_count }.by(1) + expect(project.repository.find_tag(tag_name).message).to be_blank + end + + context 'and tag_message is provided' do + let(:tag_message) { 'Annotated tag message' } + + it_behaves_like 'no errors' + + it 'creates a new annotated tag with the message' do + expect { create_release }.to change { Project.find_by_id(project.id).repository.tag_count }.by(1) + expect(project.repository.find_tag(tag_name).message).to eq(tag_message) + end end end diff --git a/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb b/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb index 85194e6eb20..e1c7fd9d60d 100644 --- a/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb +++ b/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb @@ -28,17 +28,6 @@ RSpec.describe Mutations::UserPreferences::Update do expect(current_user.user_preference.persisted?).to eq(true) expect(current_user.user_preference.issues_sort).to eq(Types::IssueSortEnum.values[sort_value].value.to_s) end - - context 'when incident_escalations feature flag is disabled' do - let(:sort_value) { 'ESCALATION_STATUS_ASC' } - - before do - stub_feature_flags(incident_escalations: false) - end - - it_behaves_like 'a mutation that returns top-level errors', - errors: ['Feature flag `incident_escalations` must be enabled to use this sort order.'] - end end context 'when user has existing preference' do @@ -56,16 +45,5 @@ RSpec.describe Mutations::UserPreferences::Update do expect(current_user.user_preference.issues_sort).to eq(Types::IssueSortEnum.values[sort_value].value.to_s) end - - context 'when incident_escalations feature flag is disabled' do - let(:sort_value) { 'ESCALATION_STATUS_DESC' } - - before do - stub_feature_flags(incident_escalations: false) - end - - it_behaves_like 'a mutation that returns top-level errors', - errors: ['Feature flag `incident_escalations` must be enabled to use this sort order.'] - end end end diff --git a/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb new file mode 100644 index 00000000000..32468a46ace --- /dev/null +++ b/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb @@ -0,0 +1,101 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Update a work item task' do + include GraphqlHelpers + + let_it_be(:project) { create(:project) } + let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } } + let_it_be(:unauthorized_work_item) { create(:work_item) } + let_it_be(:referenced_work_item, refind: true) { create(:work_item, project: project, title: 'REFERENCED') } + let_it_be(:parent_work_item) do + create(:work_item, project: project, description: "- [ ] #{referenced_work_item.to_reference}+") + end + + let(:task) { referenced_work_item } + let(:work_item) { parent_work_item } + let(:task_params) { { 'title' => 'UPDATED' } } + let(:task_input) { { 'id' => task.to_global_id.to_s }.merge(task_params) } + let(:input) { { 'id' => work_item.to_global_id.to_s, 'taskData' => task_input } } + let(:mutation) { graphql_mutation(:workItemUpdateTask, input) } + let(:mutation_response) { graphql_mutation_response(:work_item_update_task) } + + context 'the user is not allowed to read 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 has permissions to update a work item' do + let(:current_user) { developer } + + it 'updates the work item and invalidates markdown cache on the original work item' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + work_item.reload + referenced_work_item.reload + end.to change(referenced_work_item, :title).from(referenced_work_item.title).to('UPDATED') + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response).to include( + 'workItem' => hash_including( + 'title' => work_item.title, + 'descriptionHtml' => a_string_including('UPDATED') + ), + 'task' => hash_including( + 'title' => 'UPDATED' + ) + ) + end + + context 'when providing invalid task params' do + let(:task_params) { { 'title' => '' } } + + 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 + task.reload + end.to not_change(task, :title).and( + not_change(work_item, :description_html) + ) + + expect(mutation_response['errors']).to contain_exactly("Title can't be blank") + end + end + + context 'when user cannot update the task' do + let(:task) { unauthorized_work_item } + + it_behaves_like 'a mutation that returns a top-level access error' + end + + it_behaves_like 'has spam protection' do + let(:mutation_class) { ::Mutations::WorkItems::UpdateTask } + end + + context 'when the work_items feature flag is disabled' do + before do + stub_feature_flags(work_items: false) + end + + it 'does not update the task item and returns and error' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + work_item.reload + task.reload + end.to not_change(task, :title) + + expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project') + end + end + end + + context 'when user does not have permissions to update a work item' do + let(:current_user) { developer } + let(:work_item) { unauthorized_work_item } + + it_behaves_like 'a mutation that returns a top-level access error' + end +end diff --git a/spec/requests/api/graphql/mutations/work_items/update_widgets_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_widgets_spec.rb new file mode 100644 index 00000000000..595d8fe97ed --- /dev/null +++ b/spec/requests/api/graphql/mutations/work_items/update_widgets_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Update work item widgets' do + include GraphqlHelpers + + let_it_be(:project) { create(:project) } + let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } } + let_it_be(:work_item, refind: true) { create(:work_item, project: project) } + + let(:input) do + { + 'descriptionWidget' => { 'description' => 'updated description' } + } + end + + let(:mutation) { graphql_mutation(:workItemUpdateWidgets, input.merge('id' => work_item.to_global_id.to_s)) } + + let(:mutation_response) { graphql_mutation_response(:work_item_update_widgets) } + + 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 has permissions to update a work item', :aggregate_failures do + let(:current_user) { developer } + + context 'when the updated work item is not valid' do + it 'returns validation errors without the work item' do + errors = ActiveModel::Errors.new(work_item).tap { |e| e.add(:description, 'error message') } + + allow_next_found_instance_of(::WorkItem) do |instance| + allow(instance).to receive(:valid?).and_return(false) + allow(instance).to receive(:errors).and_return(errors) + end + + post_graphql_mutation(mutation, current_user: current_user) + + expect(mutation_response['workItem']).to be_nil + expect(mutation_response['errors']).to match_array(['Description error message']) + end + end + + it 'updates the work item widgets' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + work_item.reload + end.to change(work_item, :description).from(nil).to('updated description') + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['workItem']).to include( + 'title' => work_item.title + ) + end + + it_behaves_like 'has spam protection' do + let(:mutation_class) { ::Mutations::WorkItems::UpdateWidgets } + end + + context 'when the work_items feature flag is disabled' do + before do + stub_feature_flags(work_items: false) + end + + it 'does not update the work item and returns and error' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + work_item.reload + end.to not_change(work_item, :title) + + expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project') + end + end + end +end |