Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/graphql')
-rw-r--r--spec/graphql/features/feature_flag_spec.rb52
-rw-r--r--spec/graphql/mutations/boards/issues/issue_move_list_spec.rb46
-rw-r--r--spec/graphql/mutations/ci/runner/update_spec.rb170
-rw-r--r--spec/graphql/mutations/commits/create_spec.rb289
-rw-r--r--spec/graphql/mutations/environments/canary_ingress/update_spec.rb11
-rw-r--r--spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb4
-rw-r--r--spec/graphql/mutations/merge_requests/create_spec.rb119
-rw-r--r--spec/graphql/mutations/releases/create_spec.rb2
-rw-r--r--spec/graphql/mutations/releases/update_spec.rb4
-rw-r--r--spec/graphql/resolvers/board_lists_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/config_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/group_runners_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb8
-rw-r--r--spec/graphql/resolvers/ci/jobs_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/runner_projects_resolver_spec.rb69
-rw-r--r--spec/graphql/resolvers/ci/runners_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/test_suite_resolver_spec.rb11
-rw-r--r--spec/graphql/resolvers/container_repositories_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/container_repository_tags_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/crm/organization_state_counts_resolver_spec.rb61
-rw-r--r--spec/graphql/resolvers/crm/organizations_resolver_spec.rb14
-rw-r--r--spec/graphql/resolvers/deployment_resolver_spec.rb28
-rw-r--r--spec/graphql/resolvers/deployments_resolver_spec.rb41
-rw-r--r--spec/graphql/resolvers/design_management/versions_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/environments/last_deployment_resolver_spec.rb40
-rw-r--r--spec/graphql/resolvers/group_members_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb52
-rw-r--r--spec/graphql/resolvers/project_members_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/work_items_resolver_spec.rb56
-rw-r--r--spec/graphql/types/base_field_spec.rb99
-rw-r--r--spec/graphql/types/branch_protections/merge_access_level_type_spec.rb13
-rw-r--r--spec/graphql/types/branch_protections/push_access_level_type_spec.rb13
-rw-r--r--spec/graphql/types/branch_rule_type_spec.rb22
-rw-r--r--spec/graphql/types/branch_rules/branch_protection_type_spec.rb13
-rw-r--r--spec/graphql/types/ci/config_variable_type_spec.rb7
-rw-r--r--spec/graphql/types/ci/group_variable_connection_type_spec.rb11
-rw-r--r--spec/graphql/types/ci/instance_variable_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/job_artifact_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/job_token_scope_type_spec.rb4
-rw-r--r--spec/graphql/types/ci/job_type_spec.rb15
-rw-r--r--spec/graphql/types/ci/manual_variable_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/project_variable_connection_type_spec.rb11
-rw-r--r--spec/graphql/types/ci/runner_architecture_type_spec.rb4
-rw-r--r--spec/graphql/types/ci/runner_platform_type_spec.rb6
-rw-r--r--spec/graphql/types/ci/variable_interface_spec.rb2
-rw-r--r--spec/graphql/types/clusters/agent_type_spec.rb2
-rw-r--r--spec/graphql/types/customer_relations/organization_sort_enum_spec.rb22
-rw-r--r--spec/graphql/types/customer_relations/organization_state_counts_type_spec.rb31
-rw-r--r--spec/graphql/types/deployment_details_type_spec.rb17
-rw-r--r--spec/graphql/types/deployment_type_spec.rb17
-rw-r--r--spec/graphql/types/detployment_tag_type_spec.rb15
-rw-r--r--spec/graphql/types/environment_type_spec.rb10
-rw-r--r--spec/graphql/types/group_type_spec.rb12
-rw-r--r--spec/graphql/types/merge_request_review_state_enum_spec.rb4
-rw-r--r--spec/graphql/types/metrics/dashboard_type_spec.rb4
-rw-r--r--spec/graphql/types/packages/composer/metadatum_type_spec.rb2
-rw-r--r--spec/graphql/types/packages/package_type_enum_spec.rb2
-rw-r--r--spec/graphql/types/project_type_spec.rb67
-rw-r--r--spec/graphql/types/subscription_type_spec.rb3
-rw-r--r--spec/graphql/types/timelog_type_spec.rb2
-rw-r--r--spec/graphql/types/user_merge_request_interaction_type_spec.rb3
-rw-r--r--spec/graphql/types/work_item_type_spec.rb4
-rw-r--r--spec/graphql/types/work_items/widgets/description_type_spec.rb2
63 files changed, 1050 insertions, 498 deletions
diff --git a/spec/graphql/features/feature_flag_spec.rb b/spec/graphql/features/feature_flag_spec.rb
deleted file mode 100644
index b06718eb16a..00000000000
--- a/spec/graphql/features/feature_flag_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Graphql Field feature flags' do
- include GraphqlHelpers
- include Graphql::ResolverFactories
-
- let_it_be(:user) { create(:user) }
-
- let(:feature_flag) { 'test_feature' }
- let(:test_object) { double(name: 'My name') }
- let(:query_string) { '{ item { name } }' }
- let(:result) { execute_query(query_type)['data'] }
-
- before do
- skip_feature_flags_yaml_validation
- end
-
- subject { result }
-
- describe 'Feature flagged field' do
- let(:type) { type_factory }
-
- let(:query_type) do
- query_factory do |query|
- query.field :item, type, null: true, _deprecated_feature_flag: feature_flag, resolver: new_resolver(test_object)
- end
- end
-
- it 'checks YAML definition for default_enabled' do
- # Exception is indicative of a check for YAML definition
- expect { subject }.to raise_error(Feature::InvalidFeatureFlagError, /The feature flag YAML definition for '#{feature_flag}' does not exist/)
- end
-
- context 'skipping YAML check' do
- before do
- skip_default_enabled_yaml_check
- end
-
- it 'returns the value when feature is enabled' do
- expect(subject['item']).to eq('name' => test_object.name)
- end
-
- it 'returns nil when the feature is disabled' do
- stub_feature_flags(feature_flag => false)
-
- expect(subject).to be_nil
- end
- end
- end
-end
diff --git a/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb b/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb
index 10aed8a1f00..8e9a567f614 100644
--- a/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb
+++ b/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe Mutations::Boards::Issues::IssueMoveList do
let(:move_params) { {} }
it 'generates an error' do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'At least one of the arguments fromListId, toListId, afterId or beforeId is required') do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'At least one of the arguments fromListId, toListId, positionInList, moveAfterId, or moveBeforeId is required') do
subject
end
end
@@ -71,6 +71,50 @@ RSpec.describe Mutations::Boards::Issues::IssueMoveList do
end
end
+ context 'when positionInList is given' do
+ let(:move_params) { { from_list_id: list1.id, to_list_id: list2.id, position_in_list: 0 } }
+
+ context 'when fromListId and toListId are missing' do
+ let(:move_params) { { position_in_list: 0 } }
+
+ it 'generates an error' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'Both fromListId and toListId are required when positionInList is given') do
+ subject
+ end
+ end
+ end
+
+ context 'when move_before_id is also given' do
+ let(:move_params) { { from_list_id: list1.id, to_list_id: list2.id, position_in_list: 0, move_before_id: 1 } }
+
+ it 'generates an error' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'positionInList is mutually exclusive with any of moveBeforeId or moveAfterId') do
+ subject
+ end
+ end
+ end
+
+ context 'when move_after_id is also given' do
+ let(:move_params) { { from_list_id: list1.id, to_list_id: list2.id, position_in_list: 0, move_after_id: 1 } }
+
+ it 'generates an error' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'positionInList is mutually exclusive with any of moveBeforeId or moveAfterId') do
+ subject
+ end
+ end
+ end
+
+ context 'when position_in_list is invalid' do
+ let(:move_params) { { from_list_id: list1.id, to_list_id: list2.id, position_in_list: -5 } }
+
+ it 'generates an error' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, "positionInList must be >= 0 or #{Boards::Issues::MoveService::LIST_END_POSITION}") do
+ subject
+ end
+ end
+ end
+ end
+
context 'when user have access to resources' do
it 'moves and repositions issue' do
subject
diff --git a/spec/graphql/mutations/ci/runner/update_spec.rb b/spec/graphql/mutations/ci/runner/update_spec.rb
index b8efd4213fa..39fe2a53a68 100644
--- a/spec/graphql/mutations/ci/runner/update_spec.rb
+++ b/spec/graphql/mutations/ci/runner/update_spec.rb
@@ -6,10 +6,13 @@ RSpec.describe Mutations::Ci::Runner::Update do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
- let_it_be(:runner) { create(:ci_runner, active: true, locked: false, run_untagged: true) }
+ let_it_be(:project1) { create(:project) }
+ let_it_be(:runner) do
+ create(:ci_runner, :project, projects: [project1], active: true, locked: false, run_untagged: true)
+ end
let(:current_ctx) { { current_user: user } }
- let(:mutated_runner) { subject[:runner] }
+ let(:mutated_runner) { response[:runner] }
let(:mutation_params) do
{
@@ -21,14 +24,14 @@ RSpec.describe Mutations::Ci::Runner::Update do
specify { expect(described_class).to require_graphql_authorizations(:update_runner) }
describe '#resolve' do
- subject do
+ subject(:response) do
sync(resolve(described_class, args: mutation_params, ctx: current_ctx))
end
context 'when the user cannot admin the runner' do
it 'generates an error' do
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
- subject
+ response
end
end
end
@@ -37,7 +40,7 @@ RSpec.describe Mutations::Ci::Runner::Update do
let(:mutation_params) { {} }
it 'raises an error' do
- expect { subject }.to raise_error(ArgumentError, "Arguments must be provided: id")
+ expect { response }.to raise_error(ArgumentError, "Arguments must be provided: id")
end
end
@@ -45,41 +48,150 @@ RSpec.describe Mutations::Ci::Runner::Update do
let(:admin_user) { create(:user, :admin) }
let(:current_ctx) { { current_user: admin_user } }
- let(:mutation_params) do
- {
- id: runner.to_global_id,
- description: 'updated description',
- maintenance_note: 'updated maintenance note',
- maximum_timeout: 900,
- access_level: 'ref_protected',
- active: false,
- locked: true,
- run_untagged: false,
- tag_list: %w(tag1 tag2)
- }
- end
-
context 'with valid arguments' do
+ let(:mutation_params) do
+ {
+ id: runner.to_global_id,
+ description: 'updated description',
+ maintenance_note: 'updated maintenance note',
+ maximum_timeout: 900,
+ access_level: 'ref_protected',
+ active: false,
+ locked: true,
+ run_untagged: false,
+ tag_list: %w(tag1 tag2)
+ }
+ end
+
it 'updates runner with correct values' do
expected_attributes = mutation_params.except(:id, :tag_list)
- subject
+ response
- expect(subject[:errors]).to be_empty
- expect(subject[:runner]).to be_an_instance_of(Ci::Runner)
- expect(subject[:runner]).to have_attributes(expected_attributes)
- expect(subject[:runner].tag_list).to contain_exactly(*mutation_params[:tag_list])
+ expect(response[:errors]).to be_empty
+ expect(response[:runner]).to be_an_instance_of(Ci::Runner)
+ expect(response[:runner]).to have_attributes(expected_attributes)
+ expect(response[:runner].tag_list).to contain_exactly(*mutation_params[:tag_list])
expect(runner.reload).to have_attributes(expected_attributes)
expect(runner.tag_list).to contain_exactly(*mutation_params[:tag_list])
end
end
+ context 'with associatedProjects argument' do
+ let_it_be(:project2) { create(:project) }
+
+ context 'with id set to project runner' do
+ let(:mutation_params) do
+ {
+ id: runner.to_global_id,
+ description: 'updated description',
+ associated_projects: [project2.to_global_id.to_s]
+ }
+ end
+
+ it 'updates runner attributes and project relationships', :aggregate_failures do
+ expect_next_instance_of(
+ ::Ci::Runners::SetRunnerAssociatedProjectsService,
+ {
+ runner: runner,
+ current_user: admin_user,
+ project_ids: [project2.id]
+ }
+ ) do |service|
+ expect(service).to receive(:execute).and_call_original
+ end
+
+ expected_attributes = mutation_params.except(:id, :associated_projects)
+
+ response
+
+ expect(response[:errors]).to be_empty
+ expect(response[:runner]).to be_an_instance_of(Ci::Runner)
+ expect(response[:runner]).to have_attributes(expected_attributes)
+ expect(runner.reload).to have_attributes(expected_attributes)
+ expect(runner.projects).to match_array([project1, project2])
+ end
+
+ context 'with user not allowed to assign runner' do
+ before do
+ allow(admin_user).to receive(:can?).with(:assign_runner, runner).and_return(false)
+ end
+
+ it 'does not update runner', :aggregate_failures do
+ expect_next_instance_of(
+ ::Ci::Runners::SetRunnerAssociatedProjectsService,
+ {
+ runner: runner,
+ current_user: admin_user,
+ project_ids: [project2.id]
+ }
+ ) do |service|
+ expect(service).to receive(:execute).and_call_original
+ end
+
+ expected_attributes = mutation_params.except(:id, :associated_projects)
+
+ response
+
+ expect(response[:errors]).to match_array(['user not allowed to assign runner'])
+ expect(response[:runner]).to be_an_instance_of(Ci::Runner)
+ expect(response[:runner]).not_to have_attributes(expected_attributes)
+ expect(runner.reload).not_to have_attributes(expected_attributes)
+ expect(runner.projects).to match_array([project1])
+ end
+ end
+ end
+
+ context 'with id set to instance runner' do
+ let(:instance_runner) { create(:ci_runner, :instance) }
+ let(:mutation_params) do
+ {
+ id: instance_runner.to_global_id,
+ description: 'updated description',
+ associated_projects: [project2.to_global_id.to_s]
+ }
+ end
+
+ it 'raises error', :aggregate_failures do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError) do
+ response
+ end
+ end
+ end
+ end
+
+ context 'with non-existing project ID in associatedProjects argument' do
+ let(:mutation_params) do
+ {
+ id: runner.to_global_id,
+ associated_projects: ['gid://gitlab/Project/-1']
+ }
+ end
+
+ it 'does not change associated projects' do
+ expected_attributes = mutation_params.except(:id, :associated_projects)
+
+ response
+
+ expect(response[:errors]).to be_empty
+ expect(response[:runner]).to be_an_instance_of(Ci::Runner)
+ expect(response[:runner]).to have_attributes(expected_attributes)
+ expect(runner.reload).to have_attributes(expected_attributes)
+ expect(runner.projects).to match_array([project1])
+ end
+ end
+
context 'with out-of-range maximum_timeout and missing tag_list' do
- it 'returns a descriptive error' do
- mutation_params[:maximum_timeout] = 100
- mutation_params.delete(:tag_list)
+ let(:mutation_params) do
+ {
+ id: runner.to_global_id,
+ maximum_timeout: 100,
+ run_untagged: false
+ }
+ end
- expect(subject[:errors]).to contain_exactly(
+ it 'returns a descriptive error' do
+ expect(response[:errors]).to contain_exactly(
'Maximum timeout needs to be at least 10 minutes',
'Tags list can not be empty when runner is not allowed to pick untagged jobs'
)
@@ -90,7 +202,7 @@ RSpec.describe Mutations::Ci::Runner::Update do
it 'returns a descriptive error' do
mutation_params[:maintenance_note] = '1' * 1025
- expect(subject[:errors]).to contain_exactly(
+ expect(response[:errors]).to contain_exactly(
'Maintenance note is too long (maximum is 1024 characters)'
)
end
diff --git a/spec/graphql/mutations/commits/create_spec.rb b/spec/graphql/mutations/commits/create_spec.rb
index 9fc9c731b96..fd0c2c46b2e 100644
--- a/spec/graphql/mutations/commits/create_spec.rb
+++ b/spec/graphql/mutations/commits/create_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe Mutations::Commits::Create do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:group) { create(:group, :public) }
let(:context) do
GraphQL::Query::Context.new(
@@ -39,174 +40,208 @@ RSpec.describe Mutations::Commits::Create do
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
-
+ context 'when user is not a project member' do
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
+ context 'when user is a direct project member' do
+ context 'and user is a guest' do
+ before do
+ project.add_guest(user)
+ end
- it 'raises an error' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
end
- end
- context 'when the user can create a commit' do
- let(:deltas) { mutated_commit.raw_deltas }
+ context 'and user is a developer' 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 the ETag path for the commit's pipeline" do
- commit_pipeline_path = subject[:commit_pipeline_path]
- expect(commit_pipeline_path).to match(%r(pipelines/sha/\w+))
+ before_all do
+ project.add_developer(user)
end
- it 'returns the content of the commit' do
- expect(subject[:content]).to eq(actions.pluck(:content))
- end
+ context 'when service successfully creates a new commit' do
+ it "returns the ETag path for the commit's pipeline" do
+ commit_pipeline_path = subject[:commit_pipeline_path]
+ expect(commit_pipeline_path).to match(%r(pipelines/sha/\w+))
+ end
- it 'returns a new commit' do
- expect(mutated_commit).to have_attributes(message: message, project: project)
- expect(subject[:errors]).to be_empty
+ it 'returns the content of the commit' do
+ expect(subject[:content]).to eq(actions.pluck(:content))
+ end
- expect_to_contain_deltas([
- a_hash_including(a_mode: '0', b_mode: '100644', new_file: true, new_path: file_path)
- ])
+ 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: file_path)
+ ])
+ end
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
- }
- ]
+ 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
- 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')
- ])
+ 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
- end
- context 'when actions are not defined' do
- let(:actions) { [] }
+ context 'when branch does not exist' do
+ let(:branch) { 'unknown' }
- it 'returns a new commit' do
- expect(mutated_commit).to have_attributes(message: message, project: project)
- expect(subject[:errors]).to be_empty
+ it 'returns errors' do
+ expect(mutated_commit).to be_nil
+ expect(subject[:errors]).to match_array(['You can only create or edit files when you are on a branch'])
+ end
+ end
- expect_to_contain_deltas([])
+ context 'when branch does not exist and a start branch is provided' do
+ let(:branch) { 'my-branch' }
+ let(:start_branch) { 'master' }
+ let(:actions) do
+ [
+ {
+ action: 'create',
+ file_path: 'ANOTHER_FILE.md',
+ content: 'Bye'
+ }
+ ]
+ end
+
+ it 'returns a new commit' do
+ expect(mutated_commit).to have_attributes(message: message, project: project)
+ expect(subject[:errors]).to be_empty
+ expect(subject[:content]).to eq(actions.pluck(:content))
+
+ expect_to_contain_deltas([
+ a_hash_including(a_mode: '0', b_mode: '100644', new_file: true, new_path: 'ANOTHER_FILE.md')
+ ])
+ end
end
- end
- context 'when branch does not exist' do
- let(:branch) { 'unknown' }
+ 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(['You can only create or edit files when you are on a branch'])
+ it 'returns errors' do
+ expect(mutated_commit).to be_nil
+ expect(subject[:errors].to_s).to match(/3:UserCommitFiles: empty CommitMessage/)
+ end
end
- end
- context 'when branch does not exist and a start branch is provided' do
- let(:branch) { 'my-branch' }
- let(:start_branch) { 'master' }
- let(:actions) do
- [
- {
- action: 'create',
- file_path: 'ANOTHER_FILE.md',
- content: 'Bye'
- }
- ]
+ 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 match_array(['Unknown action \'unknown\''])
+ end
end
- it 'returns a new commit' do
- expect(mutated_commit).to have_attributes(message: message, project: project)
- expect(subject[:errors]).to be_empty
- expect(subject[:content]).to eq(actions.pluck(:content))
+ context 'when branch is protected' do
+ before do
+ create(:protected_branch, project: project, name: branch)
+ end
- expect_to_contain_deltas([
- a_hash_including(a_mode: '0', b_mode: '100644', new_file: true, new_path: 'ANOTHER_FILE.md')
- ])
+ it 'returns errors' do
+ expect(mutated_commit).to be_nil
+ expect(subject[:errors]).to match_array(['You are not allowed to push into this branch'])
+ end
end
end
+ end
- context 'when message is not set' do
- let(:message) { nil }
+ context 'when user is an inherited member from the group' do
+ context 'when project is public with private repository' do
+ let(:project) { create(:project, :public, :repository, :repository_private, group: group) }
- it 'returns errors' do
- expect(mutated_commit).to be_nil
- expect(subject[:errors].to_s).to match(/3:UserCommitFiles: empty CommitMessage/)
+ context 'and user is a guest' do
+ before do
+ group.add_guest(user)
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
end
end
- context 'when actions are incorrect' do
- let(:actions) { [{ action: 'unknown', file_path: 'test.md', content: '' }] }
+ context 'when project is private' do
+ let(:project) { create(:project, :private, :repository, group: group) }
+
+ context 'and user is a guest' do
+ before do
+ group.add_guest(user)
+ end
- it 'returns errors' do
- expect(mutated_commit).to be_nil
- expect(subject[:errors]).to eq(['Unknown action \'unknown\''])
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
end
end
+ end
- context 'when branch is protected' do
- before do
- create(:protected_branch, project: project, name: branch)
- end
+ context 'when user is a maintainer of a different project' do
+ before do
+ create(:project_empty_repo).add_maintainer(user)
+ 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
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
diff --git a/spec/graphql/mutations/environments/canary_ingress/update_spec.rb b/spec/graphql/mutations/environments/canary_ingress/update_spec.rb
index b93fb36a8ff..2476431816e 100644
--- a/spec/graphql/mutations/environments/canary_ingress/update_spec.rb
+++ b/spec/graphql/mutations/environments/canary_ingress/update_spec.rb
@@ -43,11 +43,12 @@ RSpec.describe Mutations::Environments::CanaryIngress::Update do
end
it 'returns notice about feature removal' do
- expect(subject[:errors]).to match_array([
- 'This endpoint was deactivated as part of the certificate-based' \
- 'kubernetes integration removal. See Epic:' \
- 'https://gitlab.com/groups/gitlab-org/configure/-/epics/8'
- ])
+ expect(subject[:errors]).to match_array(
+ [
+ 'This endpoint was deactivated as part of the certificate-based' \
+ 'kubernetes integration removal. See Epic:' \
+ 'https://gitlab.com/groups/gitlab-org/configure/-/epics/8'
+ ])
end
end
end
diff --git a/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
index 4541f8af7d3..56514c985ff 100644
--- a/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
+++ b/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::IncidentManagement::TimelineEvent::PromoteFromNote do
+ include NotesHelper
+
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:incident) { create(:incident, project: project) }
@@ -23,7 +25,7 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::PromoteFromNote do
let(:expected_timeline_event) do
instance_double(
'IncidentManagement::TimelineEvent',
- note: comment.note,
+ note: "@#{comment.author.username} [commented](#{noteable_note_url(comment)}): '#{comment.note}'",
occurred_at: comment.created_at.to_s,
incident: incident,
author: current_user,
diff --git a/spec/graphql/mutations/merge_requests/create_spec.rb b/spec/graphql/mutations/merge_requests/create_spec.rb
index e1edb60e4ff..6e593a5f4be 100644
--- a/spec/graphql/mutations/merge_requests/create_spec.rb
+++ b/spec/graphql/mutations/merge_requests/create_spec.rb
@@ -7,8 +7,7 @@ RSpec.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(:user) { create(:user) }
let(:context) do
GraphQL::Query::Context.new(
@@ -38,62 +37,106 @@ RSpec.describe Mutations::MergeRequests::Create do
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)
+ shared_examples 'resource not available' do
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
end
- context 'when user does not have enough permissions to create a merge request' do
- before do
- project.add_guest(user)
- end
+ context 'when user is not a project member' do
+ let_it_be(:project) { create(:project, :public, :repository) }
- it 'raises an error if the resource is not accessible to the user' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
- end
+ it_behaves_like 'resource not available'
end
- context 'when the user can create a merge request' do
- before_all do
- project.add_developer(user)
- end
+ context 'when user is a direct project member' do
+ let_it_be(:project) { create(:project, :public, :repository) }
- it 'creates a new merge request' do
- expect { mutated_merge_request }.to change(MergeRequest, :count).by(1)
- end
+ context 'and user is a guest' do
+ before do
+ project.add_guest(user)
+ end
- it 'returns a new merge request' do
- expect(mutated_merge_request.title).to eq(title)
- expect(subject[:errors]).to be_empty
+ it_behaves_like 'resource not available'
end
- context 'when optional description field is set' do
- let(:description) { 'content' }
+ context 'and user is a developer' do
+ before 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 with a description' do
- expect(mutated_merge_request.description).to eq(description)
+ it 'returns a new merge request' do
+ expect(mutated_merge_request.title).to eq(title)
expect(subject[:errors]).to be_empty
end
- end
- context 'when optional labels field is set' do
- let(:labels) { %w[label-1 label-2] }
+ context 'when optional description field is set' do
+ let(:description) { 'content' }
- it 'returns a new merge request with labels' do
- expect(mutated_merge_request.labels.map(&:title)).to eq(labels)
- expect(subject[:errors]).to be_empty
+ 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 optional labels field is set' do
+ let(:labels) { %w[label-1 label-2] }
+
+ it 'returns a new merge request with labels' do
+ expect(mutated_merge_request.labels.map(&:title)).to eq(labels)
+ 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 match_array(['Title can\'t be blank'])
+ end
end
end
+ end
- context 'when service cannot create a merge request' do
- let(:title) { nil }
+ context 'when user is an inherited member from the group' do
+ let_it_be(:group) { create(:group, :public) }
- it 'does not create a new merge request' do
- expect { mutated_merge_request }.not_to change(MergeRequest, :count)
+ context 'when project is public with private merge requests' do
+ let_it_be(:project) do
+ create(:project,
+ :public,
+ :repository,
+ group: group,
+ merge_requests_access_level: ProjectFeature::DISABLED)
end
- it 'returns errors' do
- expect(mutated_merge_request).to be_nil
- expect(subject[:errors]).to eq(['Title can\'t be blank'])
+ context 'and user is a guest' do
+ before do
+ group.add_guest(user)
+ end
+
+ it_behaves_like 'resource not available'
+ end
+ end
+
+ context 'when project is private' do
+ let_it_be(:project) { create(:project, :private, :repository, group: group) }
+
+ context 'and user is a guest' do
+ before do
+ group.add_guest(user)
+ end
+
+ it_behaves_like 'resource not available'
end
end
end
diff --git a/spec/graphql/mutations/releases/create_spec.rb b/spec/graphql/mutations/releases/create_spec.rb
index b6b9449aa39..e7c25a20bad 100644
--- a/spec/graphql/mutations/releases/create_spec.rb
+++ b/spec/graphql/mutations/releases/create_spec.rb
@@ -135,7 +135,7 @@ RSpec.describe Mutations::Releases::Create do
it 'has an access error' do
subject
- expect(resolve).to include(errors: ['Access Denied'])
+ expect(resolve).to include(errors: ['You are not allowed to create this tag as it is protected.'])
end
end
end
diff --git a/spec/graphql/mutations/releases/update_spec.rb b/spec/graphql/mutations/releases/update_spec.rb
index 15b10ea0648..0cf10e03fb1 100644
--- a/spec/graphql/mutations/releases/update_spec.rb
+++ b/spec/graphql/mutations/releases/update_spec.rb
@@ -18,8 +18,8 @@ RSpec.describe Mutations::Releases::Update do
let_it_be(:release) do
create(:release, project: project, tag: tag, name: name,
- description: description, released_at: released_at,
- created_at: created_at, milestones: [milestone_12_3, milestone_12_4])
+ description: description, released_at: released_at,
+ created_at: created_at, milestones: [milestone_12_3, milestone_12_4])
end
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
diff --git a/spec/graphql/resolvers/board_lists_resolver_spec.rb b/spec/graphql/resolvers/board_lists_resolver_spec.rb
index c882ad7c818..2fb7c5c4717 100644
--- a/spec/graphql/resolvers/board_lists_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_lists_resolver_spec.rb
@@ -101,7 +101,7 @@ RSpec.describe Resolvers::BoardListsResolver do
def resolve_board_lists(args: {}, current_user: user)
resolve(described_class, obj: board, args: args, ctx: { current_user: current_user },
- arg_style: :internal
+ arg_style: :internal
)
end
end
diff --git a/spec/graphql/resolvers/ci/config_resolver_spec.rb b/spec/graphql/resolvers/ci/config_resolver_spec.rb
index dc030b1313b..692bdf58784 100644
--- a/spec/graphql/resolvers/ci/config_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/config_resolver_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Resolvers::Ci::ConfigResolver do
subject(:response) do
resolve(described_class,
args: { project_path: project.full_path, content: content, sha: sha },
- ctx: { current_user: user })
+ ctx: { current_user: user })
end
shared_examples 'a valid config file' do
diff --git a/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb b/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb
index f99f48f5b07..57b2fcbea63 100644
--- a/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver do
describe '#resolve' do
subject do
resolve(described_class, obj: obj, ctx: { current_user: user }, args: args,
- arg_style: :internal)
+ arg_style: :internal)
end
include_context 'runners resolver setup'
diff --git a/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb b/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb
index ac7cef20df4..1bfd6fbf6b9 100644
--- a/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb
@@ -20,10 +20,10 @@ RSpec.describe Resolvers::Ci::JobTokenScopeResolver do
project.add_member(current_user, :maintainer)
end
- it 'returns nil when scope is not enabled' do
+ it 'returns the same project in the allow list of projects for the Ci Job Token when scope is not enabled' do
allow(project).to receive(:ci_job_token_scope_enabled?).and_return(false)
- expect(resolve_scope).to eq(nil)
+ expect(resolve_scope.all_projects).to contain_exactly(project)
end
it 'returns the same project in the allow list of projects for the Ci Job Token' do
@@ -43,8 +43,8 @@ RSpec.describe Resolvers::Ci::JobTokenScopeResolver do
project.update!(ci_job_token_scope_enabled: false)
end
- it 'returns nil' do
- expect(resolve_scope).to be_nil
+ it 'resolves projects' do
+ expect(resolve_scope.all_projects).to contain_exactly(project)
end
end
end
diff --git a/spec/graphql/resolvers/ci/jobs_resolver_spec.rb b/spec/graphql/resolvers/ci/jobs_resolver_spec.rb
index 6c228861ddf..80a70938dc4 100644
--- a/spec/graphql/resolvers/ci/jobs_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/jobs_resolver_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe Resolvers::Ci::JobsResolver do
::Types::Security::ReportTypeEnum.values['DAST'].value
]
jobs = resolve(described_class, obj: pipeline, args: { security_report_types: report_types },
- arg_style: :internal)
+ arg_style: :internal)
expect(jobs).to contain_exactly(
have_attributes(name: 'DAST job'),
diff --git a/spec/graphql/resolvers/ci/runner_projects_resolver_spec.rb b/spec/graphql/resolvers/ci/runner_projects_resolver_spec.rb
new file mode 100644
index 00000000000..952c7337d65
--- /dev/null
+++ b/spec/graphql/resolvers/ci/runner_projects_resolver_spec.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Ci::RunnerProjectsResolver do
+ include GraphqlHelpers
+
+ let_it_be(:project1) { create(:project, description: 'Project1.1') }
+ let_it_be(:project2) { create(:project, description: 'Project1.2') }
+ let_it_be(:project3) { create(:project, description: 'Project2.1') }
+ let_it_be(:runner) { create(:ci_runner, :project, projects: [project1, project2, project3]) }
+
+ let(:args) { {} }
+
+ subject { resolve_projects(args) }
+
+ describe '#resolve' do
+ context 'with authorized user', :enable_admin_mode do
+ let(:current_user) { create(:user, :admin) }
+
+ context 'with search argument' do
+ let(:args) { { search: 'Project1.' } }
+
+ it 'returns a lazy value with projects containing the specified prefix' do
+ expect(subject).to be_a(GraphQL::Execution::Lazy)
+ expect(subject.value).to contain_exactly(project1, project2)
+ end
+ end
+
+ context 'with supported arguments' do
+ let(:args) { { membership: true, search_namespaces: true, topics: %w[xyz] } }
+
+ it 'creates ProjectsFinder with expected arguments' do
+ expect(ProjectsFinder).to receive(:new).with(
+ a_hash_including(
+ params: a_hash_including(
+ non_public: true,
+ search_namespaces: true,
+ topic: %w[xyz]
+ )
+ )
+ ).and_call_original
+
+ expect(subject).to be_a(GraphQL::Execution::Lazy)
+ subject.value
+ end
+ end
+
+ context 'without arguments' do
+ it 'returns a lazy value with all projects' do
+ expect(subject).to be_a(GraphQL::Execution::Lazy)
+ expect(subject.value).to contain_exactly(project1, project2, project3)
+ end
+ end
+ end
+
+ context 'with unauthorized user' do
+ let(:current_user) { create(:user) }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ private
+
+ def resolve_projects(args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: runner, args: args, ctx: context)
+ end
+end
diff --git a/spec/graphql/resolvers/ci/runners_resolver_spec.rb b/spec/graphql/resolvers/ci/runners_resolver_spec.rb
index 8586d359336..4038192a68a 100644
--- a/spec/graphql/resolvers/ci/runners_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/runners_resolver_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver do
subject do
resolve(described_class, obj: obj, ctx: { current_user: user }, args: args,
- arg_style: :internal)
+ arg_style: :internal)
end
include_context 'runners resolver setup'
diff --git a/spec/graphql/resolvers/ci/test_suite_resolver_spec.rb b/spec/graphql/resolvers/ci/test_suite_resolver_spec.rb
index 606c6eb03a3..4083e77a38f 100644
--- a/spec/graphql/resolvers/ci/test_suite_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/test_suite_resolver_spec.rb
@@ -32,11 +32,12 @@ RSpec.describe Resolvers::Ci::TestSuiteResolver do
# Each test failure in this pipeline has a matching failure in the default branch
recent_failures = test_suite[:test_cases].map { |tc| tc[:recent_failures] }
- expect(recent_failures).to eq([
- { count: 1, base_branch: 'master' },
- { count: 1, base_branch: 'master' },
- { count: 1, base_branch: 'master' }
- ])
+ expect(recent_failures).to eq(
+ [
+ { count: 1, base_branch: 'master' },
+ { count: 1, base_branch: 'master' },
+ { count: 1, base_branch: 'master' }
+ ])
end
end
diff --git a/spec/graphql/resolvers/container_repositories_resolver_spec.rb b/spec/graphql/resolvers/container_repositories_resolver_spec.rb
index ed922259903..8cbb366f873 100644
--- a/spec/graphql/resolvers/container_repositories_resolver_spec.rb
+++ b/spec/graphql/resolvers/container_repositories_resolver_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Resolvers::ContainerRepositoriesResolver do
subject do
resolve(described_class, ctx: { current_user: user }, args: args, obj: object,
- arg_style: :internal)
+ arg_style: :internal)
end
shared_examples 'returning container repositories' do
diff --git a/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb b/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb
index 9747f663759..3ed3fe76267 100644
--- a/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb
+++ b/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe Resolvers::ContainerRepositoryTagsResolver do
describe '#resolve' do
let(:resolver) do
resolve(described_class, ctx: { current_user: user }, obj: repository, args: args,
- arg_style: :internal)
+ arg_style: :internal)
end
before do
diff --git a/spec/graphql/resolvers/crm/organization_state_counts_resolver_spec.rb b/spec/graphql/resolvers/crm/organization_state_counts_resolver_spec.rb
new file mode 100644
index 00000000000..c6ad4beeee0
--- /dev/null
+++ b/spec/graphql/resolvers/crm/organization_state_counts_resolver_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Crm::OrganizationStateCountsResolver do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group, :crm_enabled) }
+
+ before_all do
+ create(:organization, group: group, name: "ABC Corp")
+ create(:organization, group: group, name: "123 Corp", state: 'inactive')
+ create_list(:organization, 3, group: group)
+ create_list(:organization, 2, group: group, state: 'inactive')
+ end
+
+ describe '#resolve' do
+ context 'with unauthorized user' do
+ it 'does not raise an error and returns nil' do
+ expect { resolve_counts(group) }.not_to raise_error
+ expect(resolve_counts(group)).to be_nil
+ end
+ end
+
+ context 'with authorized user' do
+ before do
+ group.add_reporter(user)
+ end
+
+ context 'without parent' do
+ it 'returns nil' do
+ expect(resolve_counts(nil)).to be_nil
+ end
+ end
+
+ context 'with a group' do
+ context 'when no filter is provided' do
+ it 'returns the count of all organizations' do
+ counts = resolve_counts(group)
+ expect(counts['active']).to eq(4)
+ expect(counts['inactive']).to eq(3)
+ end
+ end
+
+ context 'when search term is provided' do
+ it 'returns the correct counts' do
+ counts = resolve_counts(group, { search: "Corp" })
+
+ expect(counts['active']).to eq(1)
+ expect(counts['inactive']).to eq(1)
+ end
+ end
+ end
+ end
+ end
+
+ def resolve_counts(parent, args = {}, context = { current_user: user })
+ resolve(described_class, obj: parent, args: args, ctx: context)
+ end
+end
diff --git a/spec/graphql/resolvers/crm/organizations_resolver_spec.rb b/spec/graphql/resolvers/crm/organizations_resolver_spec.rb
index 323f134ffc3..d5980bf3c41 100644
--- a/spec/graphql/resolvers/crm/organizations_resolver_spec.rb
+++ b/spec/graphql/resolvers/crm/organizations_resolver_spec.rb
@@ -55,11 +55,23 @@ RSpec.describe Resolvers::Crm::OrganizationsResolver do
end
context 'when no filter is provided' do
- it 'returns all the organizations in the correct order' do
+ it 'returns all the organizations in the default order' do
expect(resolve_organizations(group)).to eq([organization_a, organization_b])
end
end
+ context 'when a sort is provided' do
+ it 'returns all the organizations in the correct order' do
+ expect(resolve_organizations(group, { sort: 'NAME_DESC' })).to eq([organization_b, organization_a])
+ end
+ end
+
+ context 'when filtering for all states' do
+ it 'returns all the organizations' do
+ expect(resolve_organizations(group, { state: 'all' })).to contain_exactly(organization_a, organization_b)
+ end
+ end
+
context 'when search term is provided' do
it 'returns the correct organizations' do
expect(resolve_organizations(group, { search: "def" })).to contain_exactly(organization_b)
diff --git a/spec/graphql/resolvers/deployment_resolver_spec.rb b/spec/graphql/resolvers/deployment_resolver_spec.rb
new file mode 100644
index 00000000000..9231edefddc
--- /dev/null
+++ b/spec/graphql/resolvers/deployment_resolver_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::DeploymentResolver do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :repository, :private) }
+ let_it_be(:environment) { create(:environment, project: project) }
+ let_it_be(:deployment) { create(:deployment, :created, environment: environment, project: project) }
+ let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
+
+ let(:current_user) { developer }
+
+ describe '#resolve' do
+ it 'finds the deployment' do
+ expect(resolve_deployments(iid: deployment.iid)).to contain_exactly(deployment)
+ end
+
+ it 'does not find the deployment if the IID does not match' do
+ expect(resolve_deployments(iid: non_existing_record_id)).to be_empty
+ end
+ end
+
+ def resolve_deployments(args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: project, args: args, ctx: context)
+ end
+end
diff --git a/spec/graphql/resolvers/deployments_resolver_spec.rb b/spec/graphql/resolvers/deployments_resolver_spec.rb
new file mode 100644
index 00000000000..4e5564aad0b
--- /dev/null
+++ b/spec/graphql/resolvers/deployments_resolver_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::DeploymentsResolver do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :repository, :private) }
+ let_it_be(:environment) { create(:environment, project: project) }
+ let_it_be(:deployment) { create(:deployment, :created, environment: environment, project: project) }
+ let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
+
+ let(:current_user) { developer }
+
+ describe '#resolve' do
+ it 'finds the deployment' do
+ expect(resolve_deployments).to contain_exactly(deployment)
+ end
+
+ it 'finds the deployment when status matches' do
+ expect(resolve_deployments(statuses: [:created])).to contain_exactly(deployment)
+ end
+
+ it 'does not find the deployment when status does not match' do
+ expect(resolve_deployments(statuses: [:success])).to be_empty
+ end
+
+ it 'transforms order_by for finder' do
+ expect(DeploymentsFinder)
+ .to receive(:new)
+ .with(environment: environment.id, status: ['success'], order_by: 'finished_at', sort: 'asc')
+ .and_call_original
+
+ resolve_deployments(statuses: [:success], order_by: { finished_at: :asc })
+ end
+ end
+
+ def resolve_deployments(args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: environment, args: args, ctx: context)
+ end
+end
diff --git a/spec/graphql/resolvers/design_management/versions_resolver_spec.rb b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
index 3a2ed445484..eb39e5bafc5 100644
--- a/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
+++ b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
@@ -82,7 +82,7 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
let(:params) do
{
earlier_or_equal_to_sha: first_version.sha,
- earlier_or_equal_to_id: global_id_of(first_version)
+ earlier_or_equal_to_id: global_id_of(first_version)
}
end
@@ -95,7 +95,7 @@ RSpec.describe Resolvers::DesignManagement::VersionsResolver do
let(:params) do
{
earlier_or_equal_to_sha: first_version.sha,
- earlier_or_equal_to_id: global_id_of(other_version)
+ earlier_or_equal_to_id: global_id_of(other_version)
}
end
diff --git a/spec/graphql/resolvers/environments/last_deployment_resolver_spec.rb b/spec/graphql/resolvers/environments/last_deployment_resolver_spec.rb
new file mode 100644
index 00000000000..95a1a06730d
--- /dev/null
+++ b/spec/graphql/resolvers/environments/last_deployment_resolver_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Environments::LastDeploymentResolver do
+ include GraphqlHelpers
+ include Gitlab::Graphql::Laziness
+
+ let_it_be(:project) { create(:project, :repository, :private) }
+ let_it_be(:environment) { create(:environment, project: project) }
+ let_it_be(:deployment) { create(:deployment, :created, environment: environment, project: project) }
+ let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
+
+ let(:current_user) { developer }
+
+ describe '#resolve' do
+ it 'finds the deployment when status matches' do
+ expect(resolve_last_deployment(status: :created)).to eq(deployment)
+ end
+
+ it 'does not find the deployment when status does not match' do
+ expect(resolve_last_deployment(status: :success)).to be_nil
+ end
+
+ it 'raises an error when status is not specified' do
+ expect { resolve_last_deployment }.to raise_error(ArgumentError)
+ end
+
+ it 'raises an error when status is not supported' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError,
+ '"skipped" status is not supported.') do
+ resolve_last_deployment(status: :skipped)
+ end
+ end
+ end
+
+ def resolve_last_deployment(args = {}, context = { current_user: current_user })
+ force(resolve(described_class, obj: environment, ctx: context, args: args))
+ end
+end
diff --git a/spec/graphql/resolvers/group_members_resolver_spec.rb b/spec/graphql/resolvers/group_members_resolver_spec.rb
index bd0b4870062..d860b87875e 100644
--- a/spec/graphql/resolvers/group_members_resolver_spec.rb
+++ b/spec/graphql/resolvers/group_members_resolver_spec.rb
@@ -2,9 +2,11 @@
require 'spec_helper'
-RSpec.describe Resolvers::GroupMembersResolver do
+RSpec.describe 'Resolvers::GroupMembersResolver' do
include GraphqlHelpers
+ let(:described_class) { Resolvers::GroupMembersResolver }
+
specify do
expect(described_class).to have_nullable_graphql_type(Types::GroupMemberType.connection_type)
end
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index 89e45810033..a74b2a3f18c 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -311,49 +311,15 @@ RSpec.describe Resolvers::IssuesResolver do
end
context 'when searching issues' do
- it 'returns correct issues' do
- expect(resolve_issues(search: 'foo')).to contain_exactly(issue2)
- end
-
- it 'uses project search optimization' do
- expected_arguments = a_hash_including(
- search: 'foo',
- attempt_project_search_optimizations: true
- )
- expect(IssuesFinder).to receive(:new).with(anything, expected_arguments).and_call_original
-
- resolve_issues(search: 'foo')
- end
-
- context 'with anonymous user' do
- let_it_be(:public_project) { create(:project, :public) }
- let_it_be(:public_issue) { create(:issue, project: public_project, title: 'Test issue') }
-
- context 'with disable_anonymous_search enabled' do
- before do
- stub_feature_flags(disable_anonymous_search: true)
- end
-
- it 'generates an error' do
- error_message = "User must be authenticated to include the `search` argument."
-
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, error_message) do
- resolve(described_class, obj: public_project, args: { search: 'test' }, ctx: { current_user: nil })
- end
- end
- end
-
- context 'with disable_anonymous_search disabled' do
- before do
- stub_feature_flags(disable_anonymous_search: false)
- end
-
- it 'returns correct issues' do
- expect(
- resolve(described_class, obj: public_project, args: { search: 'test' }, ctx: { current_user: nil })
- ).to contain_exactly(public_issue)
- end
- end
+ it_behaves_like 'graphql query for searching issuables' do
+ let_it_be(:parent) { project }
+ let_it_be(:issuable1) { create(:issue, project: project, title: 'first created') }
+ let_it_be(:issuable2) { create(:issue, project: project, title: 'second created', description: 'text 1') }
+ let_it_be(:issuable3) { create(:issue, project: project, title: 'third', description: 'text 2') }
+ let_it_be(:issuable4) { create(:issue, project: project) }
+
+ let_it_be(:finder_class) { IssuesFinder }
+ let_it_be(:optimization_param) { :attempt_project_search_optimizations }
end
end
diff --git a/spec/graphql/resolvers/project_members_resolver_spec.rb b/spec/graphql/resolvers/project_members_resolver_spec.rb
index 2f4145b3215..c38cb3d157b 100644
--- a/spec/graphql/resolvers/project_members_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_members_resolver_spec.rb
@@ -2,9 +2,11 @@
require 'spec_helper'
-RSpec.describe Resolvers::ProjectMembersResolver do
+RSpec.describe 'Resolvers::ProjectMembersResolver' do
include GraphqlHelpers
+ let(:described_class) { Resolvers::ProjectMembersResolver }
+
it_behaves_like 'querying members with a group' do
let_it_be(:project) { create(:project, group: group_1) }
let_it_be(:resource_member) { create(:project_member, user: user_1, project: project) }
diff --git a/spec/graphql/resolvers/work_items_resolver_spec.rb b/spec/graphql/resolvers/work_items_resolver_spec.rb
index 29eac0ab46e..d89ccc7f806 100644
--- a/spec/graphql/resolvers/work_items_resolver_spec.rb
+++ b/spec/graphql/resolvers/work_items_resolver_spec.rb
@@ -19,13 +19,13 @@ RSpec.describe Resolvers::WorkItemsResolver do
let_it_be(:item2) do
create(:work_item, project: project, state: :closed, title: 'foo',
- created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at:
+ created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at:
1.hour.ago)
end
let_it_be(:item3) do
create(:work_item, project: other_project, state: :closed, title: 'foo',
- created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at:
+ created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at:
1.hour.ago)
end
@@ -52,49 +52,15 @@ RSpec.describe Resolvers::WorkItemsResolver do
end
context 'when searching items' do
- it 'returns correct items' do
- expect(resolve_items(search: 'foo')).to contain_exactly(item2)
- end
-
- it 'uses project search optimization' do
- expected_arguments = a_hash_including(
- search: 'foo',
- attempt_project_search_optimizations: true
- )
- expect(::WorkItems::WorkItemsFinder).to receive(:new).with(anything, expected_arguments).and_call_original
-
- resolve_items(search: 'foo')
- end
-
- context 'with anonymous user' do
- let_it_be(:public_project) { create(:project, :public) }
- let_it_be(:public_item) { create(:work_item, project: public_project, title: 'Test item') }
-
- context 'with disable_anonymous_search enabled' do
- before do
- stub_feature_flags(disable_anonymous_search: true)
- end
-
- it 'generates an error' do
- error_message = "User must be authenticated to include the `search` argument."
-
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, error_message) do
- resolve(described_class, obj: public_project, args: { search: 'test' }, ctx: { current_user: nil })
- end
- end
- end
-
- context 'with disable_anonymous_search disabled' do
- before do
- stub_feature_flags(disable_anonymous_search: false)
- end
-
- it 'returns correct items' do
- expect(
- resolve(described_class, obj: public_project, args: { search: 'test' }, ctx: { current_user: nil })
- ).to contain_exactly(public_item)
- end
- end
+ it_behaves_like 'graphql query for searching issuables' do
+ let_it_be(:parent) { project }
+ let_it_be(:issuable1) { create(:work_item, project: project, title: 'first created') }
+ let_it_be(:issuable2) { create(:work_item, project: project, title: 'second created', description: 'text 1') }
+ let_it_be(:issuable3) { create(:work_item, project: project, title: 'third', description: 'text 2') }
+ let_it_be(:issuable4) { create(:work_item, project: project) }
+
+ let_it_be(:finder_class) { ::WorkItems::WorkItemsFinder }
+ let_it_be(:optimization_param) { :attempt_project_search_optimizations }
end
end
diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb
index b85716e4d21..9f8a8717efb 100644
--- a/spec/graphql/types/base_field_spec.rb
+++ b/spec/graphql/types/base_field_spec.rb
@@ -205,39 +205,6 @@ RSpec.describe Types::BaseField do
end
end
end
-
- describe '#visible?' do
- context 'and has a feature_flag' do
- let(:flag) { :test_feature }
- let(:field) { described_class.new(name: 'test', type: GraphQL::Types::String, _deprecated_feature_flag: flag, null: false) }
- let(:context) { {} }
-
- before do
- skip_feature_flags_yaml_validation
- end
-
- it 'checks YAML definition for default_enabled' do
- # Exception is indicative of a check for YAML definition
- expect { field.visible?(context) }.to raise_error(Feature::InvalidFeatureFlagError, /The feature flag YAML definition for '#{flag}' does not exist/)
- end
-
- context 'skipping YAML check' do
- before do
- skip_default_enabled_yaml_check
- end
-
- it 'returns false if the feature is not enabled' do
- stub_feature_flags(flag => false)
-
- expect(field.visible?(context)).to eq(false)
- end
-
- it 'returns true if the feature is enabled' do
- expect(field.visible?(context)).to eq(true)
- end
- end
- end
- end
end
describe '#resolve' do
@@ -251,77 +218,11 @@ RSpec.describe Types::BaseField do
end
end
- describe '#description' do
- context 'feature flag given' do
- let(:field) { described_class.new(name: 'test', type: GraphQL::Types::String, _deprecated_feature_flag: flag, null: false, description: 'Test description.') }
- let(:flag) { :test_flag }
-
- it 'prepends the description' do
- expect(field.description).to start_with 'Test description. Available only when feature flag `test_flag` is enabled.'
- end
-
- context 'falsey feature_flag values' do
- using RSpec::Parameterized::TableSyntax
-
- where(:flag, :feature_value, :default_enabled) do
- '' | false | false
- '' | true | false
- nil | false | true
- nil | true | false
- end
-
- with_them do
- it 'returns the correct description' do
- expect(field.description).to eq('Test description.')
- end
- end
- end
-
- context 'with different default_enabled values' do
- using RSpec::Parameterized::TableSyntax
-
- where(:feature_value, :default_enabled, :expected_description) do
- disabled_ff_description = "Test description. Available only when feature flag `test_flag` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice."
- enabled_ff_description = "Test description. Available only when feature flag `test_flag` is enabled. This flag is enabled by default."
-
- false | false | disabled_ff_description
- true | false | disabled_ff_description
- false | true | enabled_ff_description
- true | true | enabled_ff_description
- end
-
- with_them do
- before do
- stub_feature_flags("#{flag}": feature_value)
-
- allow(Feature::Definition).to receive(:has_definition?).with(flag).and_return(true)
- allow(Feature::Definition).to receive(:default_enabled?).and_return(default_enabled)
- end
-
- it 'returns the correct availability in the description' do
- expect(field.description).to eq expected_description
- end
- end
- end
- end
- end
-
include_examples 'Gitlab-style deprecations' do
def subject(args = {})
base_args = { name: 'test', type: GraphQL::Types::String, null: true }
described_class.new(**base_args.merge(args))
end
-
- it 'interacts well with the `_deprecated_feature_flag` property' do
- field = subject(
- deprecated: { milestone: '1.10', reason: 'Deprecation reason' },
- description: 'Field description.',
- _deprecated_feature_flag: 'foo_flag'
- )
-
- expect(field.description).to start_with('Field description. Available only when feature flag `foo_flag` is enabled.')
- expect(field.description).to end_with('Deprecated in 1.10: Deprecation reason.')
- end
end
end
diff --git a/spec/graphql/types/branch_protections/merge_access_level_type_spec.rb b/spec/graphql/types/branch_protections/merge_access_level_type_spec.rb
new file mode 100644
index 00000000000..8cc1005d97e
--- /dev/null
+++ b/spec/graphql/types/branch_protections/merge_access_level_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['MergeAccessLevel'] do
+ subject { described_class }
+
+ let(:fields) { %i[access_level access_level_description] }
+
+ specify { is_expected.to require_graphql_authorizations(:read_protected_branch) }
+
+ specify { is_expected.to have_graphql_fields(fields).at_least }
+end
diff --git a/spec/graphql/types/branch_protections/push_access_level_type_spec.rb b/spec/graphql/types/branch_protections/push_access_level_type_spec.rb
new file mode 100644
index 00000000000..c78c0bda74c
--- /dev/null
+++ b/spec/graphql/types/branch_protections/push_access_level_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['PushAccessLevel'] do
+ subject { described_class }
+
+ let(:fields) { %i[access_level access_level_description] }
+
+ specify { is_expected.to require_graphql_authorizations(:read_protected_branch) }
+
+ specify { is_expected.to have_graphql_fields(fields).at_least }
+end
diff --git a/spec/graphql/types/branch_rule_type_spec.rb b/spec/graphql/types/branch_rule_type_spec.rb
new file mode 100644
index 00000000000..277901f00bf
--- /dev/null
+++ b/spec/graphql/types/branch_rule_type_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['BranchRule'] do
+ include GraphqlHelpers
+
+ subject { described_class }
+
+ let(:fields) do
+ %i[
+ name
+ branch_protection
+ created_at
+ updated_at
+ ]
+ end
+
+ specify { is_expected.to require_graphql_authorizations(:read_protected_branch) }
+
+ specify { is_expected.to have_graphql_fields(fields) }
+end
diff --git a/spec/graphql/types/branch_rules/branch_protection_type_spec.rb b/spec/graphql/types/branch_rules/branch_protection_type_spec.rb
new file mode 100644
index 00000000000..bbc92fd8fef
--- /dev/null
+++ b/spec/graphql/types/branch_rules/branch_protection_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['BranchProtection'] do
+ subject { described_class }
+
+ let(:fields) { %i[merge_access_levels push_access_levels allow_force_push] }
+
+ specify { is_expected.to require_graphql_authorizations(:read_protected_branch) }
+
+ specify { is_expected.to have_graphql_fields(fields).at_least }
+end
diff --git a/spec/graphql/types/ci/config_variable_type_spec.rb b/spec/graphql/types/ci/config_variable_type_spec.rb
new file mode 100644
index 00000000000..2b0937a7858
--- /dev/null
+++ b/spec/graphql/types/ci/config_variable_type_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CiConfigVariable'] do
+ specify { expect(described_class).to have_graphql_fields(:key, :description, :value).at_least }
+end
diff --git a/spec/graphql/types/ci/group_variable_connection_type_spec.rb b/spec/graphql/types/ci/group_variable_connection_type_spec.rb
new file mode 100644
index 00000000000..4a1fd490506
--- /dev/null
+++ b/spec/graphql/types/ci/group_variable_connection_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CiGroupVariableConnection'] do
+ it 'has the expected fields' do
+ expected_fields = %i[limit page_info edges nodes]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/instance_variable_type_spec.rb b/spec/graphql/types/ci/instance_variable_type_spec.rb
index cf4aaed31f1..c77a4ac1dc4 100644
--- a/spec/graphql/types/ci/instance_variable_type_spec.rb
+++ b/spec/graphql/types/ci/instance_variable_type_spec.rb
@@ -5,5 +5,5 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['CiInstanceVariable'] do
specify { expect(described_class.interfaces).to contain_exactly(Types::Ci::VariableInterface) }
- specify { expect(described_class).to have_graphql_fields(:masked, :protected).at_least }
+ specify { expect(described_class).to have_graphql_fields(:environment_scope, :masked, :protected).at_least }
end
diff --git a/spec/graphql/types/ci/job_artifact_type_spec.rb b/spec/graphql/types/ci/job_artifact_type_spec.rb
index 58b5f9cfcb7..3e054faf0c9 100644
--- a/spec/graphql/types/ci/job_artifact_type_spec.rb
+++ b/spec/graphql/types/ci/job_artifact_type_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['CiJobArtifact'] do
it 'has the correct fields' do
- expected_fields = [:download_path, :file_type, :name]
+ expected_fields = [:id, :download_path, :file_type, :name, :size, :expire_at]
expect(described_class).to have_graphql_fields(*expected_fields)
end
diff --git a/spec/graphql/types/ci/job_token_scope_type_spec.rb b/spec/graphql/types/ci/job_token_scope_type_spec.rb
index 457d46b6896..18f4d762d1e 100644
--- a/spec/graphql/types/ci/job_token_scope_type_spec.rb
+++ b/spec/graphql/types/ci/job_token_scope_type_spec.rb
@@ -69,8 +69,8 @@ RSpec.describe GitlabSchema.types['CiJobTokenScopeType'] do
expect(subject['errors']).to be_nil
end
- it 'returns nil' do
- expect(subject['data']['project']['ciJobTokenScope']).to be_nil
+ it 'returns readable projects in scope' do
+ expect(returned_project_paths).to contain_exactly(project.path)
end
end
end
diff --git a/spec/graphql/types/ci/job_type_spec.rb b/spec/graphql/types/ci/job_type_spec.rb
index bc9e64282bc..b3dee082d1f 100644
--- a/spec/graphql/types/ci/job_type_spec.rb
+++ b/spec/graphql/types/ci/job_type_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Types::Ci::JobType do
+ include GraphqlHelpers
+
specify { expect(described_class.graphql_name).to eq('CiJob') }
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Ci::Job) }
@@ -45,8 +47,21 @@ RSpec.describe Types::Ci::JobType do
tags
triggered
userPermissions
+ webPath
]
expect(described_class).to have_graphql_fields(*expected_fields)
end
+
+ describe '#web_path' do
+ subject { resolve_field(:web_path, build, current_user: user, object_type: described_class) }
+
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build, project: project, user: user) }
+
+ it 'returns the web path of the job' do
+ is_expected.to eq("/#{project.full_path}/-/jobs/#{build.id}")
+ end
+ end
end
diff --git a/spec/graphql/types/ci/manual_variable_type_spec.rb b/spec/graphql/types/ci/manual_variable_type_spec.rb
index 2884c818a52..21d36b7dfc0 100644
--- a/spec/graphql/types/ci/manual_variable_type_spec.rb
+++ b/spec/graphql/types/ci/manual_variable_type_spec.rb
@@ -4,4 +4,6 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['CiManualVariable'] do
specify { expect(described_class.interfaces).to contain_exactly(Types::Ci::VariableInterface) }
+
+ specify { expect(described_class).to have_graphql_fields(:environment_scope).at_least }
end
diff --git a/spec/graphql/types/ci/project_variable_connection_type_spec.rb b/spec/graphql/types/ci/project_variable_connection_type_spec.rb
new file mode 100644
index 00000000000..97c3a207f7f
--- /dev/null
+++ b/spec/graphql/types/ci/project_variable_connection_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CiProjectVariableConnection'] do
+ it 'has the expected fields' do
+ expected_fields = %i[limit page_info edges nodes]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/runner_architecture_type_spec.rb b/spec/graphql/types/ci/runner_architecture_type_spec.rb
index 527adef8cf9..60709acfd53 100644
--- a/spec/graphql/types/ci/runner_architecture_type_spec.rb
+++ b/spec/graphql/types/ci/runner_architecture_type_spec.rb
@@ -7,8 +7,8 @@ RSpec.describe Types::Ci::RunnerArchitectureType do
it 'exposes the expected fields' do
expected_fields = %i[
- name
- download_location
+ name
+ download_location
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/ci/runner_platform_type_spec.rb b/spec/graphql/types/ci/runner_platform_type_spec.rb
index 66b83f607d0..29b8e885183 100644
--- a/spec/graphql/types/ci/runner_platform_type_spec.rb
+++ b/spec/graphql/types/ci/runner_platform_type_spec.rb
@@ -7,9 +7,9 @@ RSpec.describe Types::Ci::RunnerPlatformType do
it 'exposes the expected fields' do
expected_fields = %i[
- name
- human_readable_name
- architectures
+ name
+ human_readable_name
+ architectures
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/ci/variable_interface_spec.rb b/spec/graphql/types/ci/variable_interface_spec.rb
index 8cef0ac2a14..328c5305a44 100644
--- a/spec/graphql/types/ci/variable_interface_spec.rb
+++ b/spec/graphql/types/ci/variable_interface_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['CiVariable'] do
specify do
expect(described_class).to have_graphql_fields(
- :id, :key, :value, :variable_type, :raw
+ :id, :key, :raw, :value, :variable_type
).at_least
end
end
diff --git a/spec/graphql/types/clusters/agent_type_spec.rb b/spec/graphql/types/clusters/agent_type_spec.rb
index 3f4faccf15d..bb1006c55c0 100644
--- a/spec/graphql/types/clusters/agent_type_spec.rb
+++ b/spec/graphql/types/clusters/agent_type_spec.rb
@@ -9,5 +9,5 @@ RSpec.describe GitlabSchema.types['ClusterAgent'] do
it { expect(described_class).to require_graphql_authorizations(:read_cluster) }
- it { expect(described_class).to have_graphql_fields(fields) }
+ it { expect(described_class).to include_graphql_fields(*fields) }
end
diff --git a/spec/graphql/types/customer_relations/organization_sort_enum_spec.rb b/spec/graphql/types/customer_relations/organization_sort_enum_spec.rb
new file mode 100644
index 00000000000..7ff498f0097
--- /dev/null
+++ b/spec/graphql/types/customer_relations/organization_sort_enum_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['OrganizationSort'] do
+ specify { expect(described_class.graphql_name).to eq('OrganizationSort') }
+
+ it_behaves_like 'common sort values'
+
+ it 'exposes all the contact sort values' do
+ expect(described_class.values.keys).to include(
+ *%w[
+ NAME_ASC
+ NAME_DESC
+ DESCRIPTION_ASC
+ DESCRIPTION_DESC
+ DEFAULT_RATE_ASC
+ DEFAULT_RATE_DESC
+ ]
+ )
+ end
+end
diff --git a/spec/graphql/types/customer_relations/organization_state_counts_type_spec.rb b/spec/graphql/types/customer_relations/organization_state_counts_type_spec.rb
new file mode 100644
index 00000000000..a2c8dacb1a5
--- /dev/null
+++ b/spec/graphql/types/customer_relations/organization_state_counts_type_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['OrganizationStateCounts'] do
+ include GraphqlHelpers
+
+ let(:fields) do
+ %w[
+ all
+ active
+ inactive
+ ]
+ end
+
+ let(:object) do
+ {
+ 'inactive' => 3,
+ 'active' => 4
+ }
+ end
+
+ it { expect(described_class.graphql_name).to eq('OrganizationStateCounts') }
+ it { expect(described_class).to have_graphql_fields(fields) }
+
+ describe '#all' do
+ it 'returns the sum of all counts' do
+ expect(resolve_field(:all, object)).to eq(7)
+ end
+ end
+end
diff --git a/spec/graphql/types/deployment_details_type_spec.rb b/spec/graphql/types/deployment_details_type_spec.rb
new file mode 100644
index 00000000000..70fdc38019e
--- /dev/null
+++ b/spec/graphql/types/deployment_details_type_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['DeploymentDetails'] do
+ specify { expect(described_class.graphql_name).to eq('DeploymentDetails') }
+
+ it 'has the expected fields' do
+ expected_fields = %w[
+ id iid ref tag tags sha created_at updated_at finished_at status commit job triggerer
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+
+ specify { expect(described_class).to require_graphql_authorizations(:read_deployment) }
+end
diff --git a/spec/graphql/types/deployment_type_spec.rb b/spec/graphql/types/deployment_type_spec.rb
new file mode 100644
index 00000000000..bf4be0523c6
--- /dev/null
+++ b/spec/graphql/types/deployment_type_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['Deployment'] do
+ specify { expect(described_class.graphql_name).to eq('Deployment') }
+
+ it 'has the expected fields' do
+ expected_fields = %w[
+ id iid ref tag sha created_at updated_at finished_at status commit job triggerer
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+
+ specify { expect(described_class).to require_graphql_authorizations(:read_deployment) }
+end
diff --git a/spec/graphql/types/detployment_tag_type_spec.rb b/spec/graphql/types/detployment_tag_type_spec.rb
new file mode 100644
index 00000000000..9a7a8db0970
--- /dev/null
+++ b/spec/graphql/types/detployment_tag_type_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['DeploymentTag'] do
+ specify { expect(described_class.graphql_name).to eq('DeploymentTag') }
+
+ it 'has the expected fields' do
+ expected_fields = %w[
+ name path
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/environment_type_spec.rb b/spec/graphql/types/environment_type_spec.rb
index 3671d35e8a5..ae58fe00af7 100644
--- a/spec/graphql/types/environment_type_spec.rb
+++ b/spec/graphql/types/environment_type_spec.rb
@@ -7,7 +7,8 @@ RSpec.describe GitlabSchema.types['Environment'] do
it 'has the expected fields' do
expected_fields = %w[
- name id state metrics_dashboard latest_opened_most_severe_alert path
+ name id state metrics_dashboard latest_opened_most_severe_alert path external_url deployments
+ slug createdAt updatedAt autoStopAt autoDeleteAt tier environmentType lastDeployment
]
expect(described_class).to have_graphql_fields(*expected_fields)
@@ -17,7 +18,7 @@ RSpec.describe GitlabSchema.types['Environment'] do
context 'when there is an environment' do
let_it_be(:project) { create(:project) }
- let_it_be(:environment) { create(:environment, project: project) }
+ let_it_be(:environment) { create(:environment, project: project, external_url: 'https://gitlab.com') }
let_it_be(:user) { create(:user) }
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
@@ -29,6 +30,7 @@ RSpec.describe GitlabSchema.types['Environment'] do
environment(name: "#{environment.name}") {
name
path
+ externalUrl
state
}
}
@@ -50,6 +52,10 @@ RSpec.describe GitlabSchema.types['Environment'] do
)
end
+ it 'returns the external url of the environment' do
+ expect(subject['data']['project']['environment']['externalUrl']).to eq(environment.external_url)
+ end
+
context 'when query alert data for the environment' do
let_it_be(:query) do
%(
diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb
index 72b3bb90194..0b65778ce90 100644
--- a/spec/graphql/types/group_type_spec.rb
+++ b/spec/graphql/types/group_type_spec.rb
@@ -24,8 +24,9 @@ RSpec.describe GitlabSchema.types['Group'] do
dependency_proxy_blobs dependency_proxy_image_count
dependency_proxy_blob_count dependency_proxy_total_size
dependency_proxy_image_prefix dependency_proxy_image_ttl_policy
- shared_runners_setting timelogs organizations contacts contact_state_counts
- work_item_types recent_issue_boards ci_variables
+ shared_runners_setting timelogs organization_state_counts organizations
+ contact_state_counts contacts work_item_types
+ recent_issue_boards ci_variables
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -62,6 +63,13 @@ RSpec.describe GitlabSchema.types['Group'] do
it { is_expected.to have_graphql_resolver(Resolvers::Crm::ContactStateCountsResolver) }
end
+ describe 'organization_state_counts field' do
+ subject { described_class.fields['organizationStateCounts'] }
+
+ it { is_expected.to have_graphql_type(Types::CustomerRelations::OrganizationStateCountsType) }
+ it { is_expected.to have_graphql_resolver(Resolvers::Crm::OrganizationStateCountsResolver) }
+ end
+
it_behaves_like 'a GraphQL type with labels' do
let(:labels_resolver_arguments) { [:search_term, :includeAncestorGroups, :includeDescendantGroups, :onlyGroupLabels] }
end
diff --git a/spec/graphql/types/merge_request_review_state_enum_spec.rb b/spec/graphql/types/merge_request_review_state_enum_spec.rb
index 407a1ae3c1f..486e1c4f502 100644
--- a/spec/graphql/types/merge_request_review_state_enum_spec.rb
+++ b/spec/graphql/types/merge_request_review_state_enum_spec.rb
@@ -12,10 +12,6 @@ RSpec.describe GitlabSchema.types['MergeRequestReviewState'] do
'UNREVIEWED' => have_attributes(
description: 'The merge request is unreviewed.',
value: 'unreviewed'
- ),
- 'ATTENTION_REQUESTED' => have_attributes(
- description: 'The merge request is attention_requested.',
- value: 'attention_requested'
)
)
end
diff --git a/spec/graphql/types/metrics/dashboard_type_spec.rb b/spec/graphql/types/metrics/dashboard_type_spec.rb
index 30dccc7c0be..114db87d5f1 100644
--- a/spec/graphql/types/metrics/dashboard_type_spec.rb
+++ b/spec/graphql/types/metrics/dashboard_type_spec.rb
@@ -7,8 +7,8 @@ RSpec.describe GitlabSchema.types['MetricsDashboard'] do
it 'has the expected fields' do
expected_fields = %w[
- path annotations schema_validation_warnings
- ]
+ path annotations schema_validation_warnings
+ ]
expect(described_class).to have_graphql_fields(*expected_fields)
end
diff --git a/spec/graphql/types/packages/composer/metadatum_type_spec.rb b/spec/graphql/types/packages/composer/metadatum_type_spec.rb
index a950c10a41d..272d518cdd5 100644
--- a/spec/graphql/types/packages/composer/metadatum_type_spec.rb
+++ b/spec/graphql/types/packages/composer/metadatum_type_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['ComposerMetadata'] do
it 'includes composer metadatum fields' do
expected_fields = %w[
- target_sha composer_json
+ target_sha composer_json
]
expect(described_class).to include_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/packages/package_type_enum_spec.rb b/spec/graphql/types/packages/package_type_enum_spec.rb
index 9d5a7716a61..fb93b1c8c8a 100644
--- a/spec/graphql/types/packages/package_type_enum_spec.rb
+++ b/spec/graphql/types/packages/package_type_enum_spec.rb
@@ -4,6 +4,6 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['PackageTypeEnum'] do
it 'exposes all package types' do
- expect(described_class.values.keys).to contain_exactly(*%w[MAVEN NPM CONAN NUGET PYPI COMPOSER GENERIC GOLANG DEBIAN RUBYGEMS HELM TERRAFORM_MODULE])
+ expect(described_class.values.keys).to contain_exactly(*%w[MAVEN NPM CONAN NUGET PYPI COMPOSER GENERIC GOLANG DEBIAN RUBYGEMS HELM TERRAFORM_MODULE RPM])
end
end
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 5ff7653ce39..617cbdb07fe 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['Project'] do
include GraphqlHelpers
- include Ci::TemplateHelpers
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Project) }
@@ -37,7 +36,7 @@ RSpec.describe GitlabSchema.types['Project'] do
cluster_agent cluster_agents agent_configurations
ci_template timelogs merge_commit_template squash_commit_template work_item_types
recent_issue_boards ci_config_path_or_default packages_cleanup_policy ci_variables
- timelog_categories fork_targets
+ timelog_categories fork_targets branch_rules ci_config_variables
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -509,6 +508,20 @@ RSpec.describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_resolver(Resolvers::Ci::JobTokenScopeResolver) }
end
+ describe 'branch_rules field' do
+ subject { described_class.fields['branchRules'] }
+
+ let(:br_resolver) { Resolvers::Projects::BranchRulesResolver }
+
+ specify do
+ is_expected.to have_graphql_type(
+ Types::Projects::BranchRuleType.connection_type
+ )
+ end
+
+ specify { is_expected.to have_graphql_resolver(br_resolver) }
+ end
+
describe 'agent_configurations' do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
@@ -682,4 +695,54 @@ RSpec.describe GitlabSchema.types['Project'] do
end
end
end
+
+ describe 'branch_rules' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project, reload: true) { create(:project, :public) }
+ let_it_be(:name) { 'feat/*' }
+ let_it_be(:protected_branch) do
+ create(:protected_branch, project: project, name: name)
+ end
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ branchRules {
+ nodes {
+ name
+ }
+ }
+ }
+ }
+ )
+ end
+
+ let(:branch_rules_data) do
+ subject.dig('data', 'project', 'branchRules', 'nodes')
+ end
+
+ subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
+
+ context 'when a user can read protected branches' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'is present and correct' do
+ expect(branch_rules_data.count).to eq(1)
+ expect(branch_rules_data.first['name']).to eq(name)
+ end
+ end
+
+ context 'when a user cannot read protected branches' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'is empty' do
+ expect(branch_rules_data.count).to eq(0)
+ end
+ end
+ end
end
diff --git a/spec/graphql/types/subscription_type_spec.rb b/spec/graphql/types/subscription_type_spec.rb
index 9b043fa52cf..860cbbf0c15 100644
--- a/spec/graphql/types/subscription_type_spec.rb
+++ b/spec/graphql/types/subscription_type_spec.rb
@@ -10,8 +10,9 @@ RSpec.describe GitlabSchema.types['Subscription'] do
issuable_title_updated
issuable_labels_updated
issuable_dates_updated
+ merge_request_reviewers_updated
]
- expect(described_class).to have_graphql_fields(*expected_fields).only
+ expect(described_class).to include_graphql_fields(*expected_fields)
end
end
diff --git a/spec/graphql/types/timelog_type_spec.rb b/spec/graphql/types/timelog_type_spec.rb
index c897a25d10d..3a26ba89e04 100644
--- a/spec/graphql/types/timelog_type_spec.rb
+++ b/spec/graphql/types/timelog_type_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe GitlabSchema.types['Timelog'] do
it { expect(described_class.graphql_name).to eq('Timelog') }
it { expect(described_class).to have_graphql_fields(fields) }
- it { expect(described_class).to require_graphql_authorizations(:read_issue) }
+ it { expect(described_class).to require_graphql_authorizations(:read_issuable) }
it { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Timelog) }
describe 'user field' do
diff --git a/spec/graphql/types/user_merge_request_interaction_type_spec.rb b/spec/graphql/types/user_merge_request_interaction_type_spec.rb
index 4782a1faf8d..3cd9750debb 100644
--- a/spec/graphql/types/user_merge_request_interaction_type_spec.rb
+++ b/spec/graphql/types/user_merge_request_interaction_type_spec.rb
@@ -76,11 +76,8 @@ RSpec.describe GitlabSchema.types['UserMergeRequestInteraction'] do
context 'when the user has been asked to review the MR' do
before do
merge_request.reviewers << user
- merge_request.find_reviewer(user).update!(state: :attention_requested)
end
- it { is_expected.to eq(Types::MergeRequestReviewStateEnum.values['ATTENTION_REQUESTED'].value) }
-
it 'implies not reviewed' do
expect(resolve(:reviewed)).to be false
end
diff --git a/spec/graphql/types/work_item_type_spec.rb b/spec/graphql/types/work_item_type_spec.rb
index c556424b0b4..11b02a88dbd 100644
--- a/spec/graphql/types/work_item_type_spec.rb
+++ b/spec/graphql/types/work_item_type_spec.rb
@@ -28,8 +28,6 @@ RSpec.describe GitlabSchema.types['WorkItem'] do
closed_at
]
- fields.each do |field_name|
- expect(described_class).to have_graphql_fields(*fields)
- end
+ expect(described_class).to have_graphql_fields(*fields)
end
end
diff --git a/spec/graphql/types/work_items/widgets/description_type_spec.rb b/spec/graphql/types/work_items/widgets/description_type_spec.rb
index 5ade1fe4aa2..aee388ce82a 100644
--- a/spec/graphql/types/work_items/widgets/description_type_spec.rb
+++ b/spec/graphql/types/work_items/widgets/description_type_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Types::WorkItems::Widgets::DescriptionType do
it 'exposes the expected fields' do
- expected_fields = %i[description description_html type]
+ expected_fields = %i[description description_html edited last_edited_at last_edited_by type]
expect(described_class).to have_graphql_fields(*expected_fields)
end