diff options
Diffstat (limited to 'spec/requests/api/graphql/mutations/work_items/create_spec.rb')
-rw-r--r-- | spec/requests/api/graphql/mutations/work_items/create_spec.rb | 152 |
1 files changed, 120 insertions, 32 deletions
diff --git a/spec/requests/api/graphql/mutations/work_items/create_spec.rb b/spec/requests/api/graphql/mutations/work_items/create_spec.rb index 16f78b67b5c..fca3c84e534 100644 --- a/spec/requests/api/graphql/mutations/work_items/create_spec.rb +++ b/spec/requests/api/graphql/mutations/work_items/create_spec.rb @@ -5,52 +5,43 @@ require 'spec_helper' RSpec.describe 'Create a work item', feature_category: :team_planning do include GraphqlHelpers - let_it_be(:project) { create(:project) } - let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + let_it_be(:developer) { create(:user).tap { |user| group.add_developer(user) } } let(:input) do { 'title' => 'new title', 'description' => 'new description', 'confidential' => true, - 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_global_id.to_s + 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_gid.to_s } end - let(:mutation) { graphql_mutation(:workItemCreate, input.merge('projectPath' => project.full_path)) } - + let(:fields) { nil } let(:mutation_response) { graphql_mutation_response(:work_item_create) } + let(:current_user) { developer } - context 'the user is not allowed to create 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 create a work item' do - let(:current_user) { developer } - + RSpec.shared_examples 'creates work item' do it 'creates the work item' do expect do post_graphql_mutation(mutation, current_user: current_user) end.to change(WorkItem, :count).by(1) created_work_item = WorkItem.last - expect(response).to have_gitlab_http_status(:success) - expect(created_work_item.issue_type).to eq('task') expect(created_work_item).to be_confidential expect(created_work_item.work_item_type.base_type).to eq('task') expect(mutation_response['workItem']).to include( input.except('workItemTypeId').merge( - 'id' => created_work_item.to_global_id.to_s, + 'id' => created_work_item.to_gid.to_s, 'workItemType' => hash_including('name' => 'Task') ) ) end context 'when input is invalid' do - let(:input) { { 'title' => '', 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_global_id.to_s } } + let(:input) { { 'title' => '', 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_gid.to_s } } it 'does not create and returns validation errors' do expect do @@ -90,16 +81,14 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do FIELDS end - let(:mutation) { graphql_mutation(:workItemCreate, input.merge('projectPath' => project.full_path), fields) } - context 'when setting parent' do - let_it_be(:parent) { create(:work_item, project: project) } + let_it_be(:parent) { create(:work_item, **container_params) } let(:input) do { title: 'item1', - workItemTypeId: WorkItems::Type.default_by_type(:task).to_global_id.to_s, - hierarchyWidget: { 'parentId' => parent.to_global_id.to_s } + workItemTypeId: WorkItems::Type.default_by_type(:task).to_gid.to_s, + hierarchyWidget: { 'parentId' => parent.to_gid.to_s } } end @@ -110,14 +99,14 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do expect(widgets_response).to include( { 'children' => { 'edges' => [] }, - 'parent' => { 'id' => parent.to_global_id.to_s }, + 'parent' => { 'id' => parent.to_gid.to_s }, 'type' => 'HIERARCHY' } ) end context 'when parent work item type is invalid' do - let_it_be(:parent) { create(:work_item, :task, project: project) } + let_it_be(:parent) { create(:work_item, :task, **container_params) } it 'returns error' do post_graphql_mutation(mutation, current_user: current_user) @@ -137,6 +126,40 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do expect(graphql_errors.first['message']).to include('No object found for `parentId') end end + + context 'when adjacent is already in place' do + let_it_be(:adjacent) { create(:work_item, :task, **container_params) } + + let(:work_item) { WorkItem.last } + + let(:input) do + { + title: 'item1', + workItemTypeId: WorkItems::Type.default_by_type(:task).to_gid.to_s, + hierarchyWidget: { 'parentId' => parent.to_gid.to_s } + } + end + + before(:all) do + create(:parent_link, work_item_parent: parent, work_item: adjacent, relative_position: 0) + end + + it 'creates work item and sets the relative position to be AFTER adjacent' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + end.to change(WorkItem, :count).by(1) + + expect(response).to have_gitlab_http_status(:success) + expect(widgets_response).to include( + { + 'children' => { 'edges' => [] }, + 'parent' => { 'id' => parent.to_gid.to_s }, + 'type' => 'HIERARCHY' + } + ) + expect(work_item.parent_link.relative_position).to be > adjacent.parent_link.relative_position + end + end end context 'when unsupported widget input is sent' do @@ -144,7 +167,7 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do { 'title' => 'new title', 'description' => 'new description', - 'workItemTypeId' => WorkItems::Type.default_by_type(:test_case).to_global_id.to_s, + 'workItemTypeId' => WorkItems::Type.default_by_type(:test_case).to_gid.to_s, 'hierarchyWidget' => {} } end @@ -172,17 +195,15 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do FIELDS end - let(:mutation) { graphql_mutation(:workItemCreate, input.merge('projectPath' => project.full_path), fields) } - context 'when setting milestone on work item creation' do let_it_be(:project_milestone) { create(:milestone, project: project) } - let_it_be(:group_milestone) { create(:milestone, project: project) } + let_it_be(:group_milestone) { create(:milestone, group: group) } let(:input) do { title: 'some WI', - workItemTypeId: WorkItems::Type.default_by_type(:task).to_global_id.to_s, - milestoneWidget: { 'milestoneId' => milestone.to_global_id.to_s } + workItemTypeId: WorkItems::Type.default_by_type(:task).to_gid.to_s, + milestoneWidget: { 'milestoneId' => milestone.to_gid.to_s } } end @@ -196,13 +217,18 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do expect(widgets_response).to include( { 'type' => 'MILESTONE', - 'milestone' => { 'id' => milestone.to_global_id.to_s } + 'milestone' => { 'id' => milestone.to_gid.to_s } } ) end end context 'when assigning a project milestone' do + before do + group_work_item = container_params[:namespace].present? + skip('cannot set a project level milestone to a group level work item') if group_work_item + end + it_behaves_like "work item's milestone is set" do let(:milestone) { project_milestone } end @@ -216,4 +242,66 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do end end end + + context 'the user is not allowed to create a work item' do + let(:current_user) { create(:user) } + let(:mutation) { graphql_mutation(:workItemCreate, input.merge('projectPath' => project.full_path), fields) } + + it_behaves_like 'a mutation that returns a top-level access error' + end + + context 'when user has permissions to create a work item' do + context 'when creating work items in a project' do + context 'with projectPath' do + let_it_be(:container_params) { { project: project } } + let(:mutation) { graphql_mutation(:workItemCreate, input.merge('projectPath' => project.full_path), fields) } + + it_behaves_like 'creates work item' + end + + context 'with namespacePath' do + let_it_be(:container_params) { { project: project } } + let(:mutation) { graphql_mutation(:workItemCreate, input.merge('namespacePath' => project.full_path), fields) } + + it_behaves_like 'creates work item' + end + end + + context 'when creating work items in a group' do + let_it_be(:container_params) { { namespace: group } } + let(:mutation) { graphql_mutation(:workItemCreate, input.merge(namespacePath: group.full_path), fields) } + + it_behaves_like 'creates work item' + end + + context 'when both projectPath and namespacePath are passed' do + let_it_be(:container_params) { { project: project } } + let(:mutation) do + graphql_mutation( + :workItemCreate, + input.merge('projectPath' => project.full_path, 'namespacePath' => project.full_path), + fields + ) + end + + it_behaves_like 'a mutation that returns top-level errors', errors: [ + Mutations::WorkItems::Create::MUTUALLY_EXCLUSIVE_ARGUMENTS_ERROR + ] + end + + context 'when neither of projectPath nor namespacePath are passed' do + let_it_be(:container_params) { { project: project } } + let(:mutation) do + graphql_mutation( + :workItemCreate, + input, + fields + ) + end + + it_behaves_like 'a mutation that returns top-level errors', errors: [ + Mutations::WorkItems::Create::MUTUALLY_EXCLUSIVE_ARGUMENTS_ERROR + ] + end + end end |