diff options
Diffstat (limited to 'spec/graphql')
102 files changed, 2061 insertions, 134 deletions
diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb index 0f21a55f7e9..8960ad91543 100644 --- a/spec/graphql/gitlab_schema_spec.rb +++ b/spec/graphql/gitlab_schema_spec.rb @@ -191,13 +191,17 @@ describe GitlabSchema do context 'for other classes' do # We cannot use an anonymous class here as `GlobalID` expects `.name` not # to return `nil` - class TestGlobalId - include GlobalID::Identification - attr_accessor :id - - def initialize(id) - @id = id + before do + test_global_id = Class.new do + include GlobalID::Identification + attr_accessor :id + + def initialize(id) + @id = id + end end + + stub_const('TestGlobalId', test_global_id) end it 'falls back to a regular find' do diff --git a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb new file mode 100644 index 00000000000..1e51767cf0e --- /dev/null +++ b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Mutations::AlertManagement::CreateAlertIssue do + let_it_be(:current_user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:alert) { create(:alert_management_alert, project: project, status: 'triggered') } + let(:args) { { project_path: project.full_path, iid: alert.iid } } + + specify { expect(described_class).to require_graphql_authorizations(:update_alert_management_alert) } + + describe '#resolve' do + subject(:resolve) { mutation_for(project, current_user).resolve(args) } + + context 'user has access to project' do + before do + project.add_developer(current_user) + end + + context 'when CreateAlertIssueService responds with success' do + it 'returns the issue with no errors' do + expect(resolve).to eq( + alert: alert.reload, + issue: Issue.last!, + errors: [] + ) + end + end + + context 'when CreateAlertIssue responds with an error' do + before do + allow_any_instance_of(::AlertManagement::CreateAlertIssueService) + .to receive(:execute) + .and_return(ServiceResponse.error(payload: { issue: nil }, message: 'An issue already exists')) + end + + it 'returns errors' do + expect(resolve).to eq( + alert: alert, + issue: nil, + errors: ['An issue already exists'] + ) + end + end + end + + context 'when resource is not accessible to the user' do + it 'raises an error if the resource is not accessible to the user' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + end + + private + + def mutation_for(project, user) + described_class.new(object: project, context: { current_user: user }, field: nil) + end +end diff --git a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb new file mode 100644 index 00000000000..8b9abd9497d --- /dev/null +++ b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Mutations::AlertManagement::UpdateAlertStatus do + let_it_be(:current_user) { create(:user) } + let_it_be(:alert) { create(:alert_management_alert, :triggered) } + let_it_be(:project) { alert.project } + let(:new_status) { Types::AlertManagement::StatusEnum.values['ACKNOWLEDGED'].value } + let(:args) { { status: new_status, project_path: project.full_path, iid: alert.iid } } + + specify { expect(described_class).to require_graphql_authorizations(:update_alert_management_alert) } + + describe '#resolve' do + subject(:resolve) { mutation_for(project, current_user).resolve(args) } + + context 'user has access to project' do + before do + project.add_developer(current_user) + end + + it 'changes the status' do + expect { resolve }.to change { alert.reload.acknowledged? }.to(true) + end + + it 'returns the alert with no errors' do + expect(resolve).to eq( + alert: alert, + errors: [] + ) + end + + context 'error occurs when updating' do + it 'returns the alert with errors' do + # Stub an error on the alert + allow_next_instance_of(Resolvers::AlertManagementAlertResolver) do |resolver| + allow(resolver).to receive(:resolve).and_return(alert) + end + + allow(alert).to receive(:save).and_return(false) + allow(alert).to receive(:errors).and_return( + double(full_messages: %w(foo bar)) + ) + expect(resolve).to eq( + alert: alert, + errors: ['foo and bar'] + ) + end + + context 'invalid status given' do + let(:new_status) { 'invalid_status' } + + it 'returns the alert with errors' do + expect(resolve).to eq( + alert: alert, + errors: [_('Invalid status')] + ) + end + end + end + end + + it 'raises an error if the resource is not accessible to the user' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + private + + def mutation_for(project, user) + described_class.new(object: project, context: { current_user: user }, field: nil) + end +end diff --git a/spec/graphql/mutations/branches/create_spec.rb b/spec/graphql/mutations/branches/create_spec.rb new file mode 100644 index 00000000000..744f8f1f2bc --- /dev/null +++ b/spec/graphql/mutations/branches/create_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Mutations::Branches::Create do + subject(:mutation) { described_class.new(object: nil, context: context, field: nil) } + + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:user) { create(:user) } + let_it_be(:context) do + GraphQL::Query::Context.new( + query: OpenStruct.new(schema: nil), + values: { current_user: user }, + object: nil + ) + end + + describe '#resolve' do + subject { mutation.resolve(project_path: project.full_path, name: branch, ref: ref) } + + let(:branch) { 'new_branch' } + let(:ref) { 'master' } + let(:mutated_branch) { subject[:branch] } + + it 'raises an error if the resource is not accessible to the user' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + + context 'when the user can create a branch' do + before do + project.add_developer(user) + + allow_next_instance_of(::Branches::CreateService, project, user) do |create_service| + allow(create_service).to receive(:execute).with(branch, ref) { service_result } + end + end + + context 'when service successfully creates a new branch' do + let(:service_result) { { status: :success, branch: double(name: branch) } } + + it 'returns a new branch' do + expect(mutated_branch.name).to eq(branch) + expect(subject[:errors]).to be_empty + end + end + + context 'when service fails to create a new branch' do + let(:service_result) { { status: :error, message: 'Branch already exists' } } + + it { expect(mutated_branch).to be_nil } + it { expect(subject[:errors]).to eq(['Branch already exists']) } + end + end + end +end diff --git a/spec/graphql/mutations/design_management/delete_spec.rb b/spec/graphql/mutations/design_management/delete_spec.rb new file mode 100644 index 00000000000..60be6dad62a --- /dev/null +++ b/spec/graphql/mutations/design_management/delete_spec.rb @@ -0,0 +1,145 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Mutations::DesignManagement::Delete do + include DesignManagementTestHelpers + + let(:issue) { create(:issue) } + let(:current_designs) { issue.designs.current } + let(:user) { issue.author } + let(:project) { issue.project } + let(:design_a) { create(:design, :with_file, issue: issue) } + let(:design_b) { create(:design, :with_file, issue: issue) } + let(:design_c) { create(:design, :with_file, issue: issue) } + let(:filenames) { [design_a, design_b, design_c].map(&:filename) } + + let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + + before do + stub_const('Errors', Gitlab::Graphql::Errors, transfer_nested_constants: true) + end + + def run_mutation + mutation = described_class.new(object: nil, context: { current_user: user }, field: nil) + mutation.resolve(project_path: project.full_path, iid: issue.iid, filenames: filenames) + end + + describe '#resolve' do + let(:expected_response) do + { errors: [], version: DesignManagement::Version.for_issue(issue).ordered.first } + end + + shared_examples "failures" do |error: Gitlab::Graphql::Errors::ResourceNotAvailable| + it "raises #{error.name}" do + expect { run_mutation }.to raise_error(error) + end + end + + shared_examples "resource not available" do + it_behaves_like "failures" + end + + context "when the feature is not available" do + before do + enable_design_management(false) + end + + it_behaves_like "resource not available" + end + + context "when the feature is available" do + before do + enable_design_management(true) + end + + context "when the user is not allowed to delete designs" do + let(:user) { create(:user) } + + it_behaves_like "resource not available" + end + + context 'deleting an already deleted file' do + before do + run_mutation + end + + it 'fails with an argument error' do + expect { run_mutation }.to raise_error(Gitlab::Graphql::Errors::ArgumentError) + end + end + + context "when deleting all the designs" do + let(:response) { run_mutation } + + it "returns a new version, and no errors" do + expect(response).to include(expected_response) + end + + describe 'the current designs' do + before do + run_mutation + end + + it 'is empty' do + expect(current_designs).to be_empty + end + end + + it 'runs no more than 28 queries' do + filenames.each(&:present?) # ignore setup + # Queries: as of 2019-08-28 + # ------------- + # 01. routing query + # 02. find project by id + # 03. project.project_features + # 04. find namespace by id and type + # 05,06. project.authorizations for user (same query twice) + # 07. find issue by iid + # 08. find project by id + # 09. find namespace by id + # 10. find group namespace by id + # 11. project.authorizations for user (same query as 5) + # 12. project.project_features (same query as 3) + # 13. project.authorizations for user (same query as 5) + # 14. current designs by filename and issue + # 15, 16 project.authorizations for user (same query as 5) + # 17. find route by id and source_type + # ------------- our queries are below: + # 18. start transaction 1 + # 19. start transaction 2 + # 20. find version by sha and issue + # 21. exists version with sha and issue? + # 22. leave transaction 2 + # 23. create version with sha and issue + # 24. create design-version links + # 25. validate version.actions.present? + # 26. validate version.issue.present? + # 27. validate version.sha is unique + # 28. leave transaction 1 + # + expect { run_mutation }.not_to exceed_query_limit(28) + end + end + + context "when deleting a design" do + let(:filenames) { [design_a.filename] } + let(:response) { run_mutation } + + it "returns the expected response" do + expect(response).to include(expected_response) + end + + describe 'the current designs' do + before do + run_mutation + end + + it 'does contain designs b and c' do + expect(current_designs).to contain_exactly(design_b, design_c) + end + end + end + end + end +end diff --git a/spec/graphql/mutations/design_management/upload_spec.rb b/spec/graphql/mutations/design_management/upload_spec.rb new file mode 100644 index 00000000000..783af70448c --- /dev/null +++ b/spec/graphql/mutations/design_management/upload_spec.rb @@ -0,0 +1,136 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Mutations::DesignManagement::Upload do + include DesignManagementTestHelpers + include ConcurrentHelpers + + let(:issue) { create(:issue) } + let(:user) { issue.author } + let(:project) { issue.project } + + subject(:mutation) do + described_class.new(object: nil, context: { current_user: user }, field: nil) + end + + def run_mutation(files_to_upload = files, project_path = project.full_path, iid = issue.iid) + mutation = described_class.new(object: nil, context: { current_user: user }, field: nil) + mutation.resolve(project_path: project_path, iid: iid, files: files_to_upload) + end + + describe "#resolve" do + let(:files) { [fixture_file_upload('spec/fixtures/dk.png')] } + + subject(:resolve) do + mutation.resolve(project_path: project.full_path, iid: issue.iid, files: files) + end + + shared_examples "resource not available" do + it "raises an error" do + expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context "when the feature is not available" do + it_behaves_like "resource not available" + end + + context "when the feature is available" do + before do + enable_design_management + end + + describe 'contention in the design repo' do + before do + issue.design_collection.repository.create_if_not_exists + end + + let(:files) do + ['dk.png', 'rails_sample.jpg', 'banana_sample.gif'] + .cycle + .take(Concurrent.processor_count * 2) + .map { |f| RenameableUpload.unique_file(f) } + end + + def creates_designs + prior_count = DesignManagement::Design.count + + expect { yield }.not_to raise_error + + expect(DesignManagement::Design.count).to eq(prior_count + files.size) + end + + describe 'running requests in parallel' do + it 'does not cause errors' do + creates_designs do + run_parallel(files.map { |f| -> { run_mutation([f]) } }) + end + end + end + + describe 'running requests in parallel on different issues' do + it 'does not cause errors' do + creates_designs do + issues = create_list(:issue, files.size, author: user) + issues.each { |i| i.project.add_developer(user) } + blocks = files.zip(issues).map do |(f, i)| + -> { run_mutation([f], i.project.full_path, i.iid) } + end + + run_parallel(blocks) + end + end + end + + describe 'running requests in serial' do + it 'does not cause errors' do + creates_designs do + files.each do |f| + run_mutation([f]) + end + end + end + end + end + + context "when the user is not allowed to upload designs" do + let(:user) { create(:user) } + + it_behaves_like "resource not available" + end + + context "a valid design" do + it "returns the updated designs" do + expect(resolve[:errors]).to eq [] + expect(resolve[:designs].map(&:filename)).to contain_exactly("dk.png") + end + end + + context "context when passing an invalid project" do + let(:project) { build(:project) } + + it_behaves_like "resource not available" + end + + context "context when passing an invalid issue" do + let(:issue) { build(:issue) } + + it_behaves_like "resource not available" + end + + context "when creating designs causes errors" do + before do + fake_service = double(::DesignManagement::SaveDesignsService) + + allow(fake_service).to receive(:execute).and_return(status: :error, message: "Something failed") + allow(::DesignManagement::SaveDesignsService).to receive(:new).and_return(fake_service) + end + + it "wraps the errors" do + expect(resolve[:errors]).to eq(["Something failed"]) + expect(resolve[:designs]).to eq([]) + end + end + end + end +end diff --git a/spec/graphql/mutations/issues/set_confidential_spec.rb b/spec/graphql/mutations/issues/set_confidential_spec.rb index 6031953c869..c90ce2658d6 100644 --- a/spec/graphql/mutations/issues/set_confidential_spec.rb +++ b/spec/graphql/mutations/issues/set_confidential_spec.rb @@ -8,6 +8,8 @@ describe Mutations::Issues::SetConfidential do subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + specify { expect(described_class).to require_graphql_authorizations(:update_issue) } + describe '#resolve' do let(:confidential) { true } let(:mutated_issue) { subject[:issue] } diff --git a/spec/graphql/mutations/issues/set_due_date_spec.rb b/spec/graphql/mutations/issues/set_due_date_spec.rb index 73ba11fc551..84df6fce7c7 100644 --- a/spec/graphql/mutations/issues/set_due_date_spec.rb +++ b/spec/graphql/mutations/issues/set_due_date_spec.rb @@ -8,6 +8,8 @@ describe Mutations::Issues::SetDueDate do subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + specify { expect(described_class).to require_graphql_authorizations(:update_issue) } + describe '#resolve' do let(:due_date) { 2.days.since } let(:mutated_issue) { subject[:issue] } diff --git a/spec/graphql/mutations/issues/update_spec.rb b/spec/graphql/mutations/issues/update_spec.rb index da286bb4092..8c3d01918fd 100644 --- a/spec/graphql/mutations/issues/update_spec.rb +++ b/spec/graphql/mutations/issues/update_spec.rb @@ -16,6 +16,8 @@ describe Mutations::Issues::Update do let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } let(:mutated_issue) { subject[:issue] } + specify { expect(described_class).to require_graphql_authorizations(:update_issue) } + describe '#resolve' do let(:mutation_params) do { diff --git a/spec/graphql/mutations/merge_requests/set_labels_spec.rb b/spec/graphql/mutations/merge_requests/set_labels_spec.rb index f58f35eb6f3..0fd2c20a5c8 100644 --- a/spec/graphql/mutations/merge_requests/set_labels_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_labels_spec.rb @@ -8,6 +8,8 @@ describe Mutations::MergeRequests::SetLabels do subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) } + describe '#resolve' do let(:label) { create(:label, project: merge_request.project) } let(:label2) { create(:label, project: merge_request.project) } diff --git a/spec/graphql/mutations/merge_requests/set_locked_spec.rb b/spec/graphql/mutations/merge_requests/set_locked_spec.rb index 12ae1314f22..d5219c781fd 100644 --- a/spec/graphql/mutations/merge_requests/set_locked_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_locked_spec.rb @@ -8,6 +8,8 @@ describe Mutations::MergeRequests::SetLocked do subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) } + describe '#resolve' do let(:locked) { true } let(:mutated_merge_request) { subject[:merge_request] } diff --git a/spec/graphql/mutations/merge_requests/set_milestone_spec.rb b/spec/graphql/mutations/merge_requests/set_milestone_spec.rb index ad7f2df0842..d77ec4de4d0 100644 --- a/spec/graphql/mutations/merge_requests/set_milestone_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_milestone_spec.rb @@ -8,6 +8,8 @@ describe Mutations::MergeRequests::SetMilestone do subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) } + describe '#resolve' do let(:milestone) { create(:milestone, project: merge_request.project) } let(:mutated_merge_request) { subject[:merge_request] } diff --git a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb index a28bab363f3..cf569a74aa9 100644 --- a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb @@ -9,6 +9,8 @@ describe Mutations::MergeRequests::SetSubscription do subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) } + describe '#resolve' do let(:subscribe) { true } let(:mutated_merge_request) { subject[:merge_request] } diff --git a/spec/graphql/mutations/merge_requests/set_wip_spec.rb b/spec/graphql/mutations/merge_requests/set_wip_spec.rb index 9f0adcf117a..7255d0fe7d7 100644 --- a/spec/graphql/mutations/merge_requests/set_wip_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_wip_spec.rb @@ -8,6 +8,8 @@ describe Mutations::MergeRequests::SetWip do subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) } + describe '#resolve' do let(:wip) { true } let(:mutated_merge_request) { subject[:merge_request] } diff --git a/spec/graphql/mutations/todos/mark_all_done_spec.rb b/spec/graphql/mutations/todos/mark_all_done_spec.rb index 98b22a3e761..4af00307969 100644 --- a/spec/graphql/mutations/todos/mark_all_done_spec.rb +++ b/spec/graphql/mutations/todos/mark_all_done_spec.rb @@ -17,6 +17,8 @@ describe Mutations::Todos::MarkAllDone do let_it_be(:user3) { create(:user) } + specify { expect(described_class).to require_graphql_authorizations(:update_user) } + describe '#resolve' do it 'marks all pending todos as done' do updated_todo_ids = mutation_for(current_user).resolve.dig(:updated_ids) diff --git a/spec/graphql/mutations/todos/mark_done_spec.rb b/spec/graphql/mutations/todos/mark_done_spec.rb index 059ef3c8eee..44065f83f74 100644 --- a/spec/graphql/mutations/todos/mark_done_spec.rb +++ b/spec/graphql/mutations/todos/mark_done_spec.rb @@ -16,6 +16,8 @@ describe Mutations::Todos::MarkDone do let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } + specify { expect(described_class).to require_graphql_authorizations(:update_todo) } + describe '#resolve' do it 'marks a single todo as done' do result = mark_done_mutation(todo1) diff --git a/spec/graphql/mutations/todos/restore_spec.rb b/spec/graphql/mutations/todos/restore_spec.rb index 1637acc2fb5..949ab6a164b 100644 --- a/spec/graphql/mutations/todos/restore_spec.rb +++ b/spec/graphql/mutations/todos/restore_spec.rb @@ -14,6 +14,8 @@ describe Mutations::Todos::Restore do let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } + specify { expect(described_class).to require_graphql_authorizations(:update_todo) } + describe '#resolve' do it 'restores a single todo' do result = restore_mutation(todo1) diff --git a/spec/graphql/resolvers/alert_management/alert_status_counts_resolver_spec.rb b/spec/graphql/resolvers/alert_management/alert_status_counts_resolver_spec.rb new file mode 100644 index 00000000000..8eb28c8c945 --- /dev/null +++ b/spec/graphql/resolvers/alert_management/alert_status_counts_resolver_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::AlertManagement::AlertStatusCountsResolver do + include GraphqlHelpers + + describe '#resolve' do + let_it_be(:current_user) { create(:user) } + let_it_be(:project) { create(:project) } + let(:args) { {} } + + subject { resolve_alert_status_counts(args) } + + it { is_expected.to be_a(Gitlab::AlertManagement::AlertStatusCounts) } + specify { expect(subject.project).to eq(project) } + + private + + def resolve_alert_status_counts(args = {}, context = { current_user: current_user }) + resolve(described_class, obj: project, args: args, ctx: context) + end + end +end diff --git a/spec/graphql/resolvers/alert_management_alert_resolver_spec.rb b/spec/graphql/resolvers/alert_management_alert_resolver_spec.rb new file mode 100644 index 00000000000..971a81a826d --- /dev/null +++ b/spec/graphql/resolvers/alert_management_alert_resolver_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::AlertManagementAlertResolver do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:alert_1) { create(:alert_management_alert, :resolved, project: project, ended_at: 1.year.ago, events: 2, severity: :high) } + let_it_be(:alert_2) { create(:alert_management_alert, :ignored, project: project, events: 1, severity: :critical) } + let_it_be(:alert_other_proj) { create(:alert_management_alert) } + + let(:args) { {} } + + subject { resolve_alerts(args) } + + context 'user does not have permission' do + it { is_expected.to eq(AlertManagement::Alert.none) } + end + + context 'user has permission' do + before do + project.add_developer(current_user) + end + + it { is_expected.to contain_exactly(alert_1, alert_2) } + + context 'finding by iid' do + let(:args) { { iid: alert_1.iid } } + + it { is_expected.to contain_exactly(alert_1) } + end + + context 'finding by status' do + let(:args) { { status: [Types::AlertManagement::StatusEnum.values['IGNORED'].value] } } + + it { is_expected.to contain_exactly(alert_2) } + end + + describe 'sorting' do + # Other sorting examples in spec/finders/alert_management/alerts_finder_spec.rb + context 'when sorting by events count' do + let_it_be(:alert_count_6) { create(:alert_management_alert, project: project, events: 6) } + let_it_be(:alert_count_3) { create(:alert_management_alert, project: project, events: 3) } + + it 'sorts alerts ascending' do + expect(resolve_alerts(sort: :events_count_asc)).to eq [alert_2, alert_1, alert_count_3, alert_count_6] + end + + it 'sorts alerts descending' do + expect(resolve_alerts(sort: :events_count_desc)).to eq [alert_count_6, alert_count_3, alert_1, alert_2] + end + end + end + end + + private + + def resolve_alerts(args = {}, context = { current_user: current_user }) + resolve(described_class, obj: project, args: args, ctx: context) + end +end diff --git a/spec/graphql/resolvers/board_lists_resolver_spec.rb b/spec/graphql/resolvers/board_lists_resolver_spec.rb new file mode 100644 index 00000000000..5f6c440a8ed --- /dev/null +++ b/spec/graphql/resolvers/board_lists_resolver_spec.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::BoardListsResolver do + include GraphqlHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:guest) { create(:user) } + let_it_be(:unauth_user) { create(:user) } + let_it_be(:project) { create(:project, creator_id: user.id, namespace: user.namespace ) } + let_it_be(:group) { create(:group, :private) } + let_it_be(:project_label) { create(:label, project: project, name: 'Development') } + let_it_be(:group_label) { create(:group_label, group: group, name: 'Development') } + + shared_examples_for 'group and project board lists resolver' do + let(:board) { create(:board, resource_parent: board_parent) } + + before do + board_parent.add_developer(user) + end + + it 'does not create the backlog list' do + lists = resolve_board_lists.items + + expect(lists.count).to eq 1 + expect(lists[0].list_type).to eq 'closed' + end + + context 'with unauthorized user' do + it 'raises an error' do + expect do + resolve_board_lists(current_user: unauth_user) + end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when authorized' do + let!(:label_list) { create(:list, board: board, label: label) } + let!(:backlog_list) { create(:backlog_list, board: board) } + + it 'returns a list of board lists' do + lists = resolve_board_lists.items + + expect(lists.count).to eq 3 + expect(lists.map(&:list_type)).to eq %w(backlog label closed) + end + + context 'when another user has list preferences' do + before do + board.lists.first.update_preferences_for(guest, collapsed: true) + end + + it 'returns the complete list of board lists for this user' do + lists = resolve_board_lists.items + + expect(lists.count).to eq 3 + end + end + end + end + + describe '#resolve' do + context 'when project boards' do + let(:board_parent) { project } + let(:label) { project_label } + + it_behaves_like 'group and project board lists resolver' + end + + context 'when group boards' do + let(:board_parent) { group } + let(:label) { group_label } + + it_behaves_like 'group and project board lists resolver' + end + end + + def resolve_board_lists(args: {}, current_user: user) + resolve(described_class, obj: board, args: args, ctx: { current_user: current_user }) + end +end diff --git a/spec/graphql/resolvers/branch_commit_resolver_spec.rb b/spec/graphql/resolvers/branch_commit_resolver_spec.rb new file mode 100644 index 00000000000..22e1de8f375 --- /dev/null +++ b/spec/graphql/resolvers/branch_commit_resolver_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::BranchCommitResolver do + include GraphqlHelpers + + subject(:commit) { resolve(described_class, obj: branch) } + + let_it_be(:repository) { create(:project, :repository).repository } + let(:branch) { repository.find_branch('master') } + + describe '#resolve' do + it 'resolves commit' do + is_expected.to eq(repository.commits('master', limit: 1).last) + end + + context 'when branch does not exist' do + let(:branch) { nil } + + it 'returns nil' do + is_expected.to be_nil + end + end + end +end diff --git a/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb new file mode 100644 index 00000000000..a5054ae3ebf --- /dev/null +++ b/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::DesignManagement::DesignAtVersionResolver do + include GraphqlHelpers + include DesignManagementTestHelpers + + let_it_be(:issue) { create(:issue) } + let_it_be(:project) { issue.project } + let_it_be(:user) { create(:user) } + let_it_be(:design_a) { create(:design, issue: issue) } + let_it_be(:version_a) { create(:design_version, issue: issue, created_designs: [design_a]) } + + let(:current_user) { user } + let(:object) { issue.design_collection } + let(:global_id) { GitlabSchema.id_from_object(design_at_version).to_s } + + let(:design_at_version) { ::DesignManagement::DesignAtVersion.new(design: design_a, version: version_a) } + + let(:resource_not_available) { ::Gitlab::Graphql::Errors::ResourceNotAvailable } + + before do + enable_design_management + project.add_developer(user) + end + + describe '#resolve' do + context 'when the user cannot see designs' do + let(:current_user) { create(:user) } + + it 'raises ResourceNotAvailable' do + expect { resolve_design }.to raise_error(resource_not_available) + end + end + + it 'returns the specified design' do + expect(resolve_design).to eq(design_at_version) + end + + context 'the ID belongs to a design on another issue' do + let(:other_dav) do + create(:design_at_version, issue: create(:issue, project: project)) + end + + let(:global_id) { global_id_of(other_dav) } + + it 'raises ResourceNotAvailable' do + expect { resolve_design }.to raise_error(resource_not_available) + end + + context 'the current object does not constrain the issue' do + let(:object) { nil } + + it 'returns the object' do + expect(resolve_design).to eq(other_dav) + end + end + end + end + + private + + def resolve_design + args = { id: global_id } + ctx = { current_user: current_user } + eager_resolve(described_class, obj: object, args: args, ctx: ctx) + end +end diff --git a/spec/graphql/resolvers/design_management/design_resolver_spec.rb b/spec/graphql/resolvers/design_management/design_resolver_spec.rb new file mode 100644 index 00000000000..857acc3d371 --- /dev/null +++ b/spec/graphql/resolvers/design_management/design_resolver_spec.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::DesignManagement::DesignResolver do + include GraphqlHelpers + include DesignManagementTestHelpers + + before do + enable_design_management + end + + describe '#resolve' do + let_it_be(:issue) { create(:issue) } + let_it_be(:project) { issue.project } + let_it_be(:first_version) { create(:design_version) } + let_it_be(:first_design) { create(:design, issue: issue, versions: [first_version]) } + let_it_be(:current_user) { create(:user) } + let_it_be(:design_on_other_issue) do + create(:design, issue: create(:issue, project: project), versions: [create(:design_version)]) + end + + let(:args) { { id: GitlabSchema.id_from_object(first_design).to_s } } + let(:gql_context) { { current_user: current_user } } + + before do + project.add_developer(current_user) + end + + context 'when the user cannot see designs' do + let(:gql_context) { { current_user: create(:user) } } + + it 'returns nothing' do + expect(resolve_design).to be_nil + end + end + + context 'when no argument has been passed' do + let(:args) { {} } + + it 'raises an error' do + expect { resolve_design }.to raise_error(::Gitlab::Graphql::Errors::ArgumentError, /must/) + end + end + + context 'when both arguments have been passed' do + let(:args) { { filename: first_design.filename, id: GitlabSchema.id_from_object(first_design).to_s } } + + it 'raises an error' do + expect { resolve_design }.to raise_error(::Gitlab::Graphql::Errors::ArgumentError, /may/) + end + end + + context 'by ID' do + it 'returns the specified design' do + expect(resolve_design).to eq(first_design) + end + + context 'the ID belongs to a design on another issue' do + let(:args) { { id: GitlabSchema.id_from_object(design_on_other_issue).to_s } } + + it 'returns nothing' do + expect(resolve_design).to be_nil + end + end + end + + context 'by filename' do + let(:args) { { filename: first_design.filename } } + + it 'returns the specified design' do + expect(resolve_design).to eq(first_design) + end + + context 'the filename belongs to a design on another issue' do + let(:args) { { filename: design_on_other_issue.filename } } + + it 'returns nothing' do + expect(resolve_design).to be_nil + end + end + end + end + + def resolve_design + resolve(described_class, obj: issue.design_collection, args: args, ctx: gql_context) + end +end diff --git a/spec/graphql/resolvers/design_management/designs_resolver_spec.rb b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb new file mode 100644 index 00000000000..28fc9e2151d --- /dev/null +++ b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::DesignManagement::DesignsResolver do + include GraphqlHelpers + include DesignManagementTestHelpers + + before do + enable_design_management + end + + describe '#resolve' do + let_it_be(:issue) { create(:issue) } + let_it_be(:project) { issue.project } + let_it_be(:first_version) { create(:design_version) } + let_it_be(:first_design) { create(:design, issue: issue, versions: [first_version]) } + let_it_be(:current_user) { create(:user) } + let(:gql_context) { { current_user: current_user } } + let(:args) { {} } + + before do + project.add_developer(current_user) + end + + context 'when the user cannot see designs' do + let(:gql_context) { { current_user: create(:user) } } + + it 'returns nothing' do + expect(resolve_designs).to be_empty + end + end + + context 'for a design collection' do + context 'which contains just a single design' do + it 'returns just that design' do + expect(resolve_designs).to contain_exactly(first_design) + end + end + + context 'which contains another design' do + it 'returns all designs' do + second_version = create(:design_version) + second_design = create(:design, issue: issue, versions: [second_version]) + + expect(resolve_designs).to contain_exactly(first_design, second_design) + end + end + end + + describe 'filtering' do + describe 'by filename' do + let(:second_version) { create(:design_version) } + let(:second_design) { create(:design, issue: issue, versions: [second_version]) } + let(:args) { { filenames: [second_design.filename] } } + + it 'resolves to just the relevant design, ignoring designs with the same filename on different issues' do + create(:design, issue: create(:issue, project: project), filename: second_design.filename) + + expect(resolve_designs).to contain_exactly(second_design) + end + end + + describe 'by id' do + let(:second_version) { create(:design_version) } + let(:second_design) { create(:design, issue: issue, versions: [second_version]) } + + context 'the ID is on the current issue' do + let(:args) { { ids: [GitlabSchema.id_from_object(second_design).to_s] } } + + it 'resolves to just the relevant design' do + expect(resolve_designs).to contain_exactly(second_design) + end + end + + context 'the ID is on a different issue' do + let(:third_version) { create(:design_version) } + let(:third_design) { create(:design, issue: create(:issue, project: project), versions: [third_version]) } + + let(:args) { { ids: [GitlabSchema.id_from_object(third_design).to_s] } } + + it 'ignores it' do + expect(resolve_designs).to be_empty + end + end + end + end + end + + def resolve_designs + resolve(described_class, obj: issue.design_collection, args: args, ctx: gql_context) + end +end diff --git a/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb new file mode 100644 index 00000000000..cc9c0436885 --- /dev/null +++ b/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::DesignManagement::Version::DesignAtVersionResolver do + include GraphqlHelpers + + include_context 'four designs in three versions' + + let(:current_user) { authorized_user } + let(:gql_context) { { current_user: current_user } } + + let(:version) { third_version } + let(:design) { design_a } + + let(:all_singular_args) do + { + design_at_version_id: global_id_of(dav(design)), + design_id: global_id_of(design), + filename: design.filename + } + end + + shared_examples 'a bad argument' do + let(:err_class) { ::Gitlab::Graphql::Errors::ArgumentError } + + it 'raises an appropriate error' do + expect { resolve_objects }.to raise_error(err_class) + end + end + + describe '#resolve' do + describe 'passing combinations of arguments' do + context 'passing no arguments' do + let(:args) { {} } + + it_behaves_like 'a bad argument' + end + + context 'passing all arguments' do + let(:args) { all_singular_args } + + it_behaves_like 'a bad argument' + end + + context 'passing any two arguments' do + let(:args) { all_singular_args.slice(*all_singular_args.keys.sample(2)) } + + it_behaves_like 'a bad argument' + end + end + + %i[design_at_version_id design_id filename].each do |arg| + describe "passing #{arg}" do + let(:args) { all_singular_args.slice(arg) } + + it 'finds the design' do + expect(resolve_objects).to eq(dav(design)) + end + + context 'when the user cannot see designs' do + let(:current_user) { create(:user) } + + it 'returns nothing' do + expect(resolve_objects).to be_nil + end + end + end + end + + describe 'attempting to retrieve an object not visible at this version' do + let(:design) { design_d } + + %i[design_at_version_id design_id filename].each do |arg| + describe "passing #{arg}" do + let(:args) { all_singular_args.slice(arg) } + + it 'does not find the design' do + expect(resolve_objects).to be_nil + end + end + end + end + end + + def resolve_objects + resolve(described_class, obj: version, args: args, ctx: gql_context) + end + + def dav(design) + build(:design_at_version, design: design, version: version) + end +end diff --git a/spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb new file mode 100644 index 00000000000..123b26862d0 --- /dev/null +++ b/spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::DesignManagement::Version::DesignsAtVersionResolver do + include GraphqlHelpers + + include_context 'four designs in three versions' + + let_it_be(:current_user) { authorized_user } + let(:gql_context) { { current_user: current_user } } + + let(:version) { third_version } + + describe '.single' do + let(:single) { ::Resolvers::DesignManagement::Version::DesignAtVersionResolver } + + it 'returns the single context resolver' do + expect(described_class.single).to eq(single) + end + end + + describe '#resolve' do + let(:args) { {} } + + context 'when the user cannot see designs' do + let(:current_user) { create(:user) } + + it 'returns nothing' do + expect(resolve_objects).to be_empty + end + end + + context 'for the current version' do + it 'returns all designs visible at that version' do + expect(resolve_objects).to contain_exactly(dav(design_a), dav(design_b), dav(design_c)) + end + end + + context 'for a previous version with more objects' do + let(:version) { second_version } + + it 'returns objects that were later deleted' do + expect(resolve_objects).to contain_exactly(dav(design_a), dav(design_b), dav(design_c), dav(design_d)) + end + end + + context 'for a previous version with fewer objects' do + let(:version) { first_version } + + it 'does not return objects that were later created' do + expect(resolve_objects).to contain_exactly(dav(design_a)) + end + end + + describe 'filtering' do + describe 'by filename' do + let(:red_herring) { create(:design, issue: create(:issue, project: project)) } + let(:args) { { filenames: [design_b.filename, red_herring.filename] } } + + it 'resolves to just the relevant design' do + create(:design, issue: create(:issue, project: project), filename: design_b.filename) + + expect(resolve_objects).to contain_exactly(dav(design_b)) + end + end + + describe 'by id' do + let(:red_herring) { create(:design, issue: create(:issue, project: project)) } + let(:args) { { ids: [design_a, red_herring].map { |x| global_id_of(x) } } } + + it 'resolves to just the relevant design, ignoring objects on other issues' do + expect(resolve_objects).to contain_exactly(dav(design_a)) + end + end + end + end + + def resolve_objects + resolve(described_class, obj: version, args: args, ctx: gql_context) + end + + def dav(design) + build(:design_at_version, design: design, version: version) + end +end diff --git a/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb b/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb new file mode 100644 index 00000000000..ef50598d241 --- /dev/null +++ b/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::DesignManagement::VersionInCollectionResolver do + include GraphqlHelpers + include DesignManagementTestHelpers + + let(:resolver) { described_class } + + describe '#resolve' do + let_it_be(:issue) { create(:issue) } + let_it_be(:current_user) { create(:user) } + let_it_be(:first_version) { create(:design_version, issue: issue) } + + let(:project) { issue.project } + let(:params) { {} } + + before do + enable_design_management + project.add_developer(current_user) + end + + let(:appropriate_error) { ::Gitlab::Graphql::Errors::ArgumentError } + + subject(:result) { resolve_version(issue.design_collection) } + + context 'Neither id nor sha is passed as parameters' do + it 'raises an appropriate error' do + expect { result }.to raise_error(appropriate_error) + end + end + + context 'we pass an id' do + let(:params) { { id: global_id_of(first_version) } } + + it { is_expected.to eq(first_version) } + end + + context 'we pass a sha' do + let(:params) { { sha: first_version.sha } } + + it { is_expected.to eq(first_version) } + end + + context 'we pass an inconsistent mixture of sha and version id' do + let(:params) { { sha: first_version.sha, id: global_id_of(create(:design_version)) } } + + it { is_expected.to be_nil } + end + + context 'we pass the id of something that is not a design_version' do + let(:params) { { id: global_id_of(project) } } + + it 'raises an appropriate error' do + expect { result }.to raise_error(appropriate_error) + end + end + end + + def resolve_version(obj, context = { current_user: current_user }) + resolve(resolver, obj: obj, args: params, ctx: context) + end +end diff --git a/spec/graphql/resolvers/design_management/version_resolver_spec.rb b/spec/graphql/resolvers/design_management/version_resolver_spec.rb new file mode 100644 index 00000000000..e7c09351204 --- /dev/null +++ b/spec/graphql/resolvers/design_management/version_resolver_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::DesignManagement::VersionResolver do + include GraphqlHelpers + include DesignManagementTestHelpers + + let_it_be(:issue) { create(:issue) } + let_it_be(:current_user) { create(:user) } + let_it_be(:version) { create(:design_version, issue: issue) } + let_it_be(:developer) { create(:user) } + + let(:project) { issue.project } + let(:params) { { id: global_id_of(version) } } + + before do + enable_design_management + project.add_developer(developer) + end + + context 'the current user is not authorized' do + let(:current_user) { create(:user) } + + it 'raises an error on resolution' do + expect { resolve_version }.to raise_error(::Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'the current user is authorized' do + let(:current_user) { developer } + + context 'the id parameter is provided' do + it 'returns the specified version' do + expect(resolve_version).to eq(version) + end + end + end + + def resolve_version + resolve(described_class, obj: nil, args: params, ctx: { current_user: current_user }) + end +end diff --git a/spec/graphql/resolvers/design_management/versions_resolver_spec.rb b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb new file mode 100644 index 00000000000..d5bab025e45 --- /dev/null +++ b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::DesignManagement::VersionsResolver do + include GraphqlHelpers + include DesignManagementTestHelpers + + describe '#resolve' do + let(:resolver) { described_class } + let_it_be(:issue) { create(:issue) } + let_it_be(:authorized_user) { create(:user) } + let_it_be(:first_version) { create(:design_version, issue: issue) } + let_it_be(:other_version) { create(:design_version, issue: issue) } + let_it_be(:first_design) { create(:design, issue: issue, versions: [first_version, other_version]) } + let_it_be(:other_design) { create(:design, :with_versions, issue: issue) } + + let(:project) { issue.project } + let(:params) { {} } + let(:current_user) { authorized_user } + let(:parent_args) { { irrelevant: 1.2 } } + let(:parent) { double('Parent', parent: nil, irep_node: double(arguments: parent_args)) } + + before do + enable_design_management + project.add_developer(authorized_user) + end + + shared_examples 'a source of versions' do + subject(:result) { resolve_versions(object) } + + let_it_be(:all_versions) { object.versions.ordered } + + context 'when the user is not authorized' do + let(:current_user) { create(:user) } + + it { is_expected.to be_empty } + end + + context 'without constraints' do + it 'returns the ordered versions' do + expect(result).to eq(all_versions) + end + end + + context 'when constrained' do + let_it_be(:matching) { all_versions.earlier_or_equal_to(first_version) } + + shared_examples 'a query for all_versions up to the first_version' do + it { is_expected.to eq(matching) } + end + + context 'by earlier_or_equal_to_id' do + let(:params) { { id: global_id_of(first_version) } } + + it_behaves_like 'a query for all_versions up to the first_version' + end + + context 'by earlier_or_equal_to_sha' do + let(:params) { { sha: first_version.sha } } + + it_behaves_like 'a query for all_versions up to the first_version' + end + + context 'by earlier_or_equal_to_sha AND earlier_or_equal_to_id' do + context 'and they match' do + # This usage is rather dumb, but so long as they match, this will + # return successfully + let(:params) do + { + sha: first_version.sha, + id: global_id_of(first_version) + } + end + + it_behaves_like 'a query for all_versions up to the first_version' + end + + context 'and they do not match' do + let(:params) do + { + sha: first_version.sha, + id: global_id_of(other_version) + } + end + + it 'raises a suitable error' do + expect { result }.to raise_error(GraphQL::ExecutionError) + end + end + end + + context 'by at_version in parent' do + let(:parent_args) { { atVersion: global_id_of(first_version) } } + + it_behaves_like 'a query for all_versions up to the first_version' + end + end + end + + describe 'a design collection' do + let_it_be(:object) { DesignManagement::DesignCollection.new(issue) } + + it_behaves_like 'a source of versions' + end + + describe 'a design' do + let_it_be(:object) { first_design } + + it_behaves_like 'a source of versions' + end + + def resolve_versions(obj, context = { current_user: current_user }) + eager_resolve(resolver, obj: obj, args: params.merge(parent: parent), ctx: context) + end + end +end diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb index 53e0a9e3724..b7cc9bc6d71 100644 --- a/spec/graphql/resolvers/issues_resolver_spec.rb +++ b/spec/graphql/resolvers/issues_resolver_spec.rb @@ -125,12 +125,11 @@ describe Resolvers::IssuesResolver do end context 'when sorting by due date' do - let(:project) { create(:project) } - - let!(:due_issue1) { create(:issue, project: project, due_date: 3.days.from_now) } - let!(:due_issue2) { create(:issue, project: project, due_date: nil) } - let!(:due_issue3) { create(:issue, project: project, due_date: 2.days.ago) } - let!(:due_issue4) { create(:issue, project: project, due_date: nil) } + let_it_be(:project) { create(:project) } + let_it_be(:due_issue1) { create(:issue, project: project, due_date: 3.days.from_now) } + let_it_be(:due_issue2) { create(:issue, project: project, due_date: nil) } + let_it_be(:due_issue3) { create(:issue, project: project, due_date: 2.days.ago) } + let_it_be(:due_issue4) { create(:issue, project: project, due_date: nil) } it 'sorts issues ascending' do expect(resolve_issues(sort: :due_date_asc)).to eq [due_issue3, due_issue1, due_issue4, due_issue2] @@ -142,17 +141,72 @@ describe Resolvers::IssuesResolver do end context 'when sorting by relative position' do - let(:project) { create(:project) } - - let!(:relative_issue1) { create(:issue, project: project, relative_position: 2000) } - let!(:relative_issue2) { create(:issue, project: project, relative_position: nil) } - let!(:relative_issue3) { create(:issue, project: project, relative_position: 1000) } - let!(:relative_issue4) { create(:issue, project: project, relative_position: nil) } + let_it_be(:project) { create(:project) } + let_it_be(:relative_issue1) { create(:issue, project: project, relative_position: 2000) } + let_it_be(:relative_issue2) { create(:issue, project: project, relative_position: nil) } + let_it_be(:relative_issue3) { create(:issue, project: project, relative_position: 1000) } + let_it_be(:relative_issue4) { create(:issue, project: project, relative_position: nil) } it 'sorts issues ascending' do expect(resolve_issues(sort: :relative_position_asc)).to eq [relative_issue3, relative_issue1, relative_issue4, relative_issue2] end end + + context 'when sorting by priority' do + let_it_be(:project) { create(:project) } + let_it_be(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) } + let_it_be(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) } + let_it_be(:priority_label1) { create(:label, project: project, priority: 1) } + let_it_be(:priority_label2) { create(:label, project: project, priority: 5) } + let_it_be(:priority_issue1) { create(:issue, project: project, labels: [priority_label1], milestone: late_milestone) } + let_it_be(:priority_issue2) { create(:issue, project: project, labels: [priority_label2]) } + let_it_be(:priority_issue3) { create(:issue, project: project, milestone: early_milestone) } + let_it_be(:priority_issue4) { create(:issue, project: project) } + + it 'sorts issues ascending' do + expect(resolve_issues(sort: :priority_asc).items).to eq([priority_issue3, priority_issue1, priority_issue2, priority_issue4]) + end + + it 'sorts issues descending' do + expect(resolve_issues(sort: :priority_desc).items).to eq([priority_issue1, priority_issue3, priority_issue2, priority_issue4]) + end + end + + context 'when sorting by label priority' do + let_it_be(:project) { create(:project) } + let_it_be(:label1) { create(:label, project: project, priority: 1) } + let_it_be(:label2) { create(:label, project: project, priority: 5) } + let_it_be(:label3) { create(:label, project: project, priority: 10) } + let_it_be(:label_issue1) { create(:issue, project: project, labels: [label1]) } + let_it_be(:label_issue2) { create(:issue, project: project, labels: [label2]) } + let_it_be(:label_issue3) { create(:issue, project: project, labels: [label1, label3]) } + let_it_be(:label_issue4) { create(:issue, project: project) } + + it 'sorts issues ascending' do + expect(resolve_issues(sort: :label_priority_asc).items).to eq([label_issue3, label_issue1, label_issue2, label_issue4]) + end + + it 'sorts issues descending' do + expect(resolve_issues(sort: :label_priority_desc).items).to eq([label_issue2, label_issue3, label_issue1, label_issue4]) + end + end + + context 'when sorting by milestone due date' do + let_it_be(:project) { create(:project) } + let_it_be(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) } + let_it_be(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) } + let_it_be(:milestone_issue1) { create(:issue, project: project) } + let_it_be(:milestone_issue2) { create(:issue, project: project, milestone: early_milestone) } + let_it_be(:milestone_issue3) { create(:issue, project: project, milestone: late_milestone) } + + it 'sorts issues ascending' do + expect(resolve_issues(sort: :milestone_due_asc).items).to eq([milestone_issue2, milestone_issue3, milestone_issue1]) + end + + it 'sorts issues descending' do + expect(resolve_issues(sort: :milestone_due_desc).items).to eq([milestone_issue3, milestone_issue2, milestone_issue1]) + end + end end it 'returns issues user can see' do diff --git a/spec/graphql/resolvers/milestone_resolver_spec.rb b/spec/graphql/resolvers/milestone_resolver_spec.rb index 297130c2027..8e2c67fdc03 100644 --- a/spec/graphql/resolvers/milestone_resolver_spec.rb +++ b/spec/graphql/resolvers/milestone_resolver_spec.rb @@ -8,14 +8,14 @@ describe Resolvers::MilestoneResolver do describe '#resolve' do let_it_be(:current_user) { create(:user) } + def resolve_group_milestones(args = {}, context = { current_user: current_user }) + resolve(described_class, obj: group, args: args, ctx: context) + end + context 'for group milestones' do let_it_be(:now) { Time.now } let_it_be(:group) { create(:group, :private) } - def resolve_group_milestones(args = {}, context = { current_user: current_user }) - resolve(described_class, obj: group, args: args, ctx: context) - end - before do group.add_developer(current_user) end @@ -89,5 +89,25 @@ describe Resolvers::MilestoneResolver do end end end + + context 'when including descendant milestones in a public group' do + let_it_be(:group) { create(:group, :public) } + let(:args) { { include_descendants: true } } + + it 'finds milestones only in accessible projects and groups' do + accessible_group = create(:group, :private, parent: group) + accessible_project = create(:project, group: accessible_group) + accessible_group.add_developer(current_user) + inaccessible_group = create(:group, :private, parent: group) + inaccessible_project = create(:project, :private, group: group) + milestone1 = create(:milestone, group: group) + milestone2 = create(:milestone, group: accessible_group) + milestone3 = create(:milestone, project: accessible_project) + create(:milestone, group: inaccessible_group) + create(:milestone, project: inaccessible_project) + + expect(resolve_group_milestones(args)).to match_array([milestone1, milestone2, milestone3]) + end + end end end diff --git a/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb index 47889126531..7146bfb441b 100644 --- a/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb +++ b/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb @@ -16,7 +16,7 @@ describe Resolvers::Projects::JiraImportsResolver do context 'when anonymous user' do let(:current_user) { nil } - it_behaves_like 'no jira import access' + it_behaves_like 'no Jira import access' end end @@ -25,7 +25,7 @@ describe Resolvers::Projects::JiraImportsResolver do project.add_guest(user) end - it_behaves_like 'no jira import data present' + it_behaves_like 'no Jira import data present' it 'does not raise access error' do expect do @@ -47,14 +47,14 @@ describe Resolvers::Projects::JiraImportsResolver do stub_feature_flags(jira_issue_import: false) end - it_behaves_like 'no jira import access' + it_behaves_like 'no Jira import access' end context 'when user cannot read Jira imports' do context 'when anonymous user' do let(:current_user) { nil } - it_behaves_like 'no jira import access' + it_behaves_like 'no Jira import access' end end diff --git a/spec/graphql/resolvers/projects_resolver_spec.rb b/spec/graphql/resolvers/projects_resolver_spec.rb new file mode 100644 index 00000000000..73ff99a2520 --- /dev/null +++ b/spec/graphql/resolvers/projects_resolver_spec.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::ProjectsResolver do + include GraphqlHelpers + + describe '#resolve' do + subject { resolve(described_class, obj: nil, args: filters, ctx: { current_user: current_user }) } + + let_it_be(:project) { create(:project, :public) } + let_it_be(:other_project) { create(:project, :public) } + let_it_be(:private_project) { create(:project, :private) } + let_it_be(:other_private_project) { create(:project, :private) } + + let_it_be(:user) { create(:user) } + + let(:filters) { {} } + + before_all do + project.add_developer(user) + private_project.add_developer(user) + end + + context 'when user is not logged in' do + let(:current_user) { nil } + + context 'when no filters are applied' do + it 'returns all public projects' do + is_expected.to contain_exactly(project, other_project) + end + + context 'when search filter is provided' do + let(:filters) { { search: project.name } } + + it 'returns matching project' do + is_expected.to contain_exactly(project) + end + end + + context 'when membership filter is provided' do + let(:filters) { { membership: true } } + + it 'returns empty list' do + is_expected.to be_empty + end + end + end + end + + context 'when user is logged in' do + let(:current_user) { user } + + context 'when no filters are applied' do + it 'returns all visible projects for the user' do + is_expected.to contain_exactly(project, other_project, private_project) + end + + context 'when search filter is provided' do + let(:filters) { { search: project.name } } + + it 'returns matching project' do + is_expected.to contain_exactly(project) + end + end + + context 'when membership filter is provided' do + let(:filters) { { membership: true } } + + it 'returns projects that user is member of' do + is_expected.to contain_exactly(project, private_project) + end + end + end + end + end +end diff --git a/spec/graphql/resolvers/release_resolver_spec.rb b/spec/graphql/resolvers/release_resolver_spec.rb new file mode 100644 index 00000000000..71aa4bbb439 --- /dev/null +++ b/spec/graphql/resolvers/release_resolver_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::ReleaseResolver do + include GraphqlHelpers + + let_it_be(:project) { create(:project, :private) } + let_it_be(:release) { create(:release, project: project) } + let_it_be(:developer) { create(:user) } + let_it_be(:public_user) { create(:user) } + + let(:args) { { tag_name: release.tag } } + + before do + project.add_developer(developer) + end + + describe '#resolve' do + context 'when the user does not have access to the project' do + let(:current_user) { public_user } + + it 'returns nil' do + expect(resolve_release).to be_nil + end + end + + context "when the user has full access to the project's releases" do + let(:current_user) { developer } + + it 'returns the release associated with the specified tag' do + expect(resolve_release).to eq(release) + end + + context 'when no tag_name argument was passed' do + let(:args) { {} } + + it 'raises an error' do + expect { resolve_release }.to raise_error(ArgumentError, "missing keyword: tag_name") + end + end + end + end + + private + + def resolve_release + context = { current_user: current_user } + resolve(described_class, obj: project, args: args, ctx: context) + end +end diff --git a/spec/graphql/resolvers/releases_resolver_spec.rb b/spec/graphql/resolvers/releases_resolver_spec.rb new file mode 100644 index 00000000000..9de539b417a --- /dev/null +++ b/spec/graphql/resolvers/releases_resolver_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::ReleasesResolver do + include GraphqlHelpers + + let_it_be(:project) { create(:project, :private) } + let_it_be(:release_v1) { create(:release, project: project, tag: 'v1.0.0') } + let_it_be(:release_v2) { create(:release, project: project, tag: 'v2.0.0') } + let_it_be(:developer) { create(:user) } + let_it_be(:public_user) { create(:user) } + + before do + project.add_developer(developer) + end + + describe '#resolve' do + context 'when the user does not have access to the project' do + let(:current_user) { public_user } + + it 'returns an empty array' do + expect(resolve_releases).to eq([]) + end + end + + context "when the user has full access to the project's releases" do + let(:current_user) { developer } + + it 'returns all releases associated to the project' do + expect(resolve_releases).to eq([release_v1, release_v2]) + end + end + end + + private + + def resolve_releases + context = { current_user: current_user } + resolve(described_class, obj: project, args: {}, ctx: context) + end +end diff --git a/spec/graphql/types/alert_management/alert_status_count_type_spec.rb b/spec/graphql/types/alert_management/alert_status_count_type_spec.rb new file mode 100644 index 00000000000..1c56028425e --- /dev/null +++ b/spec/graphql/types/alert_management/alert_status_count_type_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['AlertManagementAlertStatusCountsType'] do + specify { expect(described_class.graphql_name).to eq('AlertManagementAlertStatusCountsType') } + + it 'exposes the expected fields' do + expected_fields = %i[ + all + open + triggered + acknowledged + resolved + ignored + ] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/alert_management/alert_type_spec.rb b/spec/graphql/types/alert_management/alert_type_spec.rb new file mode 100644 index 00000000000..9c326f30e3c --- /dev/null +++ b/spec/graphql/types/alert_management/alert_type_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['AlertManagementAlert'] do + specify { expect(described_class.graphql_name).to eq('AlertManagementAlert') } + + specify { expect(described_class).to require_graphql_authorizations(:read_alert_management_alert) } + + it 'exposes the expected fields' do + expected_fields = %i[ + iid + issue_iid + title + description + severity + status + service + monitoring_tool + hosts + started_at + ended_at + event_count + details + created_at + updated_at + ] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/alert_management/severity_enum_spec.rb b/spec/graphql/types/alert_management/severity_enum_spec.rb new file mode 100644 index 00000000000..ca5aa826fe5 --- /dev/null +++ b/spec/graphql/types/alert_management/severity_enum_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['AlertManagementSeverity'] do + specify { expect(described_class.graphql_name).to eq('AlertManagementSeverity') } + + it 'exposes all the severity values' do + expect(described_class.values.keys).to include(*%w[CRITICAL HIGH MEDIUM LOW INFO UNKNOWN]) + end +end diff --git a/spec/graphql/types/alert_management/status_enum_spec.rb b/spec/graphql/types/alert_management/status_enum_spec.rb new file mode 100644 index 00000000000..240d8863c97 --- /dev/null +++ b/spec/graphql/types/alert_management/status_enum_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['AlertManagementStatus'] do + specify { expect(described_class.graphql_name).to eq('AlertManagementStatus') } + + describe 'statuses' do + using RSpec::Parameterized::TableSyntax + + where(:status_name, :status_value) do + 'TRIGGERED' | 0 + 'ACKNOWLEDGED' | 1 + 'RESOLVED' | 2 + 'IGNORED' | 3 + end + + with_them do + it 'exposes a status with the correct value' do + expect(described_class.values[status_name].value).to eq(status_value) + end + end + end +end diff --git a/spec/graphql/types/award_emojis/award_emoji_type_spec.rb b/spec/graphql/types/award_emojis/award_emoji_type_spec.rb index de5ece3b749..4e06329506d 100644 --- a/spec/graphql/types/award_emojis/award_emoji_type_spec.rb +++ b/spec/graphql/types/award_emojis/award_emoji_type_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe GitlabSchema.types['AwardEmoji'] do - it { expect(described_class.graphql_name).to eq('AwardEmoji') } + specify { expect(described_class.graphql_name).to eq('AwardEmoji') } - it { expect(described_class).to require_graphql_authorizations(:read_emoji) } + specify { expect(described_class).to require_graphql_authorizations(:read_emoji) } - it { expect(described_class).to have_graphql_fields(:description, :unicode_version, :emoji, :name, :unicode, :user) } + specify { expect(described_class).to have_graphql_fields(:description, :unicode_version, :emoji, :name, :unicode, :user) } end diff --git a/spec/graphql/types/blob_viewers/type_enum_spec.rb b/spec/graphql/types/blob_viewers/type_enum_spec.rb index 7bd4352f388..09664382af9 100644 --- a/spec/graphql/types/blob_viewers/type_enum_spec.rb +++ b/spec/graphql/types/blob_viewers/type_enum_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Types::BlobViewers::TypeEnum do - it { expect(described_class.graphql_name).to eq('BlobViewersType') } + specify { expect(described_class.graphql_name).to eq('BlobViewersType') } it 'exposes all tree entry types' do expect(described_class.values.keys).to include(*%w[rich simple auxiliary]) diff --git a/spec/graphql/types/board_list_type_spec.rb b/spec/graphql/types/board_list_type_spec.rb new file mode 100644 index 00000000000..69597fc9617 --- /dev/null +++ b/spec/graphql/types/board_list_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['BoardList'] do + specify { expect(described_class.graphql_name).to eq('BoardList') } + + it 'has specific fields' do + expected_fields = %w[id list_type position label] + + expect(described_class).to include_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/board_type_spec.rb b/spec/graphql/types/board_type_spec.rb index 1ca4bf18b57..5d87a1757b5 100644 --- a/spec/graphql/types/board_type_spec.rb +++ b/spec/graphql/types/board_type_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe GitlabSchema.types['Board'] do - it { expect(described_class.graphql_name).to eq('Board') } + specify { expect(described_class.graphql_name).to eq('Board') } - it { expect(described_class).to require_graphql_authorizations(:read_board) } + specify { expect(described_class).to require_graphql_authorizations(:read_board) } it 'has specific fields' do expected_fields = %w[id name] diff --git a/spec/graphql/types/branch_type_spec.rb b/spec/graphql/types/branch_type_spec.rb new file mode 100644 index 00000000000..f58b514116d --- /dev/null +++ b/spec/graphql/types/branch_type_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['Branch'] do + it { expect(described_class.graphql_name).to eq('Branch') } + + it { expect(described_class).to have_graphql_fields(:name, :commit) } +end diff --git a/spec/graphql/types/ci/detailed_status_type_spec.rb b/spec/graphql/types/ci/detailed_status_type_spec.rb index 169a03c770b..c62c8f23728 100644 --- a/spec/graphql/types/ci/detailed_status_type_spec.rb +++ b/spec/graphql/types/ci/detailed_status_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Types::Ci::DetailedStatusType do - it { expect(described_class.graphql_name).to eq('DetailedStatus') } + specify { expect(described_class.graphql_name).to eq('DetailedStatus') } it "has all fields" do expect(described_class).to have_graphql_fields(:group, :icon, :favicon, diff --git a/spec/graphql/types/ci/pipeline_type_spec.rb b/spec/graphql/types/ci/pipeline_type_spec.rb index 2fafc1bc13f..d56cff12105 100644 --- a/spec/graphql/types/ci/pipeline_type_spec.rb +++ b/spec/graphql/types/ci/pipeline_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Types::Ci::PipelineType do - it { expect(described_class.graphql_name).to eq('Pipeline') } + specify { expect(described_class.graphql_name).to eq('Pipeline') } - it { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Ci::Pipeline) } + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Ci::Pipeline) } end diff --git a/spec/graphql/types/commit_type_spec.rb b/spec/graphql/types/commit_type_spec.rb index f5f99229f3a..88b450e3924 100644 --- a/spec/graphql/types/commit_type_spec.rb +++ b/spec/graphql/types/commit_type_spec.rb @@ -3,13 +3,13 @@ require 'spec_helper' describe GitlabSchema.types['Commit'] do - it { expect(described_class.graphql_name).to eq('Commit') } + specify { expect(described_class.graphql_name).to eq('Commit') } - it { expect(described_class).to require_graphql_authorizations(:download_code) } + specify { expect(described_class).to require_graphql_authorizations(:download_code) } it 'contains attributes related to commit' do expect(described_class).to have_graphql_fields( - :id, :sha, :title, :description, :message, :authored_date, + :id, :sha, :title, :description, :message, :title_html, :authored_date, :author_name, :author_gravatar, :author, :web_url, :latest_pipeline, :pipelines, :signature_html ) diff --git a/spec/graphql/types/design_management/design_at_version_type_spec.rb b/spec/graphql/types/design_management/design_at_version_type_spec.rb new file mode 100644 index 00000000000..1453d73d59c --- /dev/null +++ b/spec/graphql/types/design_management/design_at_version_type_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['DesignAtVersion'] do + it_behaves_like 'a GraphQL type with design fields' do + let(:extra_design_fields) { %i[version design] } + let_it_be(:design) { create(:design, :with_versions) } + let(:object_id) do + version = design.versions.first + GitlabSchema.id_from_object(create(:design_at_version, design: design, version: version)) + end + let_it_be(:object_id_b) { GitlabSchema.id_from_object(create(:design_at_version)) } + let(:object_type) { ::Types::DesignManagement::DesignAtVersionType } + end +end diff --git a/spec/graphql/types/design_management/design_collection_type_spec.rb b/spec/graphql/types/design_management/design_collection_type_spec.rb new file mode 100644 index 00000000000..65150f0971d --- /dev/null +++ b/spec/graphql/types/design_management/design_collection_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['DesignCollection'] do + it { expect(described_class).to require_graphql_authorizations(:read_design) } + + it 'has the expected fields' do + expected_fields = %i[project issue designs versions version designAtVersion design] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/design_management/design_type_spec.rb b/spec/graphql/types/design_management/design_type_spec.rb new file mode 100644 index 00000000000..75b4cd66d5e --- /dev/null +++ b/spec/graphql/types/design_management/design_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['Design'] do + it_behaves_like 'a GraphQL type with design fields' do + let(:extra_design_fields) { %i[notes discussions versions] } + let_it_be(:design) { create(:design, :with_versions) } + let(:object_id) { GitlabSchema.id_from_object(design) } + let_it_be(:object_id_b) { GitlabSchema.id_from_object(create(:design, :with_versions)) } + let(:object_type) { ::Types::DesignManagement::DesignType } + end +end diff --git a/spec/graphql/types/design_management/design_version_event_enum_spec.rb b/spec/graphql/types/design_management/design_version_event_enum_spec.rb new file mode 100644 index 00000000000..a65f1bb5990 --- /dev/null +++ b/spec/graphql/types/design_management/design_version_event_enum_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['DesignVersionEvent'] do + it { expect(described_class.graphql_name).to eq('DesignVersionEvent') } + + it 'exposes the correct event states' do + expect(described_class.values.keys).to include(*%w[CREATION MODIFICATION DELETION NONE]) + end +end diff --git a/spec/graphql/types/design_management/version_type_spec.rb b/spec/graphql/types/design_management/version_type_spec.rb new file mode 100644 index 00000000000..3317c4c6571 --- /dev/null +++ b/spec/graphql/types/design_management/version_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['DesignVersion'] do + it { expect(described_class).to require_graphql_authorizations(:read_design) } + + it 'has the expected fields' do + expected_fields = %i[id sha designs design_at_version designs_at_version] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/design_management_type_spec.rb b/spec/graphql/types/design_management_type_spec.rb new file mode 100644 index 00000000000..a6204f20f23 --- /dev/null +++ b/spec/graphql/types/design_management_type_spec.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['DesignManagement'] do + it { expect(described_class).to have_graphql_fields(:version, :design_at_version) } +end diff --git a/spec/graphql/types/diff_refs_type_spec.rb b/spec/graphql/types/diff_refs_type_spec.rb index a6ead27455f..3165e642452 100644 --- a/spec/graphql/types/diff_refs_type_spec.rb +++ b/spec/graphql/types/diff_refs_type_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe GitlabSchema.types['DiffRefs'] do - it { expect(described_class.graphql_name).to eq('DiffRefs') } + specify { expect(described_class.graphql_name).to eq('DiffRefs') } - it { expect(described_class).to have_graphql_fields(:head_sha, :base_sha, :start_sha).only } + specify { expect(described_class).to have_graphql_fields(:head_sha, :base_sha, :start_sha).only } - it { expect(described_class.fields['headSha'].type).to be_non_null } - it { expect(described_class.fields['baseSha'].type).not_to be_non_null } - it { expect(described_class.fields['startSha'].type).to be_non_null } + specify { expect(described_class.fields['headSha'].type).to be_non_null } + specify { expect(described_class.fields['baseSha'].type).not_to be_non_null } + specify { expect(described_class.fields['startSha'].type).to be_non_null } end diff --git a/spec/graphql/types/environment_type_spec.rb b/spec/graphql/types/environment_type_spec.rb index 24a8bddfa6a..0e5cbac05df 100644 --- a/spec/graphql/types/environment_type_spec.rb +++ b/spec/graphql/types/environment_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['Environment'] do - it { expect(described_class.graphql_name).to eq('Environment') } + specify { expect(described_class.graphql_name).to eq('Environment') } it 'has the expected fields' do expected_fields = %w[ @@ -13,5 +13,5 @@ describe GitlabSchema.types['Environment'] do expect(described_class).to have_graphql_fields(*expected_fields) end - it { expect(described_class).to require_graphql_authorizations(:read_environment) } + specify { expect(described_class).to require_graphql_authorizations(:read_environment) } end diff --git a/spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb b/spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb index 44652f831b5..0a094e9e188 100644 --- a/spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb +++ b/spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe GitlabSchema.types['SentryDetailedError'] do - it { expect(described_class.graphql_name).to eq('SentryDetailedError') } + specify { expect(described_class.graphql_name).to eq('SentryDetailedError') } - it { expect(described_class).to require_graphql_authorizations(:read_sentry_issue) } + specify { expect(described_class).to require_graphql_authorizations(:read_sentry_issue) } it 'exposes the expected fields' do expected_fields = %i[ diff --git a/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb index 20ec31391d8..793da2db960 100644 --- a/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb +++ b/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe GitlabSchema.types['SentryErrorCollection'] do - it { expect(described_class.graphql_name).to eq('SentryErrorCollection') } + specify { expect(described_class.graphql_name).to eq('SentryErrorCollection') } - it { expect(described_class).to require_graphql_authorizations(:read_sentry_issue) } + specify { expect(described_class).to require_graphql_authorizations(:read_sentry_issue) } it 'exposes the expected fields' do expected_fields = %i[ diff --git a/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb index 05cc2ca7612..b65398fccc9 100644 --- a/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb +++ b/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['SentryErrorStackTraceEntry'] do - it { expect(described_class.graphql_name).to eq('SentryErrorStackTraceEntry') } + specify { expect(described_class.graphql_name).to eq('SentryErrorStackTraceEntry') } it 'exposes the expected fields' do expected_fields = %i[ diff --git a/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb index 2a422228f72..2cec8865764 100644 --- a/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb +++ b/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe GitlabSchema.types['SentryErrorStackTrace'] do - it { expect(described_class.graphql_name).to eq('SentryErrorStackTrace') } + specify { expect(described_class.graphql_name).to eq('SentryErrorStackTrace') } - it { expect(described_class).to require_graphql_authorizations(:read_sentry_issue) } + specify { expect(described_class).to require_graphql_authorizations(:read_sentry_issue) } it 'exposes the expected fields' do expected_fields = %i[ diff --git a/spec/graphql/types/error_tracking/sentry_error_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_type_spec.rb index 4676d91ef9c..f8cc801e35e 100644 --- a/spec/graphql/types/error_tracking/sentry_error_type_spec.rb +++ b/spec/graphql/types/error_tracking/sentry_error_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['SentryError'] do - it { expect(described_class.graphql_name).to eq('SentryError') } + specify { expect(described_class.graphql_name).to eq('SentryError') } it 'exposes the expected fields' do expected_fields = %i[ diff --git a/spec/graphql/types/grafana_integration_type_spec.rb b/spec/graphql/types/grafana_integration_type_spec.rb index ac26911acbf..429b5bdffe6 100644 --- a/spec/graphql/types/grafana_integration_type_spec.rb +++ b/spec/graphql/types/grafana_integration_type_spec.rb @@ -14,9 +14,9 @@ describe GitlabSchema.types['GrafanaIntegration'] do ] end - it { expect(described_class.graphql_name).to eq('GrafanaIntegration') } + specify { expect(described_class.graphql_name).to eq('GrafanaIntegration') } - it { expect(described_class).to require_graphql_authorizations(:admin_operations) } + specify { expect(described_class).to require_graphql_authorizations(:admin_operations) } - it { expect(described_class).to have_graphql_fields(*expected_fields) } + specify { expect(described_class).to have_graphql_fields(*expected_fields) } end diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb index 532f1a4b53d..a834a9038db 100644 --- a/spec/graphql/types/group_type_spec.rb +++ b/spec/graphql/types/group_type_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe GitlabSchema.types['Group'] do - it { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Group) } + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Group) } - it { expect(described_class.graphql_name).to eq('Group') } + specify { expect(described_class.graphql_name).to eq('Group') } - it { expect(described_class).to require_graphql_authorizations(:read_group) } + specify { expect(described_class).to require_graphql_authorizations(:read_group) } it 'has the expected fields' do expected_fields = %w[ diff --git a/spec/graphql/types/issuable_sort_enum_spec.rb b/spec/graphql/types/issuable_sort_enum_spec.rb new file mode 100644 index 00000000000..35c42d8194c --- /dev/null +++ b/spec/graphql/types/issuable_sort_enum_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Types::IssuableSortEnum do + specify { expect(described_class.graphql_name).to eq('IssuableSort') } + + it 'exposes all the existing issuable sort values' do + expect(described_class.values.keys).to include( + *%w[PRIORITY_ASC PRIORITY_DESC + LABEL_PRIORITY_ASC LABEL_PRIORITY_DESC + MILESTONE_DUE_ASC MILESTONE_DUE_DESC] + ) + end +end diff --git a/spec/graphql/types/issuable_state_enum_spec.rb b/spec/graphql/types/issuable_state_enum_spec.rb index 65a80fa4176..f974ed5f5fb 100644 --- a/spec/graphql/types/issuable_state_enum_spec.rb +++ b/spec/graphql/types/issuable_state_enum_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['IssuableState'] do - it { expect(described_class.graphql_name).to eq('IssuableState') } + specify { expect(described_class.graphql_name).to eq('IssuableState') } it_behaves_like 'issuable state' end diff --git a/spec/graphql/types/issue_sort_enum_spec.rb b/spec/graphql/types/issue_sort_enum_spec.rb index 1b6aa6d6069..c496b897cdb 100644 --- a/spec/graphql/types/issue_sort_enum_spec.rb +++ b/spec/graphql/types/issue_sort_enum_spec.rb @@ -3,11 +3,13 @@ require 'spec_helper' describe GitlabSchema.types['IssueSort'] do - it { expect(described_class.graphql_name).to eq('IssueSort') } + specify { expect(described_class.graphql_name).to eq('IssueSort') } it_behaves_like 'common sort values' it 'exposes all the existing issue sort values' do - expect(described_class.values.keys).to include(*%w[DUE_DATE_ASC DUE_DATE_DESC RELATIVE_POSITION_ASC]) + expect(described_class.values.keys).to include( + *%w[DUE_DATE_ASC DUE_DATE_DESC RELATIVE_POSITION_ASC] + ) end end diff --git a/spec/graphql/types/issue_state_enum_spec.rb b/spec/graphql/types/issue_state_enum_spec.rb index de19e6fc505..a18c5f5d317 100644 --- a/spec/graphql/types/issue_state_enum_spec.rb +++ b/spec/graphql/types/issue_state_enum_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['IssueState'] do - it { expect(described_class.graphql_name).to eq('IssueState') } + specify { expect(described_class.graphql_name).to eq('IssueState') } it_behaves_like 'issuable state' end diff --git a/spec/graphql/types/issue_type_spec.rb b/spec/graphql/types/issue_type_spec.rb index ebe48c17c11..a8f7edcfe8e 100644 --- a/spec/graphql/types/issue_type_spec.rb +++ b/spec/graphql/types/issue_type_spec.rb @@ -3,18 +3,19 @@ require 'spec_helper' describe GitlabSchema.types['Issue'] do - it { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Issue) } + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Issue) } - it { expect(described_class.graphql_name).to eq('Issue') } + specify { expect(described_class.graphql_name).to eq('Issue') } - it { expect(described_class).to require_graphql_authorizations(:read_issue) } + specify { expect(described_class).to require_graphql_authorizations(:read_issue) } - it { expect(described_class.interfaces).to include(Types::Notes::NoteableType) } + specify { expect(described_class.interfaces).to include(Types::Notes::NoteableType) } it 'has specific fields' do fields = %i[iid title description state reference author assignees participants labels milestone due_date confidential discussion_locked upvotes downvotes user_notes_count web_path web_url relative_position - subscribed time_estimate total_time_spent closed_at created_at updated_at task_completion_status] + subscribed time_estimate total_time_spent closed_at created_at updated_at task_completion_status + designs design_collection] fields.each do |field_name| expect(described_class).to have_graphql_field(field_name) diff --git a/spec/graphql/types/jira_import_type_spec.rb b/spec/graphql/types/jira_import_type_spec.rb index 8448a120682..ac1aa672e30 100644 --- a/spec/graphql/types/jira_import_type_spec.rb +++ b/spec/graphql/types/jira_import_type_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe GitlabSchema.types['JiraImport'] do - it { expect(described_class.graphql_name).to eq('JiraImport') } + specify { expect(described_class.graphql_name).to eq('JiraImport') } it 'has the expected fields' do - expect(described_class).to have_graphql_fields(:jira_project_key, :scheduled_at, :scheduled_by) + expect(described_class).to have_graphql_fields(:jira_project_key, :createdAt, :scheduled_at, :scheduled_by) end end diff --git a/spec/graphql/types/label_type_spec.rb b/spec/graphql/types/label_type_spec.rb index 71b86d9b528..026c63906ef 100644 --- a/spec/graphql/types/label_type_spec.rb +++ b/spec/graphql/types/label_type_spec.rb @@ -8,5 +8,5 @@ describe GitlabSchema.types['Label'] do expect(described_class).to have_graphql_fields(*expected_fields) end - it { expect(described_class).to require_graphql_authorizations(:read_label) } + specify { expect(described_class).to require_graphql_authorizations(:read_label) } end diff --git a/spec/graphql/types/merge_request_state_enum_spec.rb b/spec/graphql/types/merge_request_state_enum_spec.rb index 626e33b18d3..2abc7b298b1 100644 --- a/spec/graphql/types/merge_request_state_enum_spec.rb +++ b/spec/graphql/types/merge_request_state_enum_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['MergeRequestState'] do - it { expect(described_class.graphql_name).to eq('MergeRequestState') } + specify { expect(described_class.graphql_name).to eq('MergeRequestState') } it_behaves_like 'issuable state' diff --git a/spec/graphql/types/merge_request_type_spec.rb b/spec/graphql/types/merge_request_type_spec.rb index 0c83ebd3de9..e7ab2100084 100644 --- a/spec/graphql/types/merge_request_type_spec.rb +++ b/spec/graphql/types/merge_request_type_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe GitlabSchema.types['MergeRequest'] do - it { expect(described_class).to expose_permissions_using(Types::PermissionTypes::MergeRequest) } + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::MergeRequest) } - it { expect(described_class).to require_graphql_authorizations(:read_merge_request) } + specify { expect(described_class).to require_graphql_authorizations(:read_merge_request) } - it { expect(described_class.interfaces).to include(Types::Notes::NoteableType) } + specify { expect(described_class.interfaces).to include(Types::Notes::NoteableType) } it 'has the expected fields' do expected_fields = %w[ diff --git a/spec/graphql/types/metadata_type_spec.rb b/spec/graphql/types/metadata_type_spec.rb index c8270a8c2f5..75369ec9c3c 100644 --- a/spec/graphql/types/metadata_type_spec.rb +++ b/spec/graphql/types/metadata_type_spec.rb @@ -3,6 +3,6 @@ require 'spec_helper' describe GitlabSchema.types['Metadata'] do - it { expect(described_class.graphql_name).to eq('Metadata') } - it { expect(described_class).to require_graphql_authorizations(:read_instance_metadata) } + specify { expect(described_class.graphql_name).to eq('Metadata') } + specify { expect(described_class).to require_graphql_authorizations(:read_instance_metadata) } end diff --git a/spec/graphql/types/metrics/dashboard_type_spec.rb b/spec/graphql/types/metrics/dashboard_type_spec.rb index 76f2b4b8935..81219c596a7 100644 --- a/spec/graphql/types/metrics/dashboard_type_spec.rb +++ b/spec/graphql/types/metrics/dashboard_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['MetricsDashboard'] do - it { expect(described_class.graphql_name).to eq('MetricsDashboard') } + specify { expect(described_class.graphql_name).to eq('MetricsDashboard') } it 'has the expected fields' do expected_fields = %w[ diff --git a/spec/graphql/types/metrics/dashboards/annotation_type_spec.rb b/spec/graphql/types/metrics/dashboards/annotation_type_spec.rb index 2956a2512eb..dbb8b04dbd7 100644 --- a/spec/graphql/types/metrics/dashboards/annotation_type_spec.rb +++ b/spec/graphql/types/metrics/dashboards/annotation_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['MetricsDashboardAnnotation'] do - it { expect(described_class.graphql_name).to eq('MetricsDashboardAnnotation') } + specify { expect(described_class.graphql_name).to eq('MetricsDashboardAnnotation') } it 'has the expected fields' do expected_fields = %w[ @@ -13,5 +13,5 @@ describe GitlabSchema.types['MetricsDashboardAnnotation'] do expect(described_class).to have_graphql_fields(*expected_fields) end - it { expect(described_class).to require_graphql_authorizations(:read_metrics_dashboard_annotation) } + specify { expect(described_class).to require_graphql_authorizations(:read_metrics_dashboard_annotation) } end diff --git a/spec/graphql/types/milestone_type_spec.rb b/spec/graphql/types/milestone_type_spec.rb index f7ee79eae9f..4c3d9f50a64 100644 --- a/spec/graphql/types/milestone_type_spec.rb +++ b/spec/graphql/types/milestone_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['Milestone'] do - it { expect(described_class.graphql_name).to eq('Milestone') } + specify { expect(described_class.graphql_name).to eq('Milestone') } - it { expect(described_class).to require_graphql_authorizations(:read_milestone) } + specify { expect(described_class).to require_graphql_authorizations(:read_milestone) } end diff --git a/spec/graphql/types/namespace_type_spec.rb b/spec/graphql/types/namespace_type_spec.rb index 6c2ba70cf4c..741698021e7 100644 --- a/spec/graphql/types/namespace_type_spec.rb +++ b/spec/graphql/types/namespace_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['Namespace'] do - it { expect(described_class.graphql_name).to eq('Namespace') } + specify { expect(described_class.graphql_name).to eq('Namespace') } it 'has the expected fields' do expected_fields = %w[ @@ -14,5 +14,5 @@ describe GitlabSchema.types['Namespace'] do expect(described_class).to have_graphql_fields(*expected_fields) end - it { expect(described_class).to require_graphql_authorizations(:read_namespace) } + specify { expect(described_class).to require_graphql_authorizations(:read_namespace) } end diff --git a/spec/graphql/types/notes/discussion_type_spec.rb b/spec/graphql/types/notes/discussion_type_spec.rb index 804785ba67d..44774594d17 100644 --- a/spec/graphql/types/notes/discussion_type_spec.rb +++ b/spec/graphql/types/notes/discussion_type_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe GitlabSchema.types['Discussion'] do - it { expect(described_class).to have_graphql_fields(:id, :created_at, :notes, :reply_id) } + specify { expect(described_class).to have_graphql_fields(:id, :created_at, :notes, :reply_id) } - it { expect(described_class).to require_graphql_authorizations(:read_note) } + specify { expect(described_class).to require_graphql_authorizations(:read_note) } end diff --git a/spec/graphql/types/notes/note_type_spec.rb b/spec/graphql/types/notes/note_type_spec.rb index 8cf84cd8dfd..019f742ee77 100644 --- a/spec/graphql/types/notes/note_type_spec.rb +++ b/spec/graphql/types/notes/note_type_spec.rb @@ -10,6 +10,6 @@ describe GitlabSchema.types['Note'] do expect(described_class).to have_graphql_fields(*expected_fields) end - it { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Note) } - it { expect(described_class).to require_graphql_authorizations(:read_note) } + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Note) } + specify { expect(described_class).to require_graphql_authorizations(:read_note) } end diff --git a/spec/graphql/types/notes/noteable_type_spec.rb b/spec/graphql/types/notes/noteable_type_spec.rb index a4259e160e0..4a81f45bd4e 100644 --- a/spec/graphql/types/notes/noteable_type_spec.rb +++ b/spec/graphql/types/notes/noteable_type_spec.rb @@ -2,12 +2,13 @@ require 'spec_helper' describe Types::Notes::NoteableType do - it { expect(described_class).to have_graphql_fields(:notes, :discussions) } + specify { expect(described_class).to have_graphql_fields(:notes, :discussions) } describe ".resolve_type" do it 'knows the correct type for objects' do expect(described_class.resolve_type(build(:issue), {})).to eq(Types::IssueType) expect(described_class.resolve_type(build(:merge_request), {})).to eq(Types::MergeRequestType) + expect(described_class.resolve_type(build(:design), {})).to eq(Types::DesignManagement::DesignType) end end end diff --git a/spec/graphql/types/permission_types/issue_spec.rb b/spec/graphql/types/permission_types/issue_spec.rb index a94bc6b780e..a7a3dd00f11 100644 --- a/spec/graphql/types/permission_types/issue_spec.rb +++ b/spec/graphql/types/permission_types/issue_spec.rb @@ -5,8 +5,9 @@ require 'spec_helper' describe Types::PermissionTypes::Issue do it do expected_permissions = [ - :read_issue, :admin_issue, :update_issue, - :create_note, :reopen_issue + :read_issue, :admin_issue, :update_issue, :reopen_issue, + :read_design, :create_design, :destroy_design, + :create_note ] expected_permissions.each do |permission| diff --git a/spec/graphql/types/permission_types/merge_request_type_spec.rb b/spec/graphql/types/permission_types/merge_request_type_spec.rb index 572b4ac42d0..7e9752cdc46 100644 --- a/spec/graphql/types/permission_types/merge_request_type_spec.rb +++ b/spec/graphql/types/permission_types/merge_request_type_spec.rb @@ -3,5 +3,5 @@ require 'spec_helper' describe Types::MergeRequestType do - it { expect(described_class).to expose_permissions_using(Types::PermissionTypes::MergeRequest) } + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::MergeRequest) } end diff --git a/spec/graphql/types/permission_types/project_spec.rb b/spec/graphql/types/permission_types/project_spec.rb index 56c4c2de4df..2789464d29c 100644 --- a/spec/graphql/types/permission_types/project_spec.rb +++ b/spec/graphql/types/permission_types/project_spec.rb @@ -13,7 +13,7 @@ describe Types::PermissionTypes::Project do :create_merge_request_from, :create_wiki, :push_code, :create_deployment, :push_to_delete_protected_branch, :admin_wiki, :admin_project, :update_pages, :admin_remote_mirror, :create_label, :update_wiki, :destroy_wiki, :create_pages, :destroy_pages, :read_pages_content, - :read_merge_request + :read_merge_request, :read_design, :create_design, :destroy_design ] expected_permissions.each do |permission| diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index 6ea852190c9..6368f743720 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe GitlabSchema.types['Project'] do - it { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Project) } + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Project) } - it { expect(described_class.graphql_name).to eq('Project') } + specify { expect(described_class.graphql_name).to eq('Project') } - it { expect(described_class).to require_graphql_authorizations(:read_project) } + specify { expect(described_class).to require_graphql_authorizations(:read_project) } it 'has the expected fields' do expected_fields = %w[ @@ -24,7 +24,8 @@ describe GitlabSchema.types['Project'] do namespace group statistics repository merge_requests merge_request issues issue pipelines removeSourceBranchAfterMerge sentryDetailedError snippets grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments - boards jira_import_status jira_imports services + boards jira_import_status jira_imports services releases release + alert_management_alerts alert_management_alert alert_management_alert_status_counts ] expect(described_class).to include_graphql_fields(*expected_fields) @@ -96,4 +97,18 @@ describe GitlabSchema.types['Project'] do it { is_expected.to have_graphql_type(Types::Projects::ServiceType.connection_type) } end + + describe 'releases field' do + subject { described_class.fields['release'] } + + it { is_expected.to have_graphql_type(Types::ReleaseType) } + it { is_expected.to have_graphql_resolver(Resolvers::ReleaseResolver) } + end + + describe 'release field' do + subject { described_class.fields['releases'] } + + it { is_expected.to have_graphql_type(Types::ReleaseType.connection_type) } + it { is_expected.to have_graphql_resolver(Resolvers::ReleasesResolver) } + end end diff --git a/spec/graphql/types/projects/base_service_type_spec.rb b/spec/graphql/types/projects/base_service_type_spec.rb index bda6022bf79..4fcb9fe1a73 100644 --- a/spec/graphql/types/projects/base_service_type_spec.rb +++ b/spec/graphql/types/projects/base_service_type_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe GitlabSchema.types['BaseService'] do - it { expect(described_class.graphql_name).to eq('BaseService') } + specify { expect(described_class.graphql_name).to eq('BaseService') } it 'has basic expected fields' do expect(described_class).to have_graphql_fields(:type, :active) end - it { expect(described_class).to require_graphql_authorizations(:admin_project) } + specify { expect(described_class).to require_graphql_authorizations(:admin_project) } end diff --git a/spec/graphql/types/projects/jira_service_type_spec.rb b/spec/graphql/types/projects/jira_service_type_spec.rb index 7f8fa6538e9..91d7e4586cb 100644 --- a/spec/graphql/types/projects/jira_service_type_spec.rb +++ b/spec/graphql/types/projects/jira_service_type_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe GitlabSchema.types['JiraService'] do - it { expect(described_class.graphql_name).to eq('JiraService') } + specify { expect(described_class.graphql_name).to eq('JiraService') } it 'has basic expected fields' do expect(described_class).to have_graphql_fields(:type, :active) end - it { expect(described_class).to require_graphql_authorizations(:admin_project) } + specify { expect(described_class).to require_graphql_authorizations(:admin_project) } end diff --git a/spec/graphql/types/projects/service_type_spec.rb b/spec/graphql/types/projects/service_type_spec.rb index ad30a4008bc..f6758d17d18 100644 --- a/spec/graphql/types/projects/service_type_spec.rb +++ b/spec/graphql/types/projects/service_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Types::Projects::ServiceType do - it { expect(described_class).to have_graphql_fields(:type, :active) } + specify { expect(described_class).to have_graphql_fields(:type, :active) } describe ".resolve_type" do it 'resolves the corresponding type for objects' do diff --git a/spec/graphql/types/projects/services_enum_spec.rb b/spec/graphql/types/projects/services_enum_spec.rb index aac4aae4f69..91e398e8d81 100644 --- a/spec/graphql/types/projects/services_enum_spec.rb +++ b/spec/graphql/types/projects/services_enum_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GitlabSchema.types['ServiceType'] do - it { expect(described_class.graphql_name).to eq('ServiceType') } + specify { expect(described_class.graphql_name).to eq('ServiceType') } it 'exposes all the existing project services' do expect(described_class.values.keys).to match_array(available_services_enum) diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb index ab210f2e918..1f269a80d00 100644 --- a/spec/graphql/types/query_type_spec.rb +++ b/spec/graphql/types/query_type_spec.rb @@ -8,7 +8,7 @@ describe GitlabSchema.types['Query'] do end it 'has the expected fields' do - expected_fields = %i[project namespace group echo metadata current_user snippets] + expected_fields = %i[project namespace group echo metadata current_user snippets design_management] expect(described_class).to have_graphql_fields(*expected_fields).at_least end diff --git a/spec/graphql/types/release_type_spec.rb b/spec/graphql/types/release_type_spec.rb new file mode 100644 index 00000000000..d22a0b4f0fa --- /dev/null +++ b/spec/graphql/types/release_type_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['Release'] do + it { expect(described_class).to require_graphql_authorizations(:read_release) } + + it 'has the expected fields' do + expected_fields = %w[ + tag_name tag_path + description description_html + name milestones author commit + created_at released_at + ] + + expect(described_class).to include_graphql_fields(*expected_fields) + end + + describe 'milestones field' do + subject { described_class.fields['milestones'] } + + it { is_expected.to have_graphql_type(Types::MilestoneType.connection_type) } + end + + describe 'author field' do + subject { described_class.fields['author'] } + + it { is_expected.to have_graphql_type(Types::UserType) } + end + + describe 'commit field' do + subject { described_class.fields['commit'] } + + it { is_expected.to have_graphql_type(Types::CommitType) } + it { is_expected.to require_graphql_authorizations(:reporter_access) } + end +end diff --git a/spec/graphql/types/repository_type_spec.rb b/spec/graphql/types/repository_type_spec.rb index f746e75b574..fb52839c712 100644 --- a/spec/graphql/types/repository_type_spec.rb +++ b/spec/graphql/types/repository_type_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe GitlabSchema.types['Repository'] do - it { expect(described_class.graphql_name).to eq('Repository') } + specify { expect(described_class.graphql_name).to eq('Repository') } - it { expect(described_class).to require_graphql_authorizations(:download_code) } + specify { expect(described_class).to require_graphql_authorizations(:download_code) } - it { expect(described_class).to have_graphql_field(:root_ref) } + specify { expect(described_class).to have_graphql_field(:root_ref) } - it { expect(described_class).to have_graphql_field(:tree) } + specify { expect(described_class).to have_graphql_field(:tree) } end diff --git a/spec/graphql/types/root_storage_statistics_type_spec.rb b/spec/graphql/types/root_storage_statistics_type_spec.rb index b796b974b82..ebaa5a18623 100644 --- a/spec/graphql/types/root_storage_statistics_type_spec.rb +++ b/spec/graphql/types/root_storage_statistics_type_spec.rb @@ -3,12 +3,12 @@ require 'spec_helper' describe GitlabSchema.types['RootStorageStatistics'] do - it { expect(described_class.graphql_name).to eq('RootStorageStatistics') } + specify { expect(described_class.graphql_name).to eq('RootStorageStatistics') } it 'has all the required fields' do expect(described_class).to have_graphql_fields(:storage_size, :repository_size, :lfs_objects_size, :build_artifacts_size, :packages_size, :wiki_size) end - it { expect(described_class).to require_graphql_authorizations(:read_statistics) } + specify { expect(described_class).to require_graphql_authorizations(:read_statistics) } end diff --git a/spec/graphql/types/snippet_type_spec.rb b/spec/graphql/types/snippet_type_spec.rb index 6e580711fda..adc13d4d651 100644 --- a/spec/graphql/types/snippet_type_spec.rb +++ b/spec/graphql/types/snippet_type_spec.rb @@ -17,7 +17,7 @@ describe GitlabSchema.types['Snippet'] do end describe 'authorizations' do - it { expect(described_class).to require_graphql_authorizations(:read_snippet) } + specify { expect(described_class).to require_graphql_authorizations(:read_snippet) } end shared_examples 'response without repository URLs' do @@ -35,14 +35,6 @@ describe GitlabSchema.types['Snippet'] do expect(response['sshUrlToRepo']).to eq(snippet.ssh_url_to_repo) expect(response['httpUrlToRepo']).to eq(snippet.http_url_to_repo) end - - context 'when version_snippets feature is disabled' do - before do - stub_feature_flags(version_snippets: false) - end - - it_behaves_like 'response without repository URLs' - end end end diff --git a/spec/graphql/types/snippets/blob_type_spec.rb b/spec/graphql/types/snippets/blob_type_spec.rb index da36ab80f44..fb8c6896732 100644 --- a/spec/graphql/types/snippets/blob_type_spec.rb +++ b/spec/graphql/types/snippets/blob_type_spec.rb @@ -6,8 +6,22 @@ describe GitlabSchema.types['SnippetBlob'] do it 'has the correct fields' do expected_fields = [:rich_data, :plain_data, :raw_path, :size, :binary, :name, :path, - :simple_viewer, :rich_viewer, :mode] + :simple_viewer, :rich_viewer, :mode, :external_storage, + :rendered_as_text] expect(described_class).to have_graphql_fields(*expected_fields) end + + specify { expect(described_class.fields['richData'].type).not_to be_non_null } + specify { expect(described_class.fields['plainData'].type).not_to be_non_null } + specify { expect(described_class.fields['rawPath'].type).to be_non_null } + specify { expect(described_class.fields['size'].type).to be_non_null } + specify { expect(described_class.fields['binary'].type).to be_non_null } + specify { expect(described_class.fields['name'].type).not_to be_non_null } + specify { expect(described_class.fields['path'].type).not_to be_non_null } + specify { expect(described_class.fields['simpleViewer'].type).to be_non_null } + specify { expect(described_class.fields['richViewer'].type).not_to be_non_null } + specify { expect(described_class.fields['mode'].type).not_to be_non_null } + specify { expect(described_class.fields['externalStorage'].type).not_to be_non_null } + specify { expect(described_class.fields['renderedAsText'].type).to be_non_null } end diff --git a/spec/graphql/types/snippets/blob_viewer_type_spec.rb b/spec/graphql/types/snippets/blob_viewer_type_spec.rb index a51d09813ab..841e22451db 100644 --- a/spec/graphql/types/snippets/blob_viewer_type_spec.rb +++ b/spec/graphql/types/snippets/blob_viewer_type_spec.rb @@ -3,10 +3,91 @@ require 'spec_helper' describe GitlabSchema.types['SnippetBlobViewer'] do + let_it_be(:snippet) { create(:personal_snippet, :repository) } + let_it_be(:blob) { snippet.repository.blob_at('HEAD', 'files/images/6049019_460s.jpg') } + it 'has the correct fields' do expected_fields = [:type, :load_async, :too_large, :collapsed, :render_error, :file_type, :loading_partial_name] expect(described_class).to have_graphql_fields(*expected_fields) end + + it { expect(described_class.fields['type'].type).to be_non_null } + it { expect(described_class.fields['loadAsync'].type).to be_non_null } + it { expect(described_class.fields['collapsed'].type).to be_non_null } + it { expect(described_class.fields['tooLarge'].type).to be_non_null } + it { expect(described_class.fields['renderError'].type).not_to be_non_null } + it { expect(described_class.fields['fileType'].type).to be_non_null } + it { expect(described_class.fields['loadingPartialName'].type).to be_non_null } + + shared_examples 'nil field converted to false' do + subject { GitlabSchema.execute(query, context: { current_user: snippet.author }).as_json } + + before do + allow_next_instance_of(SnippetPresenter) do |instance| + allow(instance).to receive(:blob).and_return(blob) + end + end + + it 'returns false' do + snippet_blob = subject.dig('data', 'snippets', 'edges')[0].dig('node', 'blob') + + expect(snippet_blob['path']).to eq blob.path + expect(blob_attribute).to be_nil + expect(snippet_blob['simpleViewer'][attribute]).to eq false + end + end + + describe 'collapsed' do + it_behaves_like 'nil field converted to false' do + let(:query) do + %( + query { + snippets(ids:"#{snippet.to_global_id}"){ + edges { + node { + blob { + path + simpleViewer { + collapsed + } + } + } + } + } + } + ) + end + + let(:attribute) { 'collapsed' } + let(:blob_attribute) { blob.simple_viewer.collapsed? } + end + end + + describe 'tooLarge' do + it_behaves_like 'nil field converted to false' do + let(:query) do + %( + query { + snippets(ids:"#{snippet.to_global_id}"){ + edges { + node { + blob { + path + simpleViewer { + tooLarge + } + } + } + } + } + } + ) + end + + let(:attribute) { 'tooLarge' } + let(:blob_attribute) { blob.simple_viewer.too_large? } + end + end end diff --git a/spec/graphql/types/time_type_spec.rb b/spec/graphql/types/time_type_spec.rb index 88a535ed3bb..3c6e191e2fb 100644 --- a/spec/graphql/types/time_type_spec.rb +++ b/spec/graphql/types/time_type_spec.rb @@ -6,7 +6,7 @@ describe GitlabSchema.types['Time'] do let(:iso) { "2018-06-04T15:23:50+02:00" } let(:time) { Time.parse(iso) } - it { expect(described_class.graphql_name).to eq('Time') } + specify { expect(described_class.graphql_name).to eq('Time') } it 'coerces Time object into ISO 8601' do expect(described_class.coerce_isolated_result(time)).to eq(iso) diff --git a/spec/graphql/types/todo_type_spec.rb b/spec/graphql/types/todo_type_spec.rb index 59118259d09..87a5405f0e2 100644 --- a/spec/graphql/types/todo_type_spec.rb +++ b/spec/graphql/types/todo_type_spec.rb @@ -9,5 +9,5 @@ describe GitlabSchema.types['Todo'] do expect(described_class).to have_graphql_fields(*expected_fields) end - it { expect(described_class).to require_graphql_authorizations(:read_todo) } + specify { expect(described_class).to require_graphql_authorizations(:read_todo) } end diff --git a/spec/graphql/types/tree/blob_type_spec.rb b/spec/graphql/types/tree/blob_type_spec.rb index 516c862b9c6..547a03b5edf 100644 --- a/spec/graphql/types/tree/blob_type_spec.rb +++ b/spec/graphql/types/tree/blob_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Types::Tree::BlobType do - it { expect(described_class.graphql_name).to eq('Blob') } + specify { expect(described_class.graphql_name).to eq('Blob') } - it { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url, :lfs_oid) } + specify { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url, :lfs_oid) } end diff --git a/spec/graphql/types/tree/submodule_type_spec.rb b/spec/graphql/types/tree/submodule_type_spec.rb index 81f7ad825a1..b5cfe8eb812 100644 --- a/spec/graphql/types/tree/submodule_type_spec.rb +++ b/spec/graphql/types/tree/submodule_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Types::Tree::SubmoduleType do - it { expect(described_class.graphql_name).to eq('Submodule') } + specify { expect(described_class.graphql_name).to eq('Submodule') } - it { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url, :tree_url) } + specify { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url, :tree_url) } end diff --git a/spec/graphql/types/tree/tree_entry_type_spec.rb b/spec/graphql/types/tree/tree_entry_type_spec.rb index 228a4be0949..14826d06645 100644 --- a/spec/graphql/types/tree/tree_entry_type_spec.rb +++ b/spec/graphql/types/tree/tree_entry_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Types::Tree::TreeEntryType do - it { expect(described_class.graphql_name).to eq('TreeEntry') } + specify { expect(described_class.graphql_name).to eq('TreeEntry') } - it { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url) } + specify { expect(described_class).to have_graphql_fields(:id, :sha, :name, :type, :path, :flat_path, :web_url) } end diff --git a/spec/graphql/types/tree/tree_type_spec.rb b/spec/graphql/types/tree/tree_type_spec.rb index 23779d75600..93faebd3602 100644 --- a/spec/graphql/types/tree/tree_type_spec.rb +++ b/spec/graphql/types/tree/tree_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Types::Tree::TreeType do - it { expect(described_class.graphql_name).to eq('Tree') } + specify { expect(described_class.graphql_name).to eq('Tree') } - it { expect(described_class).to have_graphql_fields(:trees, :submodules, :blobs, :last_commit) } + specify { expect(described_class).to have_graphql_fields(:trees, :submodules, :blobs, :last_commit) } end diff --git a/spec/graphql/types/tree/type_enum_spec.rb b/spec/graphql/types/tree/type_enum_spec.rb index 4caf9e1c457..dcacd6073f9 100644 --- a/spec/graphql/types/tree/type_enum_spec.rb +++ b/spec/graphql/types/tree/type_enum_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Types::Tree::TypeEnum do - it { expect(described_class.graphql_name).to eq('EntryType') } + specify { expect(described_class.graphql_name).to eq('EntryType') } it 'exposes all tree entry types' do expect(described_class.values.keys).to include(*%w[tree blob commit]) diff --git a/spec/graphql/types/user_type_spec.rb b/spec/graphql/types/user_type_spec.rb index 8c76ce43e95..cf1e91afb80 100644 --- a/spec/graphql/types/user_type_spec.rb +++ b/spec/graphql/types/user_type_spec.rb @@ -3,13 +3,13 @@ require 'spec_helper' describe GitlabSchema.types['User'] do - it { expect(described_class.graphql_name).to eq('User') } + specify { expect(described_class.graphql_name).to eq('User') } - it { expect(described_class).to require_graphql_authorizations(:read_user) } + specify { expect(described_class).to require_graphql_authorizations(:read_user) } it 'has the expected fields' do expected_fields = %w[ - user_permissions snippets name username avatarUrl webUrl todos + id user_permissions snippets name username avatarUrl webUrl todos state ] expect(described_class).to have_graphql_fields(*expected_fields) |