diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-21 07:08:36 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-21 07:08:36 +0000 |
commit | 48aff82709769b098321c738f3444b9bdaa694c6 (patch) | |
tree | e00c7c43e2d9b603a5a6af576b1685e400410dee /spec/requests/api/graphql/project | |
parent | 879f5329ee916a948223f8f43d77fba4da6cd028 (diff) | |
download | gitlab-ce-48aff82709769b098321c738f3444b9bdaa694c6.tar.gz |
Add latest changes from gitlab-org/gitlab@13-5-stable-eev13.5.0-rc42
Diffstat (limited to 'spec/requests/api/graphql/project')
5 files changed, 321 insertions, 20 deletions
diff --git a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb index d3a2e6a1deb..8deed75a466 100644 --- a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb +++ b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb @@ -139,6 +139,19 @@ RSpec.describe 'getting Alert Management Alerts' do it { expect(alerts.size).to eq(0) } end end + + context 'assignee_username' do + let(:alert) { triggered_alert } + let(:assignee) { alert.assignees.first! } + let(:params) { { assignee_username: assignee.username } } + + it_behaves_like 'a working graphql query' + + specify do + expect(alerts.size).to eq(1) + expect(first_alert['iid']).to eq(alert.iid.to_s) + end + end end end 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 65191e057c7..e25453510d5 100644 --- a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb +++ b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb @@ -31,8 +31,8 @@ RSpec.describe 'Getting designs related to an issue' do post_graphql(query(note_fields), current_user: nil) designs_data = graphql_data['project']['issue']['designs']['designs'] - design_data = designs_data['edges'].first['node'] - note_data = design_data['notes']['edges'].first['node'] + 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) end @@ -40,14 +40,10 @@ RSpec.describe 'Getting designs related to an issue' do def query(note_fields = all_graphql_fields_for(Note)) design_node = <<~NODE designs { - edges { - node { - notes { - edges { - node { - #{note_fields} - } - } + nodes { + notes { + nodes { + #{note_fields} } } } diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb index 5d4276f47ca..40fec6ba068 100644 --- a/spec/requests/api/graphql/project/issues_spec.rb +++ b/spec/requests/api/graphql/project/issues_spec.rb @@ -53,16 +53,37 @@ RSpec.describe 'getting an issue list for a project' do context 'when limiting the number of results' do let(:query) do - graphql_query_for( - 'project', - { 'fullPath' => project.full_path }, - "issues(first: 1) { #{fields} }" - ) + <<~GQL + query($path: ID!, $n: Int) { + project(fullPath: $path) { + issues(first: $n) { #{fields} } + } + } + GQL + end + + let(:issue_limit) { 1 } + let(:variables) do + { path: project.full_path, n: issue_limit } end it_behaves_like 'a working graphql query' do before do - post_graphql(query, current_user: current_user) + post_graphql(query, current_user: current_user, variables: variables) + end + + it 'only returns N issues' do + expect(issues_data.size).to eq(issue_limit) + end + end + + context 'no limit is provided' do + let(:issue_limit) { nil } + + it 'returns all issues' do + post_graphql(query, current_user: current_user, variables: variables) + + expect(issues_data.size).to be > 1 end end @@ -71,7 +92,7 @@ RSpec.describe 'getting an issue list for a project' do # Newest first, we only want to see the newest checked expect(Ability).not_to receive(:allowed?).with(current_user, :read_issue, issues.first) - post_graphql(query, current_user: current_user) + post_graphql(query, current_user: current_user, variables: variables) 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 22b003501a1..c737e0b8caf 100644 --- a/spec/requests/api/graphql/project/merge_requests_spec.rb +++ b/spec/requests/api/graphql/project/merge_requests_spec.rb @@ -13,6 +13,7 @@ RSpec.describe 'getting merge request listings nested in a project' do let_it_be(:merge_request_b) { create(:merge_request, :closed, :unique_branches, source_project: project) } let_it_be(:merge_request_c) { create(:labeled_merge_request, :closed, :unique_branches, source_project: project, labels: [label]) } let_it_be(:merge_request_d) { create(:merge_request, :locked, :unique_branches, source_project: project) } + let_it_be(:merge_request_e) { create(:merge_request, :unique_branches, source_project: project) } let(:results) { graphql_data.dig('project', 'mergeRequests', 'nodes') } @@ -118,7 +119,7 @@ RSpec.describe 'getting merge request listings nested in a project' do context 'there are no search params' do let(:search_params) { nil } - let(:mrs) { [merge_request_a, merge_request_b, merge_request_c, merge_request_d] } + let(:mrs) { [merge_request_a, merge_request_b, merge_request_c, merge_request_d, merge_request_e] } it_behaves_like 'searching with parameters' end @@ -172,6 +173,28 @@ RSpec.describe 'getting merge request listings nested in a project' do it_behaves_like 'searching with parameters' end + context 'when requesting `approved_by`' do + let(:search_params) { { iids: [merge_request_a.iid.to_s, merge_request_b.iid.to_s] } } + let(:extra_iid_for_second_query) { merge_request_c.iid.to_s } + let(:requested_fields) { query_graphql_field(:approved_by, nil, query_graphql_field(:nodes, nil, [:username])) } + + def execute_query + query = query_merge_requests(requested_fields) + post_graphql(query, current_user: current_user) + end + + it 'exposes approver username' do + merge_request_a.approved_by_users << current_user + + execute_query + + user_data = { 'username' => current_user.username } + expect(results).to include(a_hash_including('approvedBy' => { 'nodes' => array_including(user_data) })) + end + + include_examples 'N+1 query check' + end + describe 'fields' do let(:requested_fields) { nil } let(:extra_iid_for_second_query) { merge_request_c.iid.to_s } @@ -209,7 +232,19 @@ RSpec.describe 'getting merge request listings nested in a project' do include_examples 'N+1 query check' end + + context 'when requesting `user_notes_count`' do + let(:requested_fields) { [:user_notes_count] } + + before do + create_list(:note_on_merge_request, 2, noteable: merge_request_a, project: project) + create(:note_on_merge_request, noteable: merge_request_c, project: project) + end + + include_examples 'N+1 query check' + end end + describe 'sorting and pagination' do let(:data_path) { [:project, :mergeRequests] } @@ -241,16 +276,50 @@ RSpec.describe 'getting merge request listings nested in a project' do let(:expected_results) do [ merge_request_b, - merge_request_c, merge_request_d, + merge_request_c, + merge_request_e, merge_request_a ].map(&:to_gid).map(&:to_s) end before do - merge_request_c.metrics.update!(merged_at: 5.days.ago) + five_days_ago = 5.days.ago + + merge_request_d.metrics.update!(merged_at: five_days_ago) + + # same merged_at, the second order column will decide (merge_request.id) + merge_request_c.metrics.update!(merged_at: five_days_ago) + merge_request_b.metrics.update!(merged_at: 1.day.ago) end + + context 'when paginating backwards' do + let(:params) { 'first: 2, sort: MERGED_AT_DESC' } + let(:page_info) { 'pageInfo { startCursor endCursor }' } + + before do + post_graphql(pagination_query(params, page_info), current_user: current_user) + end + + it 'paginates backwards correctly' do + # first page + first_page_response_data = graphql_dig_at(Gitlab::Json.parse(response.body), :data, *data_path, :edges) + end_cursor = graphql_dig_at(Gitlab::Json.parse(response.body), :data, :project, :mergeRequests, :pageInfo, :endCursor) + + # second page + params = "first: 2, after: \"#{end_cursor}\", sort: MERGED_AT_DESC" + post_graphql(pagination_query(params, page_info), current_user: current_user) + start_cursor = graphql_dig_at(Gitlab::Json.parse(response.body), :data, :project, :mergeRequests, :pageInfo, :start_cursor) + + # going back to the first page + + params = "last: 2, before: \"#{start_cursor}\", sort: MERGED_AT_DESC" + post_graphql(pagination_query(params, page_info), current_user: current_user) + backward_paginated_response_data = graphql_dig_at(Gitlab::Json.parse(response.body), :data, *data_path, :edges) + expect(first_page_response_data).to eq(backward_paginated_response_data) + end + end end end end diff --git a/spec/requests/api/graphql/project/milestones_spec.rb b/spec/requests/api/graphql/project/milestones_spec.rb new file mode 100644 index 00000000000..2fede4c7285 --- /dev/null +++ b/spec/requests/api/graphql/project/milestones_spec.rb @@ -0,0 +1,202 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'getting milestone listings nested in a project' do + include GraphqlHelpers + + let_it_be(:today) { Time.now.utc.to_date } + let_it_be(:project) { create(:project, :repository, :public) } + let_it_be(:current_user) { create(:user) } + + let_it_be(:no_dates) { create(:milestone, project: project, title: 'no dates') } + let_it_be(:no_end) { create(:milestone, project: project, title: 'no end', start_date: today - 10.days) } + let_it_be(:no_start) { create(:milestone, project: project, title: 'no start', due_date: today - 5.days) } + let_it_be(:fully_past) { create(:milestone, project: project, title: 'past', start_date: today - 10.days, due_date: today - 5.days) } + let_it_be(:covers_today) { create(:milestone, project: project, title: 'present', start_date: today - 5.days, due_date: today + 5.days) } + let_it_be(:fully_future) { create(:milestone, project: project, title: 'future', start_date: today + 5.days, due_date: today + 10.days) } + let_it_be(:closed) { create(:milestone, :closed, project: project) } + + let(:results) { graphql_data_at(:project, :milestones, :nodes) } + + let(:search_params) { nil } + + def query_milestones(fields) + graphql_query_for( + :project, + { full_path: project.full_path }, + query_graphql_field(:milestones, search_params, [ + query_graphql_field(:nodes, nil, %i[id title]) + ]) + ) + end + + def result_list(expected) + expected.map do |milestone| + a_hash_including('id' => global_id_of(milestone)) + end + end + + let(:query) do + query_milestones(all_graphql_fields_for('Milestone', max_depth: 1)) + end + + let(:all_milestones) do + [no_dates, no_end, no_start, fully_past, fully_future, covers_today, closed] + end + + it_behaves_like 'a working graphql query' do + before do + post_graphql(query, current_user: current_user) + end + end + + shared_examples 'searching with parameters' do + it 'finds the right milestones' do + post_graphql(query, current_user: current_user) + + expect(results).to match_array(result_list(expected)) + end + end + + context 'there are no search params' do + let(:search_params) { nil } + let(:expected) { all_milestones } + + it_behaves_like 'searching with parameters' + end + + context 'the search params do not match anything' do + let(:search_params) { { title: 'wibble' } } + let(:expected) { [] } + + it_behaves_like 'searching with parameters' + end + + context 'searching by state:closed' do + let(:search_params) { { state: :closed } } + let(:expected) { [closed] } + + it_behaves_like 'searching with parameters' + end + + context 'searching by state:active' do + let(:search_params) { { state: :active } } + let(:expected) { all_milestones - [closed] } + + it_behaves_like 'searching with parameters' + end + + context 'searching by title' do + let(:search_params) { { title: 'no start' } } + let(:expected) { [no_start] } + + it_behaves_like 'searching with parameters' + end + + context 'searching by search_title' do + let(:search_params) { { search_title: 'no' } } + let(:expected) { [no_dates, no_start, no_end] } + + it_behaves_like 'searching with parameters' + end + + context 'searching by containing_date' do + let(:search_params) { { containing_date: (today - 7.days).iso8601 } } + let(:expected) { [no_start, no_end, fully_past] } + + it_behaves_like 'searching with parameters' + end + + context 'searching by containing_date = today' do + let(:search_params) { { containing_date: today.iso8601 } } + let(:expected) { [no_end, covers_today] } + + it_behaves_like 'searching with parameters' + end + + context 'searching by custom range' do + let(:expected) { [no_end, fully_future] } + let(:search_params) do + { + start_date: (today + 6.days).iso8601, + end_date: (today + 7.days).iso8601 + } + end + + it_behaves_like 'searching with parameters' + end + + context 'using timeframe argument' do + let(:expected) { [no_end, fully_future] } + let(:search_params) do + { + timeframe: { + start: (today + 6.days).iso8601, + end: (today + 7.days).iso8601 + } + } + end + + it_behaves_like 'searching with parameters' + end + + describe 'timeframe validations' do + let(:vars) do + { + path: project.full_path, + start: (today + 6.days).iso8601, + end: (today + 7.days).iso8601 + } + end + + it_behaves_like 'a working graphql query' do + before do + query = <<~GQL + query($path: ID!, $start: Date!, $end: Date!) { + project(fullPath: $path) { + milestones(timeframe: { start: $start, end: $end }) { + nodes { id } + } + } + } + GQL + + post_graphql(query, current_user: current_user, variables: vars) + end + end + + it 'is invalid to provide timeframe and start_date/end_date' do + query = <<~GQL + query($path: ID!, $tstart: Date!, $tend: Date!, $start: Time!, $end: Time!) { + project(fullPath: $path) { + milestones(timeframe: { start: $tstart, end: $tend }, startDate: $start, endDate: $end) { + nodes { id } + } + } + } + GQL + + post_graphql(query, current_user: current_user, + variables: vars.merge(vars.transform_keys { |k| :"t#{k}" })) + + expect(graphql_errors).to contain_exactly(a_hash_including('message' => include('deprecated in favor of timeframe'))) + end + + it 'is invalid to invert the timeframe arguments' do + query = <<~GQL + query($path: ID!, $start: Date!, $end: Date!) { + project(fullPath: $path) { + milestones(timeframe: { start: $end, end: $start }) { + nodes { id } + } + } + } + GQL + + post_graphql(query, current_user: current_user, variables: vars) + + expect(graphql_errors).to contain_exactly(a_hash_including('message' => include('start must be before end'))) + end + end +end |