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/requests/api/graphql')
-rw-r--r--spec/requests/api/graphql/boards/board_lists_query_spec.rb6
-rw-r--r--spec/requests/api/graphql/ci/config_spec.rb144
-rw-r--r--spec/requests/api/graphql/ci/job_spec.rb15
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb18
-rw-r--r--spec/requests/api/graphql/ci/runners_spec.rb4
-rw-r--r--spec/requests/api/graphql/container_repository/container_repository_details_spec.rb8
-rw-r--r--spec/requests/api/graphql/current_user_todos_spec.rb8
-rw-r--r--spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb12
-rw-r--r--spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb12
-rw-r--r--spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb4
-rw-r--r--spec/requests/api/graphql/group/group_members_spec.rb50
-rw-r--r--spec/requests/api/graphql/group/merge_requests_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/milestones_spec.rb8
-rw-r--r--spec/requests/api/graphql/issue/issue_spec.rb5
-rw-r--r--spec/requests/api/graphql/merge_request/merge_request_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb (renamed from spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb)2
-rw-r--r--spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb14
-rw-r--r--spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb60
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb67
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb62
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb80
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb22
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/request_attention_spec.rb79
-rw-r--r--spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/note_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/remove_attention_request_spec.rb79
-rw-r--r--spec/requests/api/graphql/mutations/timelogs/delete_spec.rb38
-rw-r--r--spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb8
-rw-r--r--spec/requests/api/graphql/mutations/todos/restore_many_spec.rb8
-rw-r--r--spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb93
-rw-r--r--spec/requests/api/graphql/packages/conan_spec.rb21
-rw-r--r--spec/requests/api/graphql/packages/maven_spec.rb8
-rw-r--r--spec/requests/api/graphql/packages/nuget_spec.rb17
-rw-r--r--spec/requests/api/graphql/packages/package_spec.rb26
-rw-r--r--spec/requests/api/graphql/packages/pypi_spec.rb5
-rw-r--r--spec/requests/api/graphql/project/alert_management/integrations_spec.rb57
-rw-r--r--spec/requests/api/graphql/project/cluster_agents_spec.rb8
-rw-r--r--spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb127
-rw-r--r--spec/requests/api/graphql/project/issue/design_collection/version_spec.rb29
-rw-r--r--spec/requests/api/graphql/project/issue/designs/designs_spec.rb22
-rw-r--r--spec/requests/api/graphql/project/issue/designs/notes_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue_spec.rb7
-rw-r--r--spec/requests/api/graphql/project/merge_request_spec.rb6
-rw-r--r--spec/requests/api/graphql/project/merge_requests_spec.rb41
-rw-r--r--spec/requests/api/graphql/project/milestones_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/pipeline_spec.rb19
-rw-r--r--spec/requests/api/graphql/project/project_members_spec.rb9
-rw-r--r--spec/requests/api/graphql/project/release_spec.rb40
-rw-r--r--spec/requests/api/graphql/project/terraform/state_spec.rb18
-rw-r--r--spec/requests/api/graphql/project/terraform/states_spec.rb17
-rw-r--r--spec/requests/api/graphql/query_spec.rb16
-rw-r--r--spec/requests/api/graphql/user/starred_projects_query_spec.rb18
-rw-r--r--spec/requests/api/graphql/user_query_spec.rb72
-rw-r--r--spec/requests/api/graphql/users_spec.rb26
-rw-r--r--spec/requests/api/graphql/work_item_spec.rb3
60 files changed, 1161 insertions, 387 deletions
diff --git a/spec/requests/api/graphql/boards/board_lists_query_spec.rb b/spec/requests/api/graphql/boards/board_lists_query_spec.rb
index e8fb9daa43b..eb206465bce 100644
--- a/spec/requests/api/graphql/boards/board_lists_query_spec.rb
+++ b/spec/requests/api/graphql/boards/board_lists_query_spec.rb
@@ -69,6 +69,10 @@ RSpec.describe 'get board lists' do
let(:data_path) { [board_parent_type, :boards, :nodes, 0, :lists] }
+ def pagination_results_data(lists)
+ lists
+ end
+
def pagination_query(params)
graphql_query_for(
board_parent_type,
@@ -94,7 +98,7 @@ RSpec.describe 'get board lists' do
it_behaves_like 'sorted paginated query' do
let(:sort_param) { }
let(:first_param) { 2 }
- let(:all_records) { lists.map { |list| global_id_of(list) } }
+ let(:all_records) { lists.map { |list| a_graphql_entity_for(list) } }
end
end
end
diff --git a/spec/requests/api/graphql/ci/config_spec.rb b/spec/requests/api/graphql/ci/config_spec.rb
index 62b15a8396c..5f8a895b16e 100644
--- a/spec/requests/api/graphql/ci/config_spec.rb
+++ b/spec/requests/api/graphql/ci/config_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Query.ciConfig' do
include GraphqlHelpers
+ include StubRequests
subject(:post_graphql_query) { post_graphql(query, current_user: user) }
@@ -57,6 +58,16 @@ RSpec.describe 'Query.ciConfig' do
}
}
}
+ mergedYaml
+ includes {
+ type
+ location
+ blob
+ raw
+ extra
+ contextProject
+ contextSha
+ }
}
}
)
@@ -71,10 +82,12 @@ RSpec.describe 'Query.ciConfig' do
it 'returns the correct structure' do
post_graphql_query
- expect(graphql_data['ciConfig']).to eq(
+ expect(graphql_data['ciConfig']).to include(
"status" => "VALID",
"errors" => [],
"warnings" => [],
+ "includes" => [],
+ "mergedYaml" => a_kind_of(String),
"stages" =>
{
"nodes" =>
@@ -222,24 +235,6 @@ RSpec.describe 'Query.ciConfig' do
)
end
- context 'when using deprecated keywords' do
- let_it_be(:content) do
- YAML.dump(
- rspec: { script: 'ls', type: 'test' },
- types: ['test']
- )
- end
-
- it 'returns a warning' do
- post_graphql_query
-
- expect(graphql_data['ciConfig']['warnings']).to include(
- 'root `types` is deprecated in 9.0 and will be removed in 15.0.',
- 'jobs:rspec `type` is deprecated in 9.0 and will be removed in 15.0.'
- )
- end
- end
-
context 'when the config file includes other files' do
let_it_be(:content) do
YAML.dump(
@@ -271,6 +266,18 @@ RSpec.describe 'Query.ciConfig' do
"status" => "VALID",
"errors" => [],
"warnings" => [],
+ "includes" => [
+ {
+ "type" => "local",
+ "location" => "other_file.yml",
+ "blob" => "http://localhost/#{project.full_path}/-/blob/#{project.commit.sha}/other_file.yml",
+ "raw" => "http://localhost/#{project.full_path}/-/raw/#{project.commit.sha}/other_file.yml",
+ "extra" => {},
+ "contextProject" => project.full_path,
+ "contextSha" => project.commit.sha
+ }
+ ],
+ "mergedYaml" => "---\nbuild:\n script: build\nrspec:\n script: rspec\n",
"stages" =>
{
"nodes" =>
@@ -302,7 +309,7 @@ RSpec.describe 'Query.ciConfig' do
"when" => "on_success",
"tags" => [],
"needs" => { "nodes" => [] }
-}
+ }
]
}
},
@@ -337,4 +344,101 @@ RSpec.describe 'Query.ciConfig' do
)
end
end
+
+ context 'when the config file has multiple includes' do
+ let_it_be(:other_project) { create(:project, :repository, creator: user, namespace: user.namespace) }
+
+ let_it_be(:content) do
+ YAML.dump(
+ include: [
+ { local: 'other_file.yml' },
+ { remote: 'https://gitlab.com/gitlab-org/gitlab/raw/1234/.hello.yml' },
+ { file: 'other_project_file.yml', project: other_project.full_path },
+ { template: 'Jobs/Build.gitlab-ci.yml' }
+ ],
+ rspec: {
+ script: 'rspec'
+ }
+ )
+ end
+
+ let(:remote_file_content) do
+ YAML.dump(
+ remote_file_test: {
+ script: 'remote_file_test'
+ }
+ )
+ end
+
+ before do
+ allow_next_instance_of(Repository) do |repository|
+ allow(repository).to receive(:blob_data_at).with(an_instance_of(String), 'other_file.yml') do
+ YAML.dump(
+ build: {
+ script: 'build'
+ }
+ )
+ end
+
+ allow(repository).to receive(:blob_data_at).with(an_instance_of(String), 'other_project_file.yml') do
+ YAML.dump(
+ other_project_test: {
+ script: 'other_project_test'
+ }
+ )
+ end
+ end
+
+ stub_full_request('https://gitlab.com/gitlab-org/gitlab/raw/1234/.hello.yml').to_return(body: remote_file_content)
+
+ post_graphql_query
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ # rubocop:disable Layout/LineLength
+ it 'returns correct includes' do
+ expect(graphql_data['ciConfig']["includes"]).to eq(
+ [
+ {
+ "type" => "local",
+ "location" => "other_file.yml",
+ "blob" => "http://localhost/#{project.full_path}/-/blob/#{project.commit.sha}/other_file.yml",
+ "raw" => "http://localhost/#{project.full_path}/-/raw/#{project.commit.sha}/other_file.yml",
+ "extra" => {},
+ "contextProject" => project.full_path,
+ "contextSha" => project.commit.sha
+ },
+ {
+ "type" => "remote",
+ "location" => "https://gitlab.com/gitlab-org/gitlab/raw/1234/.hello.yml",
+ "blob" => nil,
+ "raw" => "https://gitlab.com/gitlab-org/gitlab/raw/1234/.hello.yml",
+ "extra" => {},
+ "contextProject" => project.full_path,
+ "contextSha" => project.commit.sha
+ },
+ {
+ "type" => "file",
+ "location" => "other_project_file.yml",
+ "blob" => "http://localhost/#{other_project.full_path}/-/blob/#{other_project.commit.sha}/other_project_file.yml",
+ "raw" => "http://localhost/#{other_project.full_path}/-/raw/#{other_project.commit.sha}/other_project_file.yml",
+ "extra" => { "project" => other_project.full_path, "ref" => "HEAD" },
+ "contextProject" => project.full_path,
+ "contextSha" => project.commit.sha
+ },
+ {
+ "type" => "template",
+ "location" => "Jobs/Build.gitlab-ci.yml",
+ "blob" => nil,
+ "raw" => "https://gitlab.com/gitlab-org/gitlab/-/raw/master/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml",
+ "extra" => {},
+ "contextProject" => project.full_path,
+ "contextSha" => project.commit.sha
+ }
+ ]
+ )
+ end
+ # rubocop:enable Layout/LineLength
+ end
end
diff --git a/spec/requests/api/graphql/ci/job_spec.rb b/spec/requests/api/graphql/ci/job_spec.rb
index ddb2664d353..2fb90dcd92b 100644
--- a/spec/requests/api/graphql/ci/job_spec.rb
+++ b/spec/requests/api/graphql/ci/job_spec.rb
@@ -47,10 +47,8 @@ RSpec.describe 'Query.project(fullPath).pipelines.job(id)' do
)
post_graphql(query, current_user: user)
- expect(graphql_data_at(*path)).to match a_hash_including(
- 'id' => global_id_of(job_2),
- 'name' => job_2.name,
- 'allowFailure' => job_2.allow_failure,
+ expect(graphql_data_at(*path)).to match a_graphql_entity_for(
+ job_2, :name, :allow_failure,
'duration' => 25,
'kind' => 'BUILD',
'queuedDuration' => 2.0,
@@ -66,10 +64,7 @@ RSpec.describe 'Query.project(fullPath).pipelines.job(id)' do
it 'retrieves scalar fields' do
post_graphql(query, current_user: user)
- expect(graphql_data_at(*path)).to match a_hash_including(
- 'id' => global_id_of(job_2),
- 'name' => job_2.name
- )
+ expect(graphql_data_at(*path)).to match a_graphql_entity_for(job_2, :name)
end
end
end
@@ -102,8 +97,8 @@ RSpec.describe 'Query.project(fullPath).pipelines.job(id)' do
'name' => test_stage.name,
'jobs' => a_hash_including(
'nodes' => contain_exactly(
- a_hash_including('id' => global_id_of(job_2)),
- a_hash_including('id' => global_id_of(job_3))
+ a_graphql_entity_for(job_2),
+ a_graphql_entity_for(job_3)
)
)
)
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index 39f0f696b08..6fa455cbfca 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -11,7 +11,8 @@ RSpec.describe 'Query.runner(id)' do
let_it_be(:active_instance_runner) do
create(:ci_runner, :instance, description: 'Runner 1', contacted_at: 2.hours.ago,
active: true, version: 'adfe156', revision: 'a', locked: true, ip_address: '127.0.0.1', maximum_timeout: 600,
- access_level: 0, tag_list: %w[tag1 tag2], run_untagged: true, executor_type: :custom)
+ access_level: 0, tag_list: %w[tag1 tag2], run_untagged: true, executor_type: :custom,
+ maintenance_note: 'Test maintenance note')
end
let_it_be(:inactive_instance_runner) do
@@ -27,10 +28,6 @@ RSpec.describe 'Query.runner(id)' do
let_it_be(:active_project_runner) { create(:ci_runner, :project) }
- before do
- allow(Gitlab::Ci::RunnerUpgradeCheck.instance).to receive(:check_runner_upgrade_status)
- end
-
shared_examples 'runner details fetch' do
let(:query) do
wrap_fields(query_graphql_path(query_path, all_graphql_fields_for('CiRunner')))
@@ -66,6 +63,9 @@ RSpec.describe 'Query.runner(id)' do
'ipAddress' => runner.ip_address,
'runnerType' => runner.instance_type? ? 'INSTANCE_TYPE' : 'PROJECT_TYPE',
'executorName' => runner.executor_type&.dasherize,
+ 'architectureName' => runner.architecture,
+ 'platformName' => runner.platform,
+ 'maintenanceNote' => runner.maintenance_note,
'jobCount' => 0,
'jobs' => a_hash_including("count" => 0, "nodes" => [], "pageInfo" => anything),
'projectCount' => nil,
@@ -239,8 +239,8 @@ RSpec.describe 'Query.runner(id)' do
stale_runner_data = graphql_data_at(:stale_runner)
expect(stale_runner_data).to match a_hash_including(
- 'status' => 'NOT_CONNECTED',
- 'legacyStatusWithExplicitVersion' => 'NOT_CONNECTED',
+ 'status' => 'STALE',
+ 'legacyStatusWithExplicitVersion' => 'STALE',
'newStatus' => 'STALE'
)
@@ -253,8 +253,8 @@ RSpec.describe 'Query.runner(id)' do
never_contacted_instance_runner_data = graphql_data_at(:never_contacted_instance_runner)
expect(never_contacted_instance_runner_data).to match a_hash_including(
- 'status' => 'NOT_CONNECTED',
- 'legacyStatusWithExplicitVersion' => 'NOT_CONNECTED',
+ 'status' => 'NEVER_CONTACTED',
+ 'legacyStatusWithExplicitVersion' => 'NEVER_CONTACTED',
'newStatus' => 'NEVER_CONTACTED'
)
end
diff --git a/spec/requests/api/graphql/ci/runners_spec.rb b/spec/requests/api/graphql/ci/runners_spec.rb
index 6b88c82b025..d3e94671724 100644
--- a/spec/requests/api/graphql/ci/runners_spec.rb
+++ b/spec/requests/api/graphql/ci/runners_spec.rb
@@ -56,9 +56,9 @@ RSpec.describe 'Query.runners' do
it_behaves_like 'a working graphql query returning expected runner'
end
- context 'runner_type is PROJECT_TYPE and status is NOT_CONNECTED' do
+ context 'runner_type is PROJECT_TYPE and status is NEVER_CONTACTED' do
let(:runner_type) { 'PROJECT_TYPE' }
- let(:status) { 'NOT_CONNECTED' }
+ let(:status) { 'NEVER_CONTACTED' }
let!(:expected_runner) { project_runner }
diff --git a/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb b/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
index 922a9ab277e..847fa72522e 100644
--- a/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
+++ b/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
@@ -127,7 +127,7 @@ RSpec.describe 'container repository details' do
let(:query) do
<<~GQL
- query($id: ID!, $n: Int) {
+ query($id: ContainerRepositoryID!, $n: Int) {
containerRepository(id: $id) {
tags(first: $n) {
edges {
@@ -157,7 +157,7 @@ RSpec.describe 'container repository details' do
let(:query) do
<<~GQL
- query($id: ID!, $n: ContainerRepositoryTagSort) {
+ query($id: ContainerRepositoryID!, $n: ContainerRepositoryTagSort) {
containerRepository(id: $id) {
tags(sort: $n) {
edges {
@@ -194,7 +194,7 @@ RSpec.describe 'container repository details' do
let(:query) do
<<~GQL
- query($id: ID!, $n: String) {
+ query($id: ContainerRepositoryID!, $n: String) {
containerRepository(id: $id) {
tags(name: $n) {
edges {
@@ -232,7 +232,7 @@ RSpec.describe 'container repository details' do
let(:query) do
<<~GQL
- query($id: ID!) {
+ query($id: ContainerRepositoryID!) {
containerRepository(id: $id) {
size
}
diff --git a/spec/requests/api/graphql/current_user_todos_spec.rb b/spec/requests/api/graphql/current_user_todos_spec.rb
index 7f37abba74a..da1c893ec2b 100644
--- a/spec/requests/api/graphql/current_user_todos_spec.rb
+++ b/spec/requests/api/graphql/current_user_todos_spec.rb
@@ -37,8 +37,8 @@ RSpec.describe 'A Todoable that implements the CurrentUserTodos interface' do
post_graphql(query, current_user: current_user)
expect(todoable_response).to contain_exactly(
- a_hash_including('id' => global_id_of(done_todo)),
- a_hash_including('id' => global_id_of(pending_todo))
+ a_graphql_entity_for(done_todo),
+ a_graphql_entity_for(pending_todo)
)
end
@@ -63,7 +63,7 @@ RSpec.describe 'A Todoable that implements the CurrentUserTodos interface' do
post_graphql(query, current_user: current_user)
expect(todoable_response).to contain_exactly(
- a_hash_including('id' => global_id_of(pending_todo))
+ a_graphql_entity_for(pending_todo)
)
end
end
@@ -75,7 +75,7 @@ RSpec.describe 'A Todoable that implements the CurrentUserTodos interface' do
post_graphql(query, current_user: current_user)
expect(todoable_response).to contain_exactly(
- a_hash_including('id' => global_id_of(done_todo))
+ a_graphql_entity_for(done_todo)
)
end
end
diff --git a/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb b/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb
index de3dbc5c324..d21c3046c1a 100644
--- a/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb
+++ b/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb
@@ -47,14 +47,14 @@ RSpec.describe 'getting dependency proxy settings for a group' do
context 'with different permissions' do
where(:group_visibility, :role, :access_granted) do
:private | :maintainer | true
- :private | :developer | true
- :private | :reporter | true
- :private | :guest | true
+ :private | :developer | false
+ :private | :reporter | false
+ :private | :guest | false
:private | :anonymous | false
:public | :maintainer | true
- :public | :developer | true
- :public | :reporter | true
- :public | :guest | true
+ :public | :developer | false
+ :public | :reporter | false
+ :public | :guest | false
:public | :anonymous | false
end
diff --git a/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb b/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb
index c8797d84906..40f4b082072 100644
--- a/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb
+++ b/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb
@@ -46,14 +46,14 @@ RSpec.describe 'getting dependency proxy image ttl policy for a group' do
context 'with different permissions' do
where(:group_visibility, :role, :access_granted) do
:private | :maintainer | true
- :private | :developer | true
- :private | :reporter | true
- :private | :guest | true
+ :private | :developer | false
+ :private | :reporter | false
+ :private | :guest | false
:private | :anonymous | false
:public | :maintainer | true
- :public | :developer | true
- :public | :reporter | true
- :public | :guest | true
+ :public | :developer | false
+ :public | :reporter | false
+ :public | :guest | false
:public | :anonymous | false
end
diff --git a/spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb b/spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb
index 3527c8183f6..c7149c100b2 100644
--- a/spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb
+++ b/spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb
@@ -122,12 +122,12 @@ RSpec.describe 'getting dependency proxy manifests in a group' do
let(:current_user) { owner }
context 'with default sorting' do
- let_it_be(:descending_manifests) { manifests.reverse.map { |manifest| global_id_of(manifest)} }
+ let_it_be(:descending_manifests) { manifests.reverse.map { |manifest| global_id_of(manifest) } }
it_behaves_like 'sorted paginated query' do
let(:sort_param) { '' }
let(:first_param) { 2 }
- let(:all_records) { descending_manifests }
+ let(:all_records) { descending_manifests.map(&:to_s) }
end
end
diff --git a/spec/requests/api/graphql/group/group_members_spec.rb b/spec/requests/api/graphql/group/group_members_spec.rb
index 78852622835..fec866486ae 100644
--- a/spec/requests/api/graphql/group/group_members_spec.rb
+++ b/spec/requests/api/graphql/group/group_members_spec.rb
@@ -24,8 +24,8 @@ RSpec.describe 'getting group members information' do
expect(graphql_errors).to be_nil
expect(graphql_data_at(:group, :group_members, :edges, :node)).to contain_exactly(
- { 'user' => { 'id' => global_id_of(user_1) } },
- { 'user' => { 'id' => global_id_of(user_2) } },
+ { 'user' => a_graphql_entity_for(user_1) },
+ { 'user' => a_graphql_entity_for(user_2) },
'user' => nil
)
end
@@ -77,6 +77,48 @@ RSpec.describe 'getting group members information' do
end
end
+ context 'by access levels' do
+ before do
+ parent_group.add_owner(user_1)
+ parent_group.add_maintainer(user_2)
+ end
+
+ subject(:by_access_levels) { fetch_members(group: parent_group, args: { access_levels: access_levels }) }
+
+ context 'by owner' do
+ let(:access_levels) { :OWNER }
+
+ it 'returns owner' do
+ by_access_levels
+
+ expect(graphql_errors).to be_nil
+ expect_array_response(user_1)
+ end
+ end
+
+ context 'by maintainer' do
+ let(:access_levels) { :MAINTAINER }
+
+ it 'returns maintainer' do
+ by_access_levels
+
+ expect(graphql_errors).to be_nil
+ expect_array_response(user_2)
+ end
+ end
+
+ context 'by owner and maintainer' do
+ let(:access_levels) { [:OWNER, :MAINTAINER] }
+
+ it 'returns owner and maintainer' do
+ by_access_levels
+
+ expect(graphql_errors).to be_nil
+ expect_array_response(user_1, user_2)
+ end
+ end
+ end
+
context 'member relations' do
let_it_be(:child_group) { create(:group, :public, parent: parent_group) }
let_it_be(:grandchild_group) { create(:group, :public, parent: child_group) }
@@ -182,8 +224,8 @@ RSpec.describe 'getting group members information' do
def expect_array_response(*items)
expect(response).to have_gitlab_http_status(:success)
- member_gids = graphql_data_at(:group, :group_members, :edges, :node, :user, :id)
+ members = graphql_data_at(:group, :group_members, :edges, :node, :user)
- expect(member_gids).to match_array(items.map { |u| global_id_of(u) })
+ expect(members).to match_array(items.map { |u| a_graphql_entity_for(u) })
end
end
diff --git a/spec/requests/api/graphql/group/merge_requests_spec.rb b/spec/requests/api/graphql/group/merge_requests_spec.rb
index c0faff11c8d..434b0d16569 100644
--- a/spec/requests/api/graphql/group/merge_requests_spec.rb
+++ b/spec/requests/api/graphql/group/merge_requests_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe 'Query.group.mergeRequests' do
end
def expected_mrs(mrs)
- mrs.map { |mr| a_hash_including('id' => global_id_of(mr)) }
+ mrs.map { |mr| a_graphql_entity_for(mr) }
end
describe 'not passing any arguments' do
diff --git a/spec/requests/api/graphql/group/milestones_spec.rb b/spec/requests/api/graphql/group/milestones_spec.rb
index 2b80b5239c8..7c51409f907 100644
--- a/spec/requests/api/graphql/group/milestones_spec.rb
+++ b/spec/requests/api/graphql/group/milestones_spec.rb
@@ -170,10 +170,8 @@ RSpec.describe 'Milestones through GroupQuery' do
end
it 'returns correct values for scalar fields' do
- expect(post_query).to eq({
- 'id' => global_id_of(milestone),
- 'title' => milestone.title,
- 'description' => milestone.description,
+ expect(post_query).to match a_graphql_entity_for(
+ milestone, :title, :description,
'state' => 'active',
'webPath' => milestone_path(milestone),
'dueDate' => milestone.due_date.iso8601,
@@ -183,7 +181,7 @@ RSpec.describe 'Milestones through GroupQuery' do
'projectMilestone' => false,
'groupMilestone' => true,
'subgroupMilestone' => false
- })
+ )
end
context 'milestone statistics' do
diff --git a/spec/requests/api/graphql/issue/issue_spec.rb b/spec/requests/api/graphql/issue/issue_spec.rb
index 42ca3348384..05fd6bf3022 100644
--- a/spec/requests/api/graphql/issue/issue_spec.rb
+++ b/spec/requests/api/graphql/issue/issue_spec.rb
@@ -8,8 +8,8 @@ RSpec.describe 'Query.issue(id)' do
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
- let_it_be(:issue_params) { { 'id' => issue.to_global_id.to_s } }
+ let(:issue_params) { { 'id' => global_id_of(issue) } }
let(:issue_data) { graphql_data['issue'] }
let(:issue_fields) { all_graphql_fields_for('Issue'.classify) }
@@ -100,7 +100,8 @@ RSpec.describe 'Query.issue(id)' do
let_it_be(:issue_fields) { ['moved', 'movedTo { title }'] }
let_it_be(:new_issue) { create(:issue) }
let_it_be(:issue) { create(:issue, project: project, moved_to: new_issue) }
- let_it_be(:issue_params) { { 'id' => issue.to_global_id.to_s } }
+
+ let(:issue_params) { { 'id' => global_id_of(issue) } }
before_all do
new_issue.project.add_developer(current_user)
diff --git a/spec/requests/api/graphql/merge_request/merge_request_spec.rb b/spec/requests/api/graphql/merge_request/merge_request_spec.rb
index 75dd01a0763..d89f381753e 100644
--- a/spec/requests/api/graphql/merge_request/merge_request_spec.rb
+++ b/spec/requests/api/graphql/merge_request/merge_request_spec.rb
@@ -8,8 +8,8 @@ RSpec.describe 'Query.merge_request(id)' do
let_it_be(:project) { create(:project, :empty_repo) }
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
let_it_be(:current_user) { create(:user) }
- let_it_be(:merge_request_params) { { 'id' => merge_request.to_global_id.to_s } }
+ let(:merge_request_params) { { 'id' => global_id_of(merge_request) } }
let(:merge_request_data) { graphql_data['mergeRequest'] }
let(:merge_request_fields) { all_graphql_fields_for('MergeRequest'.classify) }
diff --git a/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
index 30e7f196542..394d9ff53d1 100644
--- a/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'CiCdSettingsUpdate' do
+RSpec.describe 'ProjectCiCdSettingsUpdate' do
include GraphqlHelpers
let_it_be(:project) do
diff --git a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
index 12368e7e9c5..6818ba33e74 100644
--- a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
@@ -64,11 +64,10 @@ RSpec.describe 'RunnersRegistrationTokenReset' do
context 'applied to project' do
let_it_be(:project) { create_default(:project) }
+ let(:target) { project }
let(:input) { { type: 'PROJECT_TYPE', id: project.to_global_id.to_s } }
- include_context 'when unauthorized', 'project' do
- let(:target) { project }
- end
+ include_context('when unauthorized', 'project')
include_context 'when authorized', 'project' do
let_it_be(:user) { project.first_owner }
@@ -82,11 +81,10 @@ RSpec.describe 'RunnersRegistrationTokenReset' do
context 'applied to group' do
let_it_be(:group) { create_default(:group) }
+ let(:target) { group }
let(:input) { { type: 'GROUP_TYPE', id: group.to_global_id.to_s } }
- include_context 'when unauthorized', 'group' do
- let(:target) { group }
- end
+ include_context('when unauthorized', 'group')
include_context 'when authorized', 'group' do
let_it_be(:user) { create_default(:group_member, :owner, user: create(:user), group: group ).user }
@@ -99,10 +97,12 @@ RSpec.describe 'RunnersRegistrationTokenReset' do
context 'applied to instance' do
before do
- ApplicationSetting.create_from_defaults
+ target
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
end
+ let_it_be(:target) { ApplicationSetting.create_from_defaults }
+
let(:input) { { type: 'INSTANCE_TYPE' } }
context 'when unauthorized' do
diff --git a/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb b/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb
index 5f6822223ca..4891e64aab8 100644
--- a/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe 'Delete a cluster agent' do
'or you don\'t have permission to perform this action']
it 'does not delete cluster agent' do
- expect { cluster_agent.reload }.not_to raise_error(ActiveRecord::RecordNotFound)
+ expect { cluster_agent.reload }.not_to raise_error
end
end
diff --git a/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb b/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb
index 0156142dc6f..ca7c1b2ce5f 100644
--- a/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb
@@ -135,7 +135,7 @@ RSpec.describe 'Updating the container expiration policy' do
context 'with existing container expiration policy' do
where(:user_role, :shared_examples_name) do
:maintainer | 'accepting the mutation request updating the container expiration policy'
- :developer | 'accepting the mutation request updating the container expiration policy'
+ :developer | 'denying the mutation request'
:reporter | 'denying the mutation request'
:guest | 'denying the mutation request'
:anonymous | 'denying the mutation request'
@@ -155,7 +155,7 @@ RSpec.describe 'Updating the container expiration policy' do
where(:user_role, :shared_examples_name) do
:maintainer | 'accepting the mutation request creating the container expiration policy'
- :developer | 'accepting the mutation request creating the container expiration policy'
+ :developer | 'denying the mutation request'
:reporter | 'denying the mutation request'
:guest | 'denying the mutation request'
:anonymous | 'denying the mutation request'
diff --git a/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb b/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
index f05bf23ad27..9eb13e534ac 100644
--- a/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe 'Updating the dependency proxy group settings' do
context 'with permission' do
before do
- group.add_developer(user)
+ group.add_maintainer(user)
end
it 'returns the updated dependency proxy settings', :aggregate_failures do
diff --git a/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb b/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
index c9e9a22ee0b..31ba7ecdf0e 100644
--- a/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe 'Updating the dependency proxy image ttl policy' do
context 'with permission' do
before do
- group.add_developer(user)
+ group.add_maintainer(user)
end
it 'returns the updated dependency proxy image ttl policy', :aggregate_failures do
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb
new file mode 100644
index 00000000000..3ea8b38e20f
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Creating an incident timeline event' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:event_occurred_at) { Time.current }
+ let_it_be(:note) { 'demo note' }
+
+ let(:input) { { incident_id: incident.to_global_id.to_s, note: note, occurred_at: event_occurred_at } }
+ let(:mutation) do
+ graphql_mutation(:timeline_event_create, input) do
+ <<~QL
+ clientMutationId
+ errors
+ timelineEvent {
+ id
+ author { id username }
+ incident { id title }
+ note
+ editable
+ action
+ occurredAt
+ }
+ QL
+ end
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:timeline_event_create) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ it 'creates incident timeline event', :aggregate_failures do
+ post_graphql_mutation(mutation, current_user: user)
+
+ timeline_event_response = mutation_response['timelineEvent']
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(timeline_event_response).to include(
+ 'author' => {
+ 'id' => user.to_global_id.to_s,
+ 'username' => user.username
+ },
+ 'incident' => {
+ 'id' => incident.to_global_id.to_s,
+ 'title' => incident.title
+ },
+ 'note' => note,
+ 'action' => 'comment',
+ 'editable' => false,
+ 'occurredAt' => event_occurred_at.iso8601
+ )
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb
new file mode 100644
index 00000000000..faff3bfe23a
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Removing an incident timeline event' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:timeline_event) { create(:incident_management_timeline_event, incident: incident, project: project) }
+
+ let(:variables) { { id: timeline_event.to_global_id.to_s } }
+
+ let(:mutation) do
+ graphql_mutation(:timeline_event_destroy, variables) do
+ <<~QL
+ clientMutationId
+ errors
+ timelineEvent {
+ id
+ author { id username }
+ incident { id title }
+ note
+ noteHtml
+ editable
+ action
+ occurredAt
+ createdAt
+ updatedAt
+ }
+ QL
+ end
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:timeline_event_destroy) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ it 'removes incident timeline event', :aggregate_failures do
+ post_graphql_mutation(mutation, current_user: user)
+
+ timeline_event_response = mutation_response['timelineEvent']
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(timeline_event_response).to include(
+ 'author' => {
+ 'id' => timeline_event.author.to_global_id.to_s,
+ 'username' => timeline_event.author.username
+ },
+ 'incident' => {
+ 'id' => incident.to_global_id.to_s,
+ 'title' => incident.title
+ },
+ 'note' => timeline_event.note,
+ 'noteHtml' => timeline_event.note_html,
+ 'editable' => false,
+ 'action' => timeline_event.action,
+ 'occurredAt' => timeline_event.occurred_at.iso8601,
+ 'createdAt' => timeline_event.created_at.iso8601,
+ 'updatedAt' => timeline_event.updated_at.iso8601
+ )
+ expect { timeline_event.reload }.to raise_error ActiveRecord::RecordNotFound
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
new file mode 100644
index 00000000000..b92f6af1d3d
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Promote an incident timeline event from a comment' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:comment) { create(:note, project: project, noteable: incident) }
+
+ let(:input) { { note_id: comment.to_global_id.to_s } }
+ let(:mutation) do
+ graphql_mutation(:timeline_event_promote_from_note, input) do
+ <<~QL
+ clientMutationId
+ errors
+ timelineEvent {
+ author { id username }
+ incident { id title }
+ promotedFromNote { id }
+ note
+ action
+ editable
+ occurredAt
+ }
+ QL
+ end
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:timeline_event_promote_from_note) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ it 'creates incident timeline event from the note', :aggregate_failures do
+ post_graphql_mutation(mutation, current_user: user)
+
+ timeline_event_response = mutation_response['timelineEvent']
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(timeline_event_response).to include(
+ 'author' => {
+ 'id' => user.to_global_id.to_s,
+ 'username' => user.username
+ },
+ 'incident' => {
+ 'id' => incident.to_global_id.to_s,
+ 'title' => incident.title
+ },
+ 'promotedFromNote' => {
+ 'id' => comment.to_global_id.to_s
+ },
+ 'note' => comment.note,
+ 'action' => 'comment',
+ 'editable' => false,
+ 'occurredAt' => comment.created_at.iso8601
+ )
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb
new file mode 100644
index 00000000000..1c4439cec6f
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Updating an incident timeline event' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be_with_reload(:timeline_event) do
+ create(:incident_management_timeline_event, incident: incident, project: project)
+ end
+
+ let(:occurred_at) { 1.minute.ago.iso8601 }
+
+ let(:variables) do
+ {
+ id: timeline_event.to_global_id.to_s,
+ note: 'Updated note',
+ occurred_at: occurred_at
+ }
+ end
+
+ let(:mutation) do
+ graphql_mutation(:timeline_event_update, variables) do
+ <<~QL
+ clientMutationId
+ errors
+ timelineEvent {
+ id
+ author { id username }
+ updatedByUser { id username }
+ incident { id title }
+ note
+ noteHtml
+ occurredAt
+ createdAt
+ updatedAt
+ }
+ QL
+ end
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:timeline_event_update) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ it 'updates the timeline event', :aggregate_failures do
+ post_graphql_mutation(mutation, current_user: user)
+
+ timeline_event_response = mutation_response['timelineEvent']
+
+ timeline_event.reload
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(timeline_event_response).to include(
+ 'id' => timeline_event.to_global_id.to_s,
+ 'author' => {
+ 'id' => timeline_event.author.to_global_id.to_s,
+ 'username' => timeline_event.author.username
+ },
+ 'updatedByUser' => {
+ 'id' => user.to_global_id.to_s,
+ 'username' => user.username
+ },
+ 'incident' => {
+ 'id' => incident.to_global_id.to_s,
+ 'title' => incident.title
+ },
+ 'note' => 'Updated note',
+ 'noteHtml' => timeline_event.note_html,
+ 'occurredAt' => occurred_at,
+ 'createdAt' => timeline_event.created_at.iso8601,
+ 'updatedAt' => timeline_event.updated_at.iso8601
+ )
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb b/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb
index 02b79dac489..715507c3cc5 100644
--- a/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'Setting issues crm contacts' do
let(:operation_mode) { Types::MutationOperationModeEnum.default_mode }
let(:initial_contacts) { contacts[0..1] }
let(:mutation_contacts) { contacts[1..2] }
- let(:contact_ids) { contact_global_ids(mutation_contacts) }
+ let(:contact_ids) { mutation_contacts.map { global_id_of(_1) } }
let(:does_not_exist_or_no_permission) { "The resource that you are attempting to access does not exist or you don't have permission to perform this action" }
let(:mutation) do
@@ -45,8 +45,8 @@ RSpec.describe 'Setting issues crm contacts' do
graphql_mutation_response(:issue_set_crm_contacts)
end
- def contact_global_ids(contacts)
- contacts.map { |contact| global_id_of(contact) }
+ def expected_contacts(contacts)
+ contacts.map { |contact| a_graphql_entity_for(contact) }
end
before do
@@ -58,8 +58,8 @@ RSpec.describe 'Setting issues crm contacts' do
it 'updates the issue with correct contacts' do
post_graphql_mutation(mutation, current_user: user)
- expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes, :id))
- .to match_array(contact_global_ids(mutation_contacts))
+ expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes))
+ .to match_array(expected_contacts(mutation_contacts))
end
end
@@ -70,8 +70,8 @@ RSpec.describe 'Setting issues crm contacts' do
it 'updates the issue with correct contacts' do
post_graphql_mutation(mutation, current_user: user)
- expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes, :id))
- .to match_array(contact_global_ids(initial_contacts + mutation_contacts))
+ expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes))
+ .to match_array(expected_contacts(initial_contacts + mutation_contacts))
end
end
@@ -82,8 +82,8 @@ RSpec.describe 'Setting issues crm contacts' do
it 'updates the issue with correct contacts' do
post_graphql_mutation(mutation, current_user: user)
- expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes, :id))
- .to match_array(contact_global_ids(initial_contacts - mutation_contacts))
+ expect(graphql_data_at(:issue_set_crm_contacts, :issue, :customer_relations_contacts, :nodes))
+ .to match_array(expected_contacts(initial_contacts - mutation_contacts))
end
end
end
@@ -117,7 +117,7 @@ RSpec.describe 'Setting issues crm contacts' do
it_behaves_like 'successful mutation'
context 'when the contact does not exist' do
- let(:contact_ids) { ["gid://gitlab/CustomerRelations::Contact/#{non_existing_record_id}"] }
+ let(:contact_ids) { [global_id_of(model_name: 'CustomerRelations::Contact', id: non_existing_record_id)] }
it 'returns expected error' do
post_graphql_mutation(mutation, current_user: user)
@@ -159,7 +159,7 @@ RSpec.describe 'Setting issues crm contacts' do
context 'when trying to remove non-existent contact' do
let(:operation_mode) { Types::MutationOperationModeEnum.enum[:remove] }
- let(:contact_ids) { ["gid://gitlab/CustomerRelations::Contact/#{non_existing_record_id}"] }
+ let(:contact_ids) { [global_id_of(model_name: 'CustomerRelations::Contact', id: non_existing_record_id)] }
it 'raises expected error' do
post_graphql_mutation(mutation, current_user: user)
diff --git a/spec/requests/api/graphql/mutations/merge_requests/request_attention_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/request_attention_spec.rb
new file mode 100644
index 00000000000..9c751913827
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/merge_requests/request_attention_spec.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Request attention' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:merge_request) { create(:merge_request, reviewers: [user]) }
+ let_it_be(:project) { merge_request.project }
+
+ let(:input) { { user_id: global_id_of(user) } }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ iid: merge_request.iid.to_s
+ }
+ graphql_mutation(:merge_request_request_attention, variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:merge_request_request_attention)
+ end
+
+ def mutation_errors
+ mutation_response['errors']
+ end
+
+ before_all do
+ project.add_developer(current_user)
+ project.add_developer(user)
+ end
+
+ it 'is successful' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_errors).to be_empty
+ end
+
+ context 'when current user is not allowed to update the merge request' do
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).not_to be_empty
+ end
+ end
+
+ context 'when user is not a reviewer' do
+ let(:input) { { user_id: global_id_of(create(:user)) } }
+
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_errors).not_to be_empty
+ end
+ end
+
+ context 'feature flag is disabled' do
+ before do
+ stub_feature_flags(mr_attention_requests: false)
+ end
+
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(graphql_errors[0]["message"]).to eq "Feature disabled"
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
index d335642d321..194e42bf59d 100644
--- a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
@@ -109,7 +109,7 @@ RSpec.describe 'Updating the package settings' do
where(:user_role, :shared_examples_name) do
:maintainer | 'accepting the mutation request updating the package settings'
- :developer | 'accepting the mutation request updating the package settings'
+ :developer | 'denying the mutation request'
:reporter | 'denying the mutation request'
:guest | 'denying the mutation request'
:anonymous | 'denying the mutation request'
@@ -131,7 +131,7 @@ RSpec.describe 'Updating the package settings' do
where(:user_role, :shared_examples_name) do
:maintainer | 'accepting the mutation request creating the package settings'
- :developer | 'accepting the mutation request creating the package settings'
+ :developer | 'denying the mutation request'
:reporter | 'denying the mutation request'
:guest | 'denying the mutation request'
:anonymous | 'denying the mutation request'
diff --git a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
index 63b94dccca0..22b5f2d5112 100644
--- a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
@@ -64,7 +64,7 @@ RSpec.describe 'Adding a Note' do
it 'creates a Note in a discussion' do
post_graphql_mutation(mutation, current_user: current_user)
- expect(mutation_response['note']['discussion']['id']).to eq(discussion.to_global_id.to_s)
+ expect(mutation_response['note']['discussion']).to match a_graphql_entity_for(discussion)
end
context 'when the discussion_id is not for a Discussion' do
@@ -109,7 +109,7 @@ RSpec.describe 'Adding a Note' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response).to include(
- 'errors' => [/Merged this merge request/],
+ 'errors' => include(/Merged this merge request/),
'note' => nil
)
end
diff --git a/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb
index 89e3a71280f..0f7ccac3179 100644
--- a/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe 'Repositioning an ImageDiffNote' do
post_graphql_mutation(mutation, current_user: current_user)
end.to change { note.reset.position.x }.to(10)
- expect(mutation_response['note']).to eq('id' => global_id_of(note))
+ expect(mutation_response['note']).to match a_graphql_entity_for(note)
expect(mutation_response['errors']).to be_empty
end
@@ -59,7 +59,7 @@ RSpec.describe 'Repositioning an ImageDiffNote' do
post_graphql_mutation(mutation, current_user: current_user)
end.not_to change { note.reset.position.x }
- expect(mutation_response['note']).to eq('id' => global_id_of(note))
+ expect(mutation_response['note']).to match a_graphql_entity_for(note)
expect(mutation_response['errors']).to be_empty
end
end
diff --git a/spec/requests/api/graphql/mutations/remove_attention_request_spec.rb b/spec/requests/api/graphql/mutations/remove_attention_request_spec.rb
new file mode 100644
index 00000000000..053559b039d
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/remove_attention_request_spec.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Remove attention request' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:merge_request) { create(:merge_request, reviewers: [user]) }
+ let_it_be(:project) { merge_request.project }
+
+ let(:input) { { user_id: global_id_of(user) } }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ iid: merge_request.iid.to_s
+ }
+ graphql_mutation(:merge_request_remove_attention_request, variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:merge_request_remove_attention_request)
+ end
+
+ def mutation_errors
+ mutation_response['errors']
+ end
+
+ before_all do
+ project.add_developer(current_user)
+ project.add_developer(user)
+ end
+
+ it 'is successful' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_errors).to be_empty
+ end
+
+ context 'when current user is not allowed to update the merge request' do
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).not_to be_empty
+ end
+ end
+
+ context 'when user is not a reviewer' do
+ let(:input) { { user_id: global_id_of(create(:user)) } }
+
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_errors).not_to be_empty
+ end
+ end
+
+ context 'feature flag is disabled' do
+ before do
+ stub_feature_flags(mr_attention_requests: false)
+ end
+
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(graphql_errors[0]["message"]).to eq "Feature disabled"
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb b/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb
new file mode 100644
index 00000000000..b674e77f093
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Delete a timelog' do
+ include GraphqlHelpers
+ let_it_be(:author) { create(:user) }
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800)}
+
+ let(:current_user) { nil }
+ let(:mutation) { graphql_mutation(:timelogDelete, { 'id' => timelog.to_global_id.to_s }) }
+ let(:mutation_response) { graphql_mutation_response(:timelog_delete) }
+
+ context 'when the user is not allowed to delete a timelog' do
+ let(:current_user) { create(:user) }
+
+ before do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user has permissions to delete a timelog' do
+ let(:current_user) { author }
+
+ it 'deletes the timelog' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change(Timelog, :count).by(-1)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['timelog']).to include('id' => timelog.to_global_id.to_s)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
index c5c34e16717..dc20fde8e3c 100644
--- a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
@@ -46,8 +46,8 @@ RSpec.describe 'Marking all todos done' do
expect(todo3.reload.state).to eq('done')
expect(other_user_todo.reload.state).to eq('pending')
- updated_todo_ids = mutation_response['todos'].map { |todo| todo['id'] }
- expect(updated_todo_ids).to contain_exactly(global_id_of(todo1), global_id_of(todo3))
+ updated_todos = mutation_response['todos']
+ expect(updated_todos).to contain_exactly(a_graphql_entity_for(todo1), a_graphql_entity_for(todo3))
end
context 'when target_id is given', :aggregate_failures do
@@ -66,8 +66,8 @@ RSpec.describe 'Marking all todos done' do
expect(todo1.reload.state).to eq('pending')
expect(todo3.reload.state).to eq('pending')
- updated_todo_ids = mutation_response['todos'].map { |todo| todo['id'] }
- expect(updated_todo_ids).to contain_exactly(global_id_of(target_todo1), global_id_of(target_todo2))
+ updated_todos = mutation_response['todos']
+ expect(updated_todos).to contain_exactly(a_graphql_entity_for(target_todo1), a_graphql_entity_for(target_todo2))
end
context 'when target does not exist' do
diff --git a/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
index 70e3cc7f5cd..4316bd060c1 100644
--- a/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
@@ -11,8 +11,8 @@ RSpec.describe 'Restoring many Todos' do
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
- let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
- let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
+ let_it_be_with_reload(:todo1) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
+ let_it_be_with_reload(:todo2) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
let_it_be(:other_user_todo) { create(:todo, user: other_user, author: author, state: :done) }
@@ -50,8 +50,8 @@ RSpec.describe 'Restoring many Todos' do
expect(mutation_response).to include(
'errors' => be_empty,
'todos' => contain_exactly(
- { 'id' => global_id_of(todo1), 'state' => 'pending' },
- { 'id' => global_id_of(todo2), 'state' => 'pending' }
+ a_graphql_entity_for(todo1, 'state' => 'pending'),
+ a_graphql_entity_for(todo2, 'state' => 'pending')
)
)
end
diff --git a/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb b/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb
new file mode 100644
index 00000000000..05d3587d342
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe "Delete a task in a work item's description" do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } }
+ let_it_be(:task) { create(:work_item, :task, project: project, author: developer) }
+ let_it_be(:work_item, refind: true) do
+ create(:work_item, project: project, description: "- [ ] #{task.to_reference}+", lock_version: 3)
+ end
+
+ before_all do
+ create(:issue_link, source_id: work_item.id, target_id: task.id)
+ end
+
+ let(:lock_version) { work_item.lock_version }
+ let(:input) do
+ {
+ 'id' => work_item.to_global_id.to_s,
+ 'lockVersion' => lock_version,
+ 'taskData' => {
+ 'id' => task.to_global_id.to_s,
+ 'lineNumberStart' => 1,
+ 'lineNumberEnd' => 1
+ }
+ }
+ end
+
+ let(:mutation) { graphql_mutation(:workItemDeleteTask, input) }
+ let(:mutation_response) { graphql_mutation_response(:work_item_delete_task) }
+
+ context 'the user is not allowed to update a work item' do
+ let(:current_user) { create(:user) }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user can update the description but not delete the task' do
+ let(:current_user) { create(:user).tap { |u| project.add_developer(u) } }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user has permissions to remove a task' do
+ let(:current_user) { developer }
+
+ it 'removes the task from the work item' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ work_item.reload
+ end.to change(WorkItem, :count).by(-1).and(
+ change(IssueLink, :count).by(-1)
+ ).and(
+ change(work_item, :description).from("- [ ] #{task.to_reference}+").to('')
+ )
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['workItem']).to include('id' => work_item.to_global_id.to_s)
+ end
+
+ context 'when removing the task fails' do
+ let(:lock_version) { 2 }
+
+ it 'makes no changes to the DB and returns an error message' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ work_item.reload
+ end.to not_change(WorkItem, :count).and(
+ not_change(work_item, :description)
+ )
+
+ expect(mutation_response['errors']).to contain_exactly('Stale work item. Check lock version')
+ end
+ end
+
+ context 'when the work_items feature flag is disabled' do
+ before do
+ stub_feature_flags(work_items: false)
+ end
+
+ it 'does nothing and returns and error' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to not_change(WorkItem, :count)
+
+ expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/packages/conan_spec.rb b/spec/requests/api/graphql/packages/conan_spec.rb
index 84c5af33e5d..1f3732980d9 100644
--- a/spec/requests/api/graphql/packages/conan_spec.rb
+++ b/spec/requests/api/graphql/packages/conan_spec.rb
@@ -37,22 +37,19 @@ RSpec.describe 'conan package details' do
it_behaves_like 'a package with files'
it 'has the correct metadata' do
- expect(metadata_response).to include(
- 'id' => global_id_of(package.conan_metadatum),
- 'recipe' => package.conan_metadatum.recipe,
- 'packageChannel' => package.conan_metadatum.package_channel,
- 'packageUsername' => package.conan_metadatum.package_username,
- 'recipePath' => package.conan_metadatum.recipe_path
+ expect(metadata_response).to match(
+ a_graphql_entity_for(package.conan_metadatum,
+ :recipe, :package_channel, :package_username, :recipe_path)
)
end
it 'has the correct file metadata' do
- expect(first_file_response_metadata).to include(
- 'id' => global_id_of(first_file.conan_file_metadatum),
- 'packageRevision' => first_file.conan_file_metadatum.package_revision,
- 'conanPackageReference' => first_file.conan_file_metadatum.conan_package_reference,
- 'recipeRevision' => first_file.conan_file_metadatum.recipe_revision,
- 'conanFileType' => first_file.conan_file_metadatum.conan_file_type.upcase
+ expect(first_file_response_metadata).to match(
+ a_graphql_entity_for(
+ first_file.conan_file_metadatum,
+ :package_revision, :conan_package_reference, :recipe_revision,
+ conan_file_type: first_file.conan_file_metadatum.conan_file_type.upcase
+ )
)
end
end
diff --git a/spec/requests/api/graphql/packages/maven_spec.rb b/spec/requests/api/graphql/packages/maven_spec.rb
index d28d32b0df5..9d59a922660 100644
--- a/spec/requests/api/graphql/packages/maven_spec.rb
+++ b/spec/requests/api/graphql/packages/maven_spec.rb
@@ -11,12 +11,8 @@ RSpec.describe 'maven package details' do
shared_examples 'correct maven metadata' do
it 'has the correct metadata' do
- expect(metadata_response).to include(
- 'id' => global_id_of(package.maven_metadatum),
- 'path' => package.maven_metadatum.path,
- 'appGroup' => package.maven_metadatum.app_group,
- 'appVersion' => package.maven_metadatum.app_version,
- 'appName' => package.maven_metadatum.app_name
+ expect(metadata_response).to match a_graphql_entity_for(
+ package.maven_metadatum, :path, :app_group, :app_version, :app_name
)
end
end
diff --git a/spec/requests/api/graphql/packages/nuget_spec.rb b/spec/requests/api/graphql/packages/nuget_spec.rb
index ba8d2ca42d2..87cffc67ce5 100644
--- a/spec/requests/api/graphql/packages/nuget_spec.rb
+++ b/spec/requests/api/graphql/packages/nuget_spec.rb
@@ -22,24 +22,19 @@ RSpec.describe 'nuget package details' do
it_behaves_like 'a package with files'
it 'has the correct metadata' do
- expect(metadata_response).to include(
- 'id' => global_id_of(package.nuget_metadatum),
- 'licenseUrl' => package.nuget_metadatum.license_url,
- 'projectUrl' => package.nuget_metadatum.project_url,
- 'iconUrl' => package.nuget_metadatum.icon_url
+ expect(metadata_response).to match a_graphql_entity_for(
+ package.nuget_metadatum, :license_url, :project_url, :icon_url
)
end
it 'has dependency links' do
- expect(dependency_link_response).to include(
- 'id' => global_id_of(dependency_link),
+ expect(dependency_link_response).to match a_graphql_entity_for(
+ dependency_link,
'dependencyType' => dependency_link.dependency_type.upcase
)
- expect(dependency_response).to include(
- 'id' => global_id_of(dependency_link.dependency),
- 'name' => dependency_link.dependency.name,
- 'versionPattern' => dependency_link.dependency.version_pattern
+ expect(dependency_response).to match a_graphql_entity_for(
+ dependency_link.dependency, :name, :version_pattern
)
end
diff --git a/spec/requests/api/graphql/packages/package_spec.rb b/spec/requests/api/graphql/packages/package_spec.rb
index 365efc514d4..0335c1085b4 100644
--- a/spec/requests/api/graphql/packages/package_spec.rb
+++ b/spec/requests/api/graphql/packages/package_spec.rb
@@ -65,32 +65,6 @@ RSpec.describe 'package details' do
end
end
- context 'there are other versions of this package' do
- let(:depth) { 3 }
- let(:excluded) { %w[metadata project tags pipelines] } # to limit the query complexity
-
- let_it_be(:siblings) { create_list(:composer_package, 2, project: project, name: composer_package.name) }
-
- it 'includes the sibling versions' do
- subject
-
- expect(graphql_data_at(:package, :versions, :nodes)).to match_array(
- siblings.map { |p| a_hash_including('id' => global_id_of(p)) }
- )
- end
-
- context 'going deeper' do
- let(:depth) { 6 }
-
- it 'does not create a cycle of versions' do
- subject
-
- expect(graphql_data_at(:package, :versions, :nodes, :version)).to be_present
- expect(graphql_data_at(:package, :versions, :nodes, :versions, :nodes)).to match_array [nil, nil]
- end
- end
- end
-
context 'with package files pending destruction' do
let_it_be(:package_file) { create(:package_file, package: composer_package) }
let_it_be(:package_file_pending_destruction) { create(:package_file, :pending_destruction, package: composer_package) }
diff --git a/spec/requests/api/graphql/packages/pypi_spec.rb b/spec/requests/api/graphql/packages/pypi_spec.rb
index 64fe7d29a7a..0cc5bd2e3b2 100644
--- a/spec/requests/api/graphql/packages/pypi_spec.rb
+++ b/spec/requests/api/graphql/packages/pypi_spec.rb
@@ -19,9 +19,8 @@ RSpec.describe 'pypi package details' do
it_behaves_like 'a package with files'
it 'has the correct metadata' do
- expect(metadata_response).to include(
- 'id' => global_id_of(package.pypi_metadatum),
- 'requiredPython' => package.pypi_metadatum.required_python
+ expect(metadata_response).to match a_graphql_entity_for(
+ package.pypi_metadatum, :required_python
)
end
end
diff --git a/spec/requests/api/graphql/project/alert_management/integrations_spec.rb b/spec/requests/api/graphql/project/alert_management/integrations_spec.rb
index 1793d4961eb..773922c1864 100644
--- a/spec/requests/api/graphql/project/alert_management/integrations_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/integrations_spec.rb
@@ -53,33 +53,24 @@ RSpec.describe 'getting Alert Management Integrations' do
end
context 'when no extra params given' do
- let(:http_integration_response) { integrations.first }
- let(:prometheus_integration_response) { integrations.second }
-
it_behaves_like 'a working graphql query'
- it { expect(integrations.size).to eq(2) }
-
it 'returns the correct properties of the integrations' do
- expect(http_integration_response).to include(
- 'id' => global_id_of(active_http_integration),
- 'type' => 'HTTP',
- 'name' => active_http_integration.name,
- 'active' => active_http_integration.active,
- 'token' => active_http_integration.token,
- 'url' => active_http_integration.url,
- 'apiUrl' => nil
- )
-
- expect(prometheus_integration_response).to include(
- 'id' => global_id_of(prometheus_integration),
- 'type' => 'PROMETHEUS',
- 'name' => 'Prometheus',
- 'active' => prometheus_integration.manual_configuration?,
- 'token' => project_alerting_setting.token,
- 'url' => "http://localhost/#{project.full_path}/prometheus/alerts/notify.json",
- 'apiUrl' => prometheus_integration.api_url
- )
+ expect(integrations).to match [
+ a_graphql_entity_for(
+ active_http_integration,
+ :name, :active, :token, :url, type: 'HTTP', api_url: nil
+ ),
+ a_graphql_entity_for(
+ prometheus_integration,
+ 'type' => 'PROMETHEUS',
+ 'name' => 'Prometheus',
+ 'active' => prometheus_integration.manual_configuration?,
+ 'token' => project_alerting_setting.token,
+ 'url' => "http://localhost/#{project.full_path}/prometheus/alerts/notify.json",
+ 'apiUrl' => prometheus_integration.api_url
+ )
+ ]
end
end
@@ -88,17 +79,9 @@ RSpec.describe 'getting Alert Management Integrations' do
it_behaves_like 'a working graphql query'
- it { expect(integrations).to be_one }
-
it 'returns the correct properties of the HTTP integration' do
- expect(integrations.first).to include(
- 'id' => global_id_of(active_http_integration),
- 'type' => 'HTTP',
- 'name' => active_http_integration.name,
- 'active' => active_http_integration.active,
- 'token' => active_http_integration.token,
- 'url' => active_http_integration.url,
- 'apiUrl' => nil
+ expect(integrations).to contain_exactly a_graphql_entity_for(
+ active_http_integration, :name, :active, :token, :url, type: 'HTTP', api_url: nil
)
end
end
@@ -108,11 +91,9 @@ RSpec.describe 'getting Alert Management Integrations' do
it_behaves_like 'a working graphql query'
- it { expect(integrations).to be_one }
-
it 'returns the correct properties of the Prometheus Integration' do
- expect(integrations.first).to include(
- 'id' => global_id_of(prometheus_integration),
+ expect(integrations).to contain_exactly a_graphql_entity_for(
+ prometheus_integration,
'type' => 'PROMETHEUS',
'name' => 'Prometheus',
'active' => prometheus_integration.manual_configuration?,
diff --git a/spec/requests/api/graphql/project/cluster_agents_spec.rb b/spec/requests/api/graphql/project/cluster_agents_spec.rb
index c9900fea277..a34df0ee6f4 100644
--- a/spec/requests/api/graphql/project/cluster_agents_spec.rb
+++ b/spec/requests/api/graphql/project/cluster_agents_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe 'Project.cluster_agents' do
post_graphql(query, current_user: current_user)
expect(graphql_data_at(:project, :cluster_agents, :nodes)).to match_array(
- agents.map { |agent| a_hash_including('id' => global_id_of(agent)) }
+ agents.map { |agent| a_graphql_entity_for(agent) }
)
end
@@ -62,9 +62,9 @@ RSpec.describe 'Project.cluster_agents' do
tokens = graphql_data_at(:project, :cluster_agents, :nodes, :tokens, :nodes)
expect(tokens).to match([
- a_hash_including('id' => global_id_of(token_3)),
- a_hash_including('id' => global_id_of(token_2)),
- a_hash_including('id' => global_id_of(token_1))
+ a_graphql_entity_for(token_3),
+ a_graphql_entity_for(token_2),
+ a_graphql_entity_for(token_1)
])
end
diff --git a/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb b/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb
new file mode 100644
index 00000000000..708fa96986c
--- /dev/null
+++ b/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb
@@ -0,0 +1,127 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting incident timeline events' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:updated_by_user) { create(:user) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:another_incident) { create(:incident, project: project) }
+ let_it_be(:promoted_from_note) { create(:note, project: project, noteable: incident) }
+
+ let_it_be(:timeline_event) do
+ create(
+ :incident_management_timeline_event,
+ incident: incident,
+ project: project,
+ updated_by_user: updated_by_user,
+ promoted_from_note: promoted_from_note
+ )
+ end
+
+ let_it_be(:second_timeline_event) do
+ create(:incident_management_timeline_event, incident: incident, project: project)
+ end
+
+ let_it_be(:another_timeline_event) do
+ create(:incident_management_timeline_event, incident: another_incident, project: project)
+ end
+
+ let(:params) { { incident_id: incident.to_global_id.to_s } }
+
+ let(:timeline_event_fields) do
+ <<~QUERY
+ nodes {
+ id
+ author { id username }
+ updatedByUser { id username }
+ incident { id title }
+ note
+ noteHtml
+ promotedFromNote { id body }
+ editable
+ action
+ occurredAt
+ createdAt
+ updatedAt
+ }
+ QUERY
+ end
+
+ let(:query) do
+ graphql_query_for(
+ 'project',
+ { 'fullPath' => project.full_path },
+ query_graphql_field('incidentManagementTimelineEvents', params, timeline_event_fields)
+ )
+ end
+
+ let(:timeline_events) do
+ graphql_data.dig('project', 'incidentManagementTimelineEvents', 'nodes')
+ end
+
+ before do
+ project.add_guest(current_user)
+ post_graphql(query, current_user: current_user)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns the correct number of timeline events' do
+ expect(timeline_events.count).to eq(2)
+ end
+
+ it 'returns the correct properties of the incident timeline events' do
+ expect(timeline_events.first).to include(
+ 'author' => {
+ 'id' => timeline_event.author.to_global_id.to_s,
+ 'username' => timeline_event.author.username
+ },
+ 'updatedByUser' => {
+ 'id' => updated_by_user.to_global_id.to_s,
+ 'username' => updated_by_user.username
+ },
+ 'incident' => {
+ 'id' => incident.to_global_id.to_s,
+ 'title' => incident.title
+ },
+ 'note' => timeline_event.note,
+ 'noteHtml' => timeline_event.note_html,
+ 'promotedFromNote' => {
+ 'id' => promoted_from_note.to_global_id.to_s,
+ 'body' => promoted_from_note.note
+ },
+ 'editable' => false,
+ 'action' => timeline_event.action,
+ 'occurredAt' => timeline_event.occurred_at.iso8601,
+ 'createdAt' => timeline_event.created_at.iso8601,
+ 'updatedAt' => timeline_event.updated_at.iso8601
+ )
+ end
+
+ context 'when filtering by id' do
+ let(:params) { { incident_id: incident.to_global_id.to_s, id: timeline_event.to_global_id.to_s } }
+
+ let(:query) do
+ graphql_query_for(
+ 'project',
+ { 'fullPath' => project.full_path },
+ query_graphql_field('incidentManagementTimelineEvent', params, 'id occurredAt')
+ )
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns a single timeline event', :aggregate_failures do
+ single_timeline_event = graphql_data.dig('project', 'incidentManagementTimelineEvent')
+
+ expect(single_timeline_event).to include(
+ 'id' => timeline_event.to_global_id.to_s,
+ 'occurredAt' => timeline_event.occurred_at.iso8601
+ )
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb b/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb
index f544d78ecbb..8cda61f0628 100644
--- a/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb
+++ b/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb
@@ -71,11 +71,7 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)
it 'finds all the designs as of the given version' do
post_query
- expect(data).to match(
- a_hash_including(
- 'id' => global_id_of(design_at_version),
- 'filename' => design.filename
- ))
+ expect(data).to match a_graphql_entity_for(design_at_version, filename: design.filename)
end
context 'when the current_user is not authorized' do
@@ -119,7 +115,8 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)
let(:results) do
issue.designs.visible_at_version(version).map do |d|
dav = build(:design_at_version, design: d, version: version)
- { 'id' => global_id_of(dav), 'filename' => d.filename }
+
+ a_graphql_entity_for(dav, filename: d.filename)
end
end
@@ -132,8 +129,8 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)
describe 'filtering' do
let(:designs) { issue.designs.sample(3) }
let(:filenames) { designs.map(&:filename) }
- let(:ids) do
- designs.map { |d| global_id_of(build(:design_at_version, design: d, version: version)) }
+ let(:expected_designs) do
+ designs.map { |d| a_graphql_entity_for(build(:design_at_version, design: d, version: version)) }
end
before do
@@ -144,7 +141,7 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)
let(:dav_params) { { filenames: filenames } }
it 'finds the designs by filename' do
- expect(data.map { |e| e.dig('node', 'id') }).to match_array(ids)
+ expect(data.map { |e| e['node'] }).to match_array expected_designs
end
end
@@ -160,9 +157,9 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)
describe 'pagination' do
let(:end_cursor) { graphql_data_at(*path_prefix, :designs_at_version, :page_info, :end_cursor) }
- let(:ids) do
+ let(:entities) do
::DesignManagement::Design.visible_at_version(version).order(:id).map do |d|
- global_id_of(build(:design_at_version, design: d, version: version))
+ a_graphql_entity_for(build(:design_at_version, design: d, version: version))
end
end
@@ -178,19 +175,19 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)
let(:fields) { ['pageInfo { endCursor }', 'edges { node { id } }'] }
def response_values(data = graphql_data)
- data.dig(*path).map { |e| e.dig('node', 'id') }
+ data.dig(*path).map { |e| e['node'] }
end
it 'sorts designs for reliable pagination' do
post_graphql(query, current_user: current_user)
- expect(response_values).to match_array(ids.take(2))
+ expect(response_values).to match_array(entities.take(2))
post_graphql(cursored_query, current_user: current_user)
new_data = Gitlab::Json.parse(response.body).fetch('data')
- expect(response_values(new_data)).to match_array(ids.drop(2))
+ expect(response_values(new_data)).to match_array(entities.drop(2))
end
end
end
@@ -202,9 +199,7 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)
end
let(:results) do
- version.designs.map do |design|
- { 'id' => global_id_of(design), 'filename' => design.filename }
- end
+ version.designs.map { |design| a_graphql_entity_for(design, :filename) }
end
it 'finds all the designs as of the given version' do
diff --git a/spec/requests/api/graphql/project/issue/designs/designs_spec.rb b/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
index f0205319983..02bc9457c07 100644
--- a/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
+++ b/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
@@ -58,8 +58,8 @@ RSpec.describe 'Getting designs related to an issue' do
post_graphql(query, current_user: current_user)
- expect(design_response).to eq(
- 'id' => design.to_global_id.to_s,
+ expect(design_response).to match a_graphql_entity_for(
+ design,
'event' => 'CREATION',
'fullPath' => design.full_path,
'filename' => design.filename,
@@ -93,7 +93,7 @@ RSpec.describe 'Getting designs related to an issue' do
let(:end_cursor) { design_collection.dig('designs', 'pageInfo', 'endCursor') }
- let(:ids) { issue.designs.order(:id).map { |d| global_id_of(d) } }
+ let(:expected_designs) { issue.designs.order(:id).map { |d| a_graphql_entity_for(d) } }
let(:query) { make_query(designs_fragment(first: 2)) }
@@ -107,19 +107,19 @@ RSpec.describe 'Getting designs related to an issue' do
query_graphql_field(:designs, params, design_query_fields)
end
- def response_ids(data = graphql_data)
+ def response_designs(data = graphql_data)
path = %w[project issue designCollection designs edges]
- data.dig(*path).map { |e| e.dig('node', 'id') }
+ data.dig(*path).map { |e| e['node'] }
end
it 'sorts designs for reliable pagination' do
- expect(response_ids).to match_array(ids.take(2))
+ expect(response_designs).to match_array(expected_designs.take(2))
post_graphql(cursored_query, current_user: current_user)
new_data = Gitlab::Json.parse(response.body).fetch('data')
- expect(response_ids(new_data)).to match_array(ids.drop(2))
+ expect(response_designs(new_data)).to match_array(expected_designs.drop(2))
end
end
@@ -273,8 +273,10 @@ RSpec.describe 'Getting designs related to an issue' do
end
it 'returns the correct v432x230-sized design images' do
+ v0 = design.actions.most_recent.first.version
+
expect(design_nodes).to contain_exactly(
- a_hash_including('imageV432x230' => design_image_url(design, ref: version.sha, size: :v432x230)),
+ a_hash_including('imageV432x230' => design_image_url(design, ref: v0.sha, size: :v432x230)),
a_hash_including('imageV432x230' => design_image_url(second_design, ref: version.sha, size: :v432x230))
)
end
@@ -323,8 +325,10 @@ RSpec.describe 'Getting designs related to an issue' do
end
it 'returns the correct v432x230-sized design images' do
+ v0 = design.actions.most_recent.first.version
+
expect(design_nodes).to contain_exactly(
- a_hash_including('imageV432x230' => design_image_url(design, ref: version.sha, size: :v432x230)),
+ a_hash_including('imageV432x230' => design_image_url(design, ref: v0.sha, size: :v432x230)),
a_hash_including('imageV432x230' => design_image_url(second_design, ref: version.sha, size: :v432x230))
)
end
diff --git a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
index de2ace95757..3b1eb0b4b02 100644
--- a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
+++ b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe 'Getting designs related to an issue' do
design_data = designs_data['nodes'].first
note_data = design_data['notes']['nodes'].first
- expect(note_data['id']).to eq(note.to_global_id.to_s)
+ expect(note_data).to match(a_graphql_entity_for(note))
end
def query(note_fields = all_graphql_fields_for(Note, max_depth: 1))
diff --git a/spec/requests/api/graphql/project/issue_spec.rb b/spec/requests/api/graphql/project/issue_spec.rb
index ddf63a8f2c9..2415e9ef60f 100644
--- a/spec/requests/api/graphql/project/issue_spec.rb
+++ b/spec/requests/api/graphql/project/issue_spec.rb
@@ -144,10 +144,7 @@ RSpec.describe 'Query.project(fullPath).issue(iid)' do
data = graphql_data.dig(*path)
- expect(data).to match(
- a_hash_including('id' => global_id_of(version),
- 'sha' => version.sha)
- )
+ expect(data).to match a_graphql_entity_for(version, :sha)
end
end
@@ -184,6 +181,6 @@ RSpec.describe 'Query.project(fullPath).issue(iid)' do
end
def id_hash(object)
- a_hash_including('id' => global_id_of(object))
+ a_graphql_entity_for(object)
end
end
diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb
index cefe88aafc8..d2f34080be3 100644
--- a/spec/requests/api/graphql/project/merge_request_spec.rb
+++ b/spec/requests/api/graphql/project/merge_request_spec.rb
@@ -66,7 +66,7 @@ RSpec.describe 'getting merge request information nested in a project' do
it 'includes reviewers' do
expected = merge_request.reviewers.map do |r|
- a_hash_including('id' => global_id_of(r), 'username' => r.username)
+ a_graphql_entity_for(r, :username)
end
post_graphql(query, current_user: current_user)
@@ -425,7 +425,7 @@ RSpec.describe 'getting merge request information nested in a project' do
other_users.each do |user|
assign_user(user)
- merge_request.merge_request_reviewers.find_or_create_by!(reviewer: user)
+ merge_request.merge_request_reviewers.find_or_create_by!(reviewer: user, state: :attention_requested)
end
expect { post_graphql(query) }.not_to exceed_query_limit(baseline)
@@ -466,7 +466,7 @@ RSpec.describe 'getting merge request information nested in a project' do
let(:can_update) { false }
def assign_user(user)
- merge_request.merge_request_reviewers.create!(reviewer: user)
+ merge_request.merge_request_reviewers.create!(reviewer: user, state: :attention_requested)
end
end
diff --git a/spec/requests/api/graphql/project/merge_requests_spec.rb b/spec/requests/api/graphql/project/merge_requests_spec.rb
index 303748bc70e..5daec5543c0 100644
--- a/spec/requests/api/graphql/project/merge_requests_spec.rb
+++ b/spec/requests/api/graphql/project/merge_requests_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe 'getting merge request listings nested in a project' do
let_it_be(:current_user) { create(:user) }
let_it_be(:label) { create(:label, project: project) }
- let_it_be(:merge_request_a) do
+ let_it_be_with_reload(:merge_request_a) do
create(:labeled_merge_request, :unique_branches, source_project: project, labels: [label])
end
@@ -96,7 +96,7 @@ RSpec.describe 'getting merge request listings nested in a project' do
where(:field, :subfield, :is_connection) do
nested_fields_of('MergeRequest').flat_map do |name, field|
type = field_type(field)
- is_connection = type.name.ends_with?('Connection')
+ is_connection = type.graphql_name.ends_with?('Connection')
type = field_type(type.fields['nodes']) if is_connection
type.fields
@@ -412,6 +412,10 @@ RSpec.describe 'getting merge request listings nested in a project' do
describe 'sorting and pagination' do
let(:data_path) { [:project, :mergeRequests] }
+ def pagination_results_data(nodes)
+ nodes
+ end
+
def pagination_query(params)
graphql_query_for(:project, { full_path: project.full_path }, <<~QUERY)
mergeRequests(#{params}) {
@@ -429,7 +433,7 @@ RSpec.describe 'getting merge request listings nested in a project' do
merge_request_c,
merge_request_e,
merge_request_a
- ].map { |mr| global_id_of(mr) }
+ ].map { |mr| a_graphql_entity_for(mr) }
end
before do
@@ -455,7 +459,7 @@ RSpec.describe 'getting merge request listings nested in a project' do
query = pagination_query(params)
post_graphql(query, current_user: current_user)
- expect(results.map { |item| item["id"] }).to eq(all_records.last(2))
+ expect(results).to match(all_records.last(2))
end
end
end
@@ -469,7 +473,7 @@ RSpec.describe 'getting merge request listings nested in a project' do
merge_request_c,
merge_request_e,
merge_request_a
- ].map { |mr| global_id_of(mr) }
+ ].map { |mr| a_graphql_entity_for(mr) }
end
before do
@@ -495,17 +499,19 @@ RSpec.describe 'getting merge request listings nested in a project' do
query = pagination_query(params)
post_graphql(query, current_user: current_user)
- expect(results.map { |item| item["id"] }).to eq(all_records.last(2))
+ expect(results).to match(all_records.last(2))
end
end
end
end
context 'when only the count is requested' do
+ let_it_be(:merged_at) { Time.new(2020, 1, 3) }
+
context 'when merged at filter is present' do
let_it_be(:merge_request) do
create(:merge_request, :unique_branches, source_project: project).tap do |mr|
- mr.metrics.update!(merged_at: Time.new(2020, 1, 3))
+ mr.metrics.update!(merged_at: merged_at, created_at: merged_at - 2.days)
end
end
@@ -522,12 +528,18 @@ RSpec.describe 'getting merge request listings nested in a project' do
it 'does not query the merge requests table for the count' do
query_recorder = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
- queries = query_recorder.data.each_value.first[:occurrences]
+ queries = query_recorder.log
expect(queries).not_to include(match(/SELECT COUNT\(\*\) FROM "merge_requests"/))
expect(queries).to include(match(/SELECT COUNT\(\*\) FROM "merge_request_metrics"/))
end
context 'when total_time_to_merge and count is queried' do
+ let_it_be(:merge_request_2) do
+ create(:merge_request, :unique_branches, source_project: project).tap do |mr|
+ mr.metrics.update!(merged_at: merged_at, created_at: merged_at - 1.day)
+ end
+ end
+
let(:query) do
graphql_query_for(:project, { full_path: project.full_path }, <<~QUERY)
mergeRequests(mergedAfter: "2020-01-01", mergedBefore: "2020-01-05", first: 0) {
@@ -537,11 +549,18 @@ RSpec.describe 'getting merge request listings nested in a project' do
QUERY
end
- it 'does not query the merge requests table for the total_time_to_merge' do
+ it 'uses the merge_request_metrics table for total_time_to_merge' do
query_recorder = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
- queries = query_recorder.data.each_value.first[:occurrences]
- expect(queries).to include(match(/SELECT.+SUM.+FROM "merge_request_metrics" WHERE/))
+ expect(query_recorder.log).to include(match(/SELECT.+SUM.+FROM "merge_request_metrics" WHERE/))
+ end
+
+ it 'returns the correct total time to merge' do
+ post_graphql(query, current_user: current_user)
+
+ sum = graphql_data_at(:project, :merge_requests, :total_time_to_merge)
+
+ expect(sum).to eq(3.days.to_f)
end
end
diff --git a/spec/requests/api/graphql/project/milestones_spec.rb b/spec/requests/api/graphql/project/milestones_spec.rb
index 2fede4c7285..3e8948d83b1 100644
--- a/spec/requests/api/graphql/project/milestones_spec.rb
+++ b/spec/requests/api/graphql/project/milestones_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe 'getting milestone listings nested in a project' do
def result_list(expected)
expected.map do |milestone|
- a_hash_including('id' => global_id_of(milestone))
+ a_graphql_entity_for(milestone)
end
end
diff --git a/spec/requests/api/graphql/project/pipeline_spec.rb b/spec/requests/api/graphql/project/pipeline_spec.rb
index 73e02e2a4b1..ccf97918021 100644
--- a/spec/requests/api/graphql/project/pipeline_spec.rb
+++ b/spec/requests/api/graphql/project/pipeline_spec.rb
@@ -89,17 +89,16 @@ RSpec.describe 'getting pipeline information nested in a project' do
post_graphql(query, current_user: current_user)
expect(graphql_data_at(*path, :jobs, :nodes)).to contain_exactly(
- a_hash_including(
- 'name' => build_job.name,
- 'status' => build_job.status.upcase,
- 'duration' => build_job.duration
+ a_graphql_entity_for(
+ build_job, :name, :duration,
+ 'status' => build_job.status.upcase
),
- a_hash_including(
- 'id' => global_id_of(failed_build),
+ a_graphql_entity_for(
+ failed_build,
'status' => failed_build.status.upcase
),
- a_hash_including(
- 'id' => global_id_of(bridge),
+ a_graphql_entity_for(
+ bridge,
'status' => bridge.status.upcase
)
)
@@ -135,7 +134,7 @@ RSpec.describe 'getting pipeline information nested in a project' do
post_graphql(query, current_user: current_user, variables: variables)
expect(graphql_data_at(*path, :jobs, :nodes))
- .to contain_exactly(a_hash_including('id' => global_id_of(failed_build)))
+ .to contain_exactly(a_graphql_entity_for(failed_build))
end
end
@@ -166,7 +165,7 @@ RSpec.describe 'getting pipeline information nested in a project' do
end
let(:the_job) do
- a_hash_including('name' => build_job.name, 'id' => global_id_of(build_job))
+ a_graphql_entity_for(build_job, :name)
end
it 'can request a build by name' do
diff --git a/spec/requests/api/graphql/project/project_members_spec.rb b/spec/requests/api/graphql/project/project_members_spec.rb
index 315d44884ff..c3281b44954 100644
--- a/spec/requests/api/graphql/project/project_members_spec.rb
+++ b/spec/requests/api/graphql/project/project_members_spec.rb
@@ -60,7 +60,10 @@ RSpec.describe 'getting project members information' do
fetch_members(project: parent_project, args: { relations: [:DIRECT] })
expect(graphql_errors).to be_nil
- expect(graphql_data_at(:project, :project_members, :edges, :node)).to contain_exactly({ 'user' => { 'id' => global_id_of(user) } }, 'user' => nil)
+ expect(graphql_data_at(:project, :project_members, :edges, :node)).to contain_exactly(
+ a_graphql_entity_for(user: a_graphql_entity_for(user)),
+ { 'user' => nil }
+ )
end
end
@@ -238,7 +241,7 @@ RSpec.describe 'getting project members information' do
def expect_array_response(*items)
expect(response).to have_gitlab_http_status(:success)
- member_gids = graphql_data_at(:project, :project_members, :edges, :node, :user, :id)
- expect(member_gids).to match_array(items.map { |u| global_id_of(u) })
+ members = graphql_data_at(:project, :project_members, :edges, :node, :user)
+ expect(members).to match_array(items.map { |u| a_graphql_entity_for(u) })
end
end
diff --git a/spec/requests/api/graphql/project/release_spec.rb b/spec/requests/api/graphql/project/release_spec.rb
index 77abac4ef04..c4899dbb71e 100644
--- a/spec/requests/api/graphql/project/release_spec.rb
+++ b/spec/requests/api/graphql/project/release_spec.rb
@@ -77,10 +77,10 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do
post_query
expected = release.milestones.order_by_dates_and_title.map do |milestone|
- { 'id' => global_id_of(milestone), 'title' => milestone.title }
+ a_graphql_entity_for(milestone, :title)
end
- expect(data).to eq(expected)
+ expect(data).to match(expected)
end
end
@@ -94,10 +94,7 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do
it 'finds the author of the release' do
post_query
- expect(data).to eq(
- 'id' => global_id_of(release.author),
- 'username' => release.author.username
- )
+ expect(data).to match a_graphql_entity_for(release.author, :username)
end
end
@@ -142,13 +139,11 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do
post_query
expected = release.links.map do |link|
- {
- 'id' => global_id_of(link),
- 'name' => link.name,
- 'url' => link.url,
+ a_graphql_entity_for(
+ link, :name, :url,
'external' => link.external?,
'directAssetUrl' => link.filepath ? Gitlab::Routing.url_helpers.project_release_url(project, release) << "/downloads#{link.filepath}" : link.url
- }
+ )
end
expect(data).to match_array(expected)
@@ -218,10 +213,8 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do
evidence = release.evidences.first.present
- expect(data["nodes"].first).to eq(
- 'id' => global_id_of(evidence),
- 'sha' => evidence.sha,
- 'filepath' => evidence.filepath,
+ expect(data["nodes"].first).to match a_graphql_entity_for(
+ evidence, :sha, :filepath,
'collectedAt' => evidence.collected_at.utc.iso8601
)
end
@@ -274,10 +267,10 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do
post_query
expected = release.milestones.order_by_dates_and_title.map do |milestone|
- { 'id' => global_id_of(milestone), 'title' => milestone.title }
+ a_graphql_entity_for(milestone, :title)
end
- expect(data).to eq(expected)
+ expect(data).to match(expected)
end
end
@@ -291,10 +284,7 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do
it 'finds the author of the release' do
post_query
- expect(data).to eq(
- 'id' => global_id_of(release.author),
- 'username' => release.author.username
- )
+ expect(data).to match a_graphql_entity_for(release.author, :username)
end
end
@@ -339,13 +329,11 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do
post_query
expected = release.links.map do |link|
- {
- 'id' => global_id_of(link),
- 'name' => link.name,
- 'url' => link.url,
+ a_graphql_entity_for(
+ link, :name, :url,
'external' => true,
'directAssetUrl' => link.filepath ? Gitlab::Routing.url_helpers.project_release_url(project, release) << "/downloads#{link.filepath}" : link.url
- }
+ )
end
expect(data).to match_array(expected)
diff --git a/spec/requests/api/graphql/project/terraform/state_spec.rb b/spec/requests/api/graphql/project/terraform/state_spec.rb
index 9f1d9ab204a..8f2d2cffef2 100644
--- a/spec/requests/api/graphql/project/terraform/state_spec.rb
+++ b/spec/requests/api/graphql/project/terraform/state_spec.rb
@@ -57,22 +57,22 @@ RSpec.describe 'query a single terraform state' do
it_behaves_like 'a working graphql query'
it 'returns terraform state data' do
- expect(data).to match(a_hash_including({
- 'id' => global_id_of(terraform_state),
- 'name' => terraform_state.name,
+ expect(data).to match a_graphql_entity_for(
+ terraform_state,
+ :name,
'lockedAt' => terraform_state.locked_at.iso8601,
'createdAt' => terraform_state.created_at.iso8601,
'updatedAt' => terraform_state.updated_at.iso8601,
- 'lockedByUser' => { 'id' => global_id_of(terraform_state.locked_by_user) },
- 'latestVersion' => {
- 'id' => eq(global_id_of(latest_version)),
+ 'lockedByUser' => a_graphql_entity_for(terraform_state.locked_by_user),
+ 'latestVersion' => a_graphql_entity_for(
+ latest_version,
'serial' => eq(latest_version.version),
'createdAt' => eq(latest_version.created_at.iso8601),
'updatedAt' => eq(latest_version.updated_at.iso8601),
- 'createdByUser' => { 'id' => eq(global_id_of(latest_version.created_by_user)) },
+ 'createdByUser' => a_graphql_entity_for(latest_version.created_by_user),
'job' => { 'name' => eq(latest_version.build.name) }
- }
- }))
+ )
+ )
end
context 'unauthorized users' do
diff --git a/spec/requests/api/graphql/project/terraform/states_spec.rb b/spec/requests/api/graphql/project/terraform/states_spec.rb
index 2879530acc5..a7ec6f69776 100644
--- a/spec/requests/api/graphql/project/terraform/states_spec.rb
+++ b/spec/requests/api/graphql/project/terraform/states_spec.rb
@@ -62,23 +62,22 @@ RSpec.describe 'query terraform states' do
)
)
- expect(data['nodes']).to contain_exactly({
- 'id' => global_id_of(terraform_state),
- 'name' => terraform_state.name,
+ expect(data['nodes']).to contain_exactly a_graphql_entity_for(
+ terraform_state, :name,
'lockedAt' => terraform_state.locked_at.iso8601,
'createdAt' => terraform_state.created_at.iso8601,
'updatedAt' => terraform_state.updated_at.iso8601,
- 'lockedByUser' => { 'id' => global_id_of(terraform_state.locked_by_user) },
- 'latestVersion' => {
- 'id' => eq(global_id_of(latest_version)),
+ 'lockedByUser' => a_graphql_entity_for(terraform_state.locked_by_user),
+ 'latestVersion' => a_graphql_entity_for(
+ latest_version,
'serial' => eq(latest_version.version),
'downloadPath' => eq(download_path),
'createdAt' => eq(latest_version.created_at.iso8601),
'updatedAt' => eq(latest_version.updated_at.iso8601),
- 'createdByUser' => { 'id' => eq(global_id_of(latest_version.created_by_user)) },
+ 'createdByUser' => a_graphql_entity_for(latest_version.created_by_user),
'job' => { 'name' => eq(latest_version.build.name) }
- }
- })
+ )
+ )
end
it 'returns count of terraform states' do
diff --git a/spec/requests/api/graphql/query_spec.rb b/spec/requests/api/graphql/query_spec.rb
index d650acc8354..4aa9c4b8254 100644
--- a/spec/requests/api/graphql/query_spec.rb
+++ b/spec/requests/api/graphql/query_spec.rb
@@ -76,10 +76,8 @@ RSpec.describe 'Query' do
it_behaves_like 'a working graphql query'
it_behaves_like 'a query that needs authorization'
- context 'the current user is able to read designs' do
- it 'fetches the expected data' do
- expect(query_result).to eq('id' => global_id_of(version), 'sha' => version.sha)
- end
+ it 'fetches the expected data' do
+ expect(query_result).to match a_graphql_entity_for(version, :sha)
end
end
@@ -106,13 +104,13 @@ RSpec.describe 'Query' do
context 'the current user is able to read designs' do
it 'fetches the expected data, including the correct associations' do
- expect(query_result).to eq(
- 'id' => global_id_of(design_at_version),
+ expect(query_result).to match a_graphql_entity_for(
+ design_at_version,
'filename' => design_at_version.design.filename,
- 'version' => { 'id' => global_id_of(version), 'sha' => version.sha },
- 'design' => { 'id' => global_id_of(design) },
+ 'version' => a_graphql_entity_for(version, :sha),
+ 'design' => a_graphql_entity_for(design),
'issue' => { 'title' => issue.title, 'iid' => issue.iid.to_s },
- 'project' => { 'id' => global_id_of(project), 'fullPath' => project.full_path }
+ 'project' => a_graphql_entity_for(project, :full_path)
)
end
end
diff --git a/spec/requests/api/graphql/user/starred_projects_query_spec.rb b/spec/requests/api/graphql/user/starred_projects_query_spec.rb
index a8c087d1fbf..37a85b98e5f 100644
--- a/spec/requests/api/graphql/user/starred_projects_query_spec.rb
+++ b/spec/requests/api/graphql/user/starred_projects_query_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe 'Getting starredProjects of the user' do
it 'found only public project' do
expect(starred_projects).to contain_exactly(
- a_hash_including('id' => global_id_of(project_a))
+ a_graphql_entity_for(project_a)
)
end
@@ -51,9 +51,9 @@ RSpec.describe 'Getting starredProjects of the user' do
it 'found all projects' do
expect(starred_projects).to contain_exactly(
- a_hash_including('id' => global_id_of(project_a)),
- a_hash_including('id' => global_id_of(project_b)),
- a_hash_including('id' => global_id_of(project_c))
+ a_graphql_entity_for(project_a),
+ a_graphql_entity_for(project_b),
+ a_graphql_entity_for(project_c)
)
end
end
@@ -69,8 +69,8 @@ RSpec.describe 'Getting starredProjects of the user' do
it 'finds public and member projects' do
expect(starred_projects).to contain_exactly(
- a_hash_including('id' => global_id_of(project_a)),
- a_hash_including('id' => global_id_of(project_b))
+ a_graphql_entity_for(project_a),
+ a_graphql_entity_for(project_b)
)
end
end
@@ -93,9 +93,9 @@ RSpec.describe 'Getting starredProjects of the user' do
it 'finds all projects starred by the user, which the current user has access to' do
expect(starred_projects).to contain_exactly(
- a_hash_including('id' => global_id_of(project_a)),
- a_hash_including('id' => global_id_of(project_b)),
- a_hash_including('id' => global_id_of(project_c))
+ a_graphql_entity_for(project_a),
+ a_graphql_entity_for(project_b),
+ a_graphql_entity_for(project_c)
)
end
end
diff --git a/spec/requests/api/graphql/user_query_spec.rb b/spec/requests/api/graphql/user_query_spec.rb
index 1cba3674d25..8f286180617 100644
--- a/spec/requests/api/graphql/user_query_spec.rb
+++ b/spec/requests/api/graphql/user_query_spec.rb
@@ -91,11 +91,11 @@ RSpec.describe 'getting user information' do
presenter = UserPresenter.new(user)
expect(graphql_data['user']).to match(
- a_hash_including(
- 'id' => global_id_of(user),
+ a_graphql_entity_for(
+ user,
+ :username,
'state' => presenter.state,
'name' => presenter.name,
- 'username' => presenter.username,
'webUrl' => presenter.web_url,
'avatarUrl' => presenter.avatar_url,
'email' => presenter.public_email,
@@ -121,9 +121,9 @@ RSpec.describe 'getting user information' do
it 'can be found' do
expect(assigned_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(assigned_mr)),
- a_hash_including('id' => global_id_of(assigned_mr_b)),
- a_hash_including('id' => global_id_of(assigned_mr_c))
+ a_graphql_entity_for(assigned_mr),
+ a_graphql_entity_for(assigned_mr_b),
+ a_graphql_entity_for(assigned_mr_c)
)
end
@@ -145,7 +145,7 @@ RSpec.describe 'getting user information' do
it 'selects the correct MRs' do
expect(assigned_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(assigned_mr_b))
+ a_graphql_entity_for(assigned_mr_b)
)
end
end
@@ -157,8 +157,8 @@ RSpec.describe 'getting user information' do
it 'selects the correct MRs' do
expect(assigned_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(assigned_mr_b)),
- a_hash_including('id' => global_id_of(assigned_mr_c))
+ a_graphql_entity_for(assigned_mr_b),
+ a_graphql_entity_for(assigned_mr_c)
)
end
end
@@ -169,7 +169,7 @@ RSpec.describe 'getting user information' do
it 'finds the authored mrs' do
expect(assigned_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(assigned_mr_b))
+ a_graphql_entity_for(assigned_mr_b)
)
end
end
@@ -185,8 +185,8 @@ RSpec.describe 'getting user information' do
post_graphql(query, current_user: current_user)
expect(assigned_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(assigned_mr_b)),
- a_hash_including('id' => global_id_of(assigned_mr_c))
+ a_graphql_entity_for(assigned_mr_b),
+ a_graphql_entity_for(assigned_mr_c)
)
end
end
@@ -212,9 +212,9 @@ RSpec.describe 'getting user information' do
it 'can be found' do
expect(reviewed_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(reviewed_mr)),
- a_hash_including('id' => global_id_of(reviewed_mr_b)),
- a_hash_including('id' => global_id_of(reviewed_mr_c))
+ a_graphql_entity_for(reviewed_mr),
+ a_graphql_entity_for(reviewed_mr_b),
+ a_graphql_entity_for(reviewed_mr_c)
)
end
@@ -236,7 +236,7 @@ RSpec.describe 'getting user information' do
it 'selects the correct MRs' do
expect(reviewed_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(reviewed_mr_b))
+ a_graphql_entity_for(reviewed_mr_b)
)
end
end
@@ -248,8 +248,8 @@ RSpec.describe 'getting user information' do
it 'selects the correct MRs' do
expect(reviewed_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(reviewed_mr_b)),
- a_hash_including('id' => global_id_of(reviewed_mr_c))
+ a_graphql_entity_for(reviewed_mr_b),
+ a_graphql_entity_for(reviewed_mr_c)
)
end
end
@@ -260,7 +260,7 @@ RSpec.describe 'getting user information' do
it 'finds the authored mrs' do
expect(reviewed_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(reviewed_mr_b))
+ a_graphql_entity_for(reviewed_mr_b)
)
end
end
@@ -275,7 +275,7 @@ RSpec.describe 'getting user information' do
post_graphql(query, current_user: current_user)
expect(reviewed_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(reviewed_mr_c))
+ a_graphql_entity_for(reviewed_mr_c)
)
end
end
@@ -301,9 +301,9 @@ RSpec.describe 'getting user information' do
it 'can be found' do
expect(authored_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(authored_mr)),
- a_hash_including('id' => global_id_of(authored_mr_b)),
- a_hash_including('id' => global_id_of(authored_mr_c))
+ a_graphql_entity_for(authored_mr),
+ a_graphql_entity_for(authored_mr_b),
+ a_graphql_entity_for(authored_mr_c)
)
end
@@ -329,8 +329,8 @@ RSpec.describe 'getting user information' do
post_graphql(query, current_user: current_user)
expect(authored_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(authored_mr)),
- a_hash_including('id' => global_id_of(authored_mr_c))
+ a_graphql_entity_for(authored_mr),
+ a_graphql_entity_for(authored_mr_c)
)
end
end
@@ -346,8 +346,8 @@ RSpec.describe 'getting user information' do
post_graphql(query, current_user: current_user)
expect(authored_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(authored_mr_b)),
- a_hash_including('id' => global_id_of(authored_mr_c))
+ a_graphql_entity_for(authored_mr_b),
+ a_graphql_entity_for(authored_mr_c)
)
end
end
@@ -359,7 +359,7 @@ RSpec.describe 'getting user information' do
it 'selects the correct MRs' do
expect(authored_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(authored_mr_b))
+ a_graphql_entity_for(authored_mr_b)
)
end
end
@@ -371,8 +371,8 @@ RSpec.describe 'getting user information' do
it 'selects the correct MRs' do
expect(authored_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(authored_mr_b)),
- a_hash_including('id' => global_id_of(authored_mr_c))
+ a_graphql_entity_for(authored_mr_b),
+ a_graphql_entity_for(authored_mr_c)
)
end
end
@@ -417,7 +417,7 @@ RSpec.describe 'getting user information' do
it 'can be found' do
expect(group_memberships).to include(
- a_hash_including('id' => global_id_of(membership_a))
+ a_graphql_entity_for(membership_a)
)
end
end
@@ -440,7 +440,7 @@ RSpec.describe 'getting user information' do
it 'can be found' do
expect(project_memberships).to include(
- a_hash_including('id' => global_id_of(membership_a))
+ a_graphql_entity_for(membership_a)
)
end
end
@@ -460,7 +460,7 @@ RSpec.describe 'getting user information' do
it 'can be found' do
expect(authored_mrs).to include(
- a_hash_including('id' => global_id_of(authored_mr))
+ a_graphql_entity_for(authored_mr)
)
end
end
@@ -480,9 +480,9 @@ RSpec.describe 'getting user information' do
it 'can be found' do
expect(assigned_mrs).to contain_exactly(
- a_hash_including('id' => global_id_of(assigned_mr)),
- a_hash_including('id' => global_id_of(assigned_mr_b)),
- a_hash_including('id' => global_id_of(assigned_mr_c))
+ a_graphql_entity_for(assigned_mr),
+ a_graphql_entity_for(assigned_mr_b),
+ a_graphql_entity_for(assigned_mr_c)
)
end
end
diff --git a/spec/requests/api/graphql/users_spec.rb b/spec/requests/api/graphql/users_spec.rb
index fe824834a2c..79ee3c2cb57 100644
--- a/spec/requests/api/graphql/users_spec.rb
+++ b/spec/requests/api/graphql/users_spec.rb
@@ -72,12 +72,12 @@ RSpec.describe 'Users' do
post_query
expect(graphql_data.dig('users', 'nodes')).to include(
- { "id" => user0.to_global_id.to_s },
- { "id" => user1.to_global_id.to_s },
- { "id" => user2.to_global_id.to_s },
- { "id" => user3.to_global_id.to_s },
- { "id" => admin.to_global_id.to_s },
- { "id" => another_admin.to_global_id.to_s }
+ a_graphql_entity_for(user0),
+ a_graphql_entity_for(user1),
+ a_graphql_entity_for(user2),
+ a_graphql_entity_for(user3),
+ a_graphql_entity_for(admin),
+ a_graphql_entity_for(another_admin)
)
end
end
@@ -91,15 +91,15 @@ RSpec.describe 'Users' do
post_graphql(query, current_user: current_user)
expect(graphql_data.dig('users', 'nodes')).to include(
- { "id" => another_admin.to_global_id.to_s },
- { "id" => admin.to_global_id.to_s }
+ a_graphql_entity_for(another_admin),
+ a_graphql_entity_for(admin)
)
expect(graphql_data.dig('users', 'nodes')).not_to include(
- { "id" => user0.to_global_id.to_s },
- { "id" => user1.to_global_id.to_s },
- { "id" => user2.to_global_id.to_s },
- { "id" => user3.to_global_id.to_s }
+ a_graphql_entity_for(user0),
+ a_graphql_entity_for(user1),
+ a_graphql_entity_for(user2),
+ a_graphql_entity_for(user3)
)
end
end
@@ -114,7 +114,7 @@ RSpec.describe 'Users' do
end
context 'when sorting by created_at' do
- let_it_be(:ascending_users) { [user3, user2, user1, user0].map { |u| global_id_of(u) } }
+ let_it_be(:ascending_users) { [user3, user2, user1, user0].map { |u| global_id_of(u).to_s } }
context 'when ascending' do
it_behaves_like 'sorted paginated query' do
diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb
index bc5a8b3e006..5b34c21989a 100644
--- a/spec/requests/api/graphql/work_item_spec.rb
+++ b/spec/requests/api/graphql/work_item_spec.rb
@@ -33,7 +33,8 @@ RSpec.describe 'Query.work_item(id)' do
'lockVersion' => work_item.lock_version,
'state' => "OPEN",
'title' => work_item.title,
- 'workItemType' => hash_including('id' => work_item.work_item_type.to_gid.to_s)
+ 'workItemType' => hash_including('id' => work_item.work_item_type.to_gid.to_s),
+ 'userPermissions' => { 'readWorkItem' => true, 'updateWorkItem' => true, 'deleteWorkItem' => false }
)
end