diff options
Diffstat (limited to 'spec')
16 files changed, 381 insertions, 50 deletions
diff --git a/spec/db/development/create_base_work_item_types_spec.rb b/spec/db/development/create_base_work_item_types_spec.rb new file mode 100644 index 00000000000..914b84d8668 --- /dev/null +++ b/spec/db/development/create_base_work_item_types_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Create base work item types in development' do + subject { load Rails.root.join('db', 'fixtures', 'development', '001_create_base_work_item_types.rb') } + + it_behaves_like 'work item base types importer' +end diff --git a/spec/db/production/create_base_work_item_types_spec.rb b/spec/db/production/create_base_work_item_types_spec.rb new file mode 100644 index 00000000000..81d80104bb4 --- /dev/null +++ b/spec/db/production/create_base_work_item_types_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Create base work item types in production' do + subject { load Rails.root.join('db', 'fixtures', 'production', '003_create_base_work_item_types.rb') } + + it_behaves_like 'work item base types importer' +end diff --git a/spec/frontend/deploy_freeze/store/actions_spec.js b/spec/frontend/deploy_freeze/store/actions_spec.js index ac606f1b182..ad67afdce75 100644 --- a/spec/frontend/deploy_freeze/store/actions_spec.js +++ b/spec/frontend/deploy_freeze/store/actions_spec.js @@ -5,6 +5,7 @@ import * as actions from '~/deploy_freeze/store/actions'; import * as types from '~/deploy_freeze/store/mutation_types'; import getInitialState from '~/deploy_freeze/store/state'; import createFlash from '~/flash'; +import * as logger from '~/lib/logger'; import axios from '~/lib/utils/axios_utils'; import { freezePeriodsFixture, timezoneDataFixture } from '../helpers'; @@ -218,7 +219,7 @@ describe('deploy freeze store actions', () => { }); it('should show flash error and set error in state on delete failure', () => { - const errorSpy = jest.spyOn(console, 'error').mockImplementation(); + jest.spyOn(logger, 'logError').mockImplementation(); const error = new Error(); Api.deleteFreezePeriod.mockRejectedValue(error); @@ -234,7 +235,7 @@ describe('deploy freeze store actions', () => { () => { expect(createFlash).toHaveBeenCalled(); - expect(errorSpy).toHaveBeenCalledWith('[gitlab] Unable to delete deploy freeze:', error); + expect(logger.logError).toHaveBeenCalledWith('Unable to delete deploy freeze', error); }, ); }); diff --git a/spec/frontend/lib/logger/index_spec.js b/spec/frontend/lib/logger/index_spec.js new file mode 100644 index 00000000000..9382fafe4de --- /dev/null +++ b/spec/frontend/lib/logger/index_spec.js @@ -0,0 +1,23 @@ +import { logError, LOG_PREFIX } from '~/lib/logger'; + +describe('~/lib/logger', () => { + let consoleErrorSpy; + + beforeEach(() => { + consoleErrorSpy = jest.spyOn(console, 'error'); + consoleErrorSpy.mockImplementation(); + }); + + describe('logError', () => { + it('sends given message to console.error', () => { + const message = 'Lorem ipsum dolar sit amit'; + const error = new Error('lorem ipsum'); + + expect(consoleErrorSpy).not.toHaveBeenCalled(); + + logError(message, error); + + expect(consoleErrorSpy).toHaveBeenCalledWith(LOG_PREFIX, `${message}\n`, error); + }); + }); +}); diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb index d752496d809..719c14ee188 100644 --- a/spec/graphql/resolvers/issues_resolver_spec.rb +++ b/spec/graphql/resolvers/issues_resolver_spec.rb @@ -20,6 +20,7 @@ RSpec.describe Resolvers::IssuesResolver do let_it_be(:issue4) { create(:issue) } let_it_be(:label1) { create(:label, project: project) } let_it_be(:label2) { create(:label, project: project) } + let_it_be(:upvote_award) { create(:award_emoji, :upvote, user: current_user, awardable: issue1) } specify do expect(described_class).to have_nullable_graphql_type(Types::IssueType.connection_type) @@ -200,6 +201,27 @@ RSpec.describe Resolvers::IssuesResolver do end end + context 'filtering by reaction emoji' do + let_it_be(:downvoted_issue) { create(:issue, project: project) } + let_it_be(:downvote_award) { create(:award_emoji, :downvote, user: current_user, awardable: downvoted_issue) } + + it 'filters by reaction emoji' do + expect(resolve_issues(my_reaction_emoji: upvote_award.name)).to contain_exactly(issue1) + end + + it 'filters by reaction emoji wildcard "none"' do + expect(resolve_issues(my_reaction_emoji: 'none')).to contain_exactly(issue2) + end + + it 'filters by reaction emoji wildcard "any"' do + expect(resolve_issues(my_reaction_emoji: 'any')).to contain_exactly(issue1, downvoted_issue) + end + + it 'filters by negated reaction emoji' do + expect(resolve_issues(not: { my_reaction_emoji: downvote_award.name })).to contain_exactly(issue1, issue2) + end + end + context 'when searching issues' do it 'returns correct issues' do expect(resolve_issues(search: 'foo')).to contain_exactly(issue2) diff --git a/spec/lib/gitlab/database/load_balancing/sidekiq_client_middleware_spec.rb b/spec/lib/gitlab/database/load_balancing/sidekiq_client_middleware_spec.rb index 23a496d85f8..f683ade978a 100644 --- a/spec/lib/gitlab/database/load_balancing/sidekiq_client_middleware_spec.rb +++ b/spec/lib/gitlab/database/load_balancing/sidekiq_client_middleware_spec.rb @@ -85,7 +85,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqClientMiddleware do end it 'passes database_replica_location' do - expected_location = { main: location } + expected_location = { Gitlab::Database::MAIN_DATABASE_NAME.to_sym => location } expect(load_balancer).to receive_message_chain(:host, "database_replica_location").and_return(location) @@ -103,7 +103,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqClientMiddleware do end it 'passes primary write location', :aggregate_failures do - expected_location = { main: location } + expected_location = { Gitlab::Database::MAIN_DATABASE_NAME.to_sym => location } expect(load_balancer).to receive(:primary_write_location).and_return(location) @@ -116,28 +116,43 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqClientMiddleware do end end - shared_examples_for 'database location was already provided' do - shared_examples_for 'does not set database location again' do |use_primary| - before do - allow(Gitlab::Database::LoadBalancing::Session.current).to receive(:use_primary?).and_return(use_primary) - end + context 'when worker cannot be constantized' do + let(:worker_class) { 'ActionMailer::MailDeliveryJob' } + let(:expected_consistency) { :always } - it 'does not set database locations again' do - run_middleware + include_examples 'does not pass database locations' + end - expect(job['wal_locations']).to eq({ main: old_location }) - end - end + context 'when worker class does not include ApplicationWorker' do + let(:worker_class) { ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper } + let(:expected_consistency) { :always } + + include_examples 'does not pass database locations' + end + context 'database wal location was already provided' do let(:old_location) { '0/D525E3A8' } let(:new_location) { 'AB/12345' } - let(:job) { { "job_id" => "a180b47c-3fd6-41b8-81e9-34da61c3400e", 'wal_locations' => { main: old_location } } } + let(:wal_locations) { { Gitlab::Database::MAIN_DATABASE_NAME.to_sym => old_location } } + let(:job) { { "job_id" => "a180b47c-3fd6-41b8-81e9-34da61c3400e", 'wal_locations' => wal_locations } } before do allow(load_balancer).to receive(:primary_write_location).and_return(new_location) allow(load_balancer).to receive(:database_replica_location).and_return(new_location) end + shared_examples_for 'does not set database location again' do |use_primary| + before do + allow(Gitlab::Database::LoadBalancing::Session.current).to receive(:use_primary?).and_return(use_primary) + end + + it 'does not set database locations again' do + run_middleware + + expect(job['wal_locations']).to eq(wal_locations) + end + end + context "when write was performed" do include_examples 'does not set database location again', true end @@ -147,24 +162,6 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqClientMiddleware do end end - context 'when worker cannot be constantized' do - let(:worker_class) { 'ActionMailer::MailDeliveryJob' } - let(:expected_consistency) { :always } - - include_examples 'does not pass database locations' - end - - context 'when worker class does not include ApplicationWorker' do - let(:worker_class) { ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper } - let(:expected_consistency) { :always } - - include_examples 'does not pass database locations' - end - - context 'database wal location was already provided' do - include_examples 'database location was already provided' - end - context 'when worker data consistency is :always' do include_context 'data consistency worker class', :always, :load_balancing_for_test_data_consistency_worker diff --git a/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb b/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb index fcb1d52fbaf..1fe348bbf2e 100644 --- a/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb +++ b/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb @@ -63,10 +63,11 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do end shared_examples_for 'replica is up to date' do |expected_strategy| - let(:wal_locations) { { main: '0/D525E3A8' } } + let(:location) {'0/D525E3A8' } + let(:wal_locations) { { Gitlab::Database::MAIN_DATABASE_NAME.to_sym => location } } it 'does not stick to the primary', :aggregate_failures do - expect(load_balancer).to receive(:select_up_to_date_host).with(wal_locations[:main]).and_return(true) + expect(load_balancer).to receive(:select_up_to_date_host).with(location).and_return(true) run_middleware do expect(Gitlab::Database::LoadBalancing::Session.current.use_primary?).not_to be_truthy @@ -91,7 +92,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do let(:job) { { 'job_id' => 'a180b47c-3fd6-41b8-81e9-34da61c3400e', 'wal_locations' => wal_locations } } before do - allow(load_balancer).to receive(:select_up_to_date_host).with(wal_locations[:main]).and_return(true) + allow(load_balancer).to receive(:select_up_to_date_host).with(location).and_return(true) end it_behaves_like 'replica is up to date', 'replica' diff --git a/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb b/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb new file mode 100644 index 00000000000..8c3d372cc55 --- /dev/null +++ b/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter do + subject { described_class.import } + + it_behaves_like 'work item base types importer' +end diff --git a/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb b/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb new file mode 100644 index 00000000000..ac2695977c4 --- /dev/null +++ b/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Pagination::CursorBasedKeyset do + subject { described_class } + + describe '.available_for_type?' do + it 'returns true for Group' do + expect(subject.available_for_type?(Group.all)).to be_truthy + end + + it 'return false for other types of relations' do + expect(subject.available_for_type?(User.all)).to be_falsey + end + end + + describe '.available?' do + let(:request_context) { double('request_context', params: { order_by: order_by, sort: sort }) } + let(:cursor_based_request_context) { Gitlab::Pagination::Keyset::CursorBasedRequestContext.new(request_context) } + + context 'with order-by name asc' do + let(:order_by) { :name } + let(:sort) { :asc } + + it 'returns true for Group' do + expect(subject.available?(cursor_based_request_context, Group.all)).to be_truthy + end + + it 'return false for other types of relations' do + expect(subject.available?(cursor_based_request_context, User.all)).to be_falsey + end + end + + context 'with other order-by columns' do + let(:order_by) { :path } + let(:sort) { :asc } + + it 'returns false for Group' do + expect(subject.available?(cursor_based_request_context, Group.all)).to be_falsey + end + + it 'return false for other types of relations' do + expect(subject.available?(cursor_based_request_context, User.all)).to be_falsey + end + end + end +end diff --git a/spec/lib/gitlab/pagination/keyset/cursor_based_request_context_spec.rb b/spec/lib/gitlab/pagination/keyset/cursor_based_request_context_spec.rb index 4998abd2186..79de6f230ec 100644 --- a/spec/lib/gitlab/pagination/keyset/cursor_based_request_context_spec.rb +++ b/spec/lib/gitlab/pagination/keyset/cursor_based_request_context_spec.rb @@ -3,32 +3,40 @@ require 'spec_helper' RSpec.describe Gitlab::Pagination::Keyset::CursorBasedRequestContext do - let(:params) { { per_page: 2, cursor: 'eyJuYW1lIjoiR2l0TGFiIEluc3RhbmNlIiwiaWQiOiI1MiIsIl9rZCI6Im4ifQ==' } } - let(:request) { double('request', params: params) } + let(:params) { { per_page: 2, cursor: 'eyJuYW1lIjoiR2l0TGFiIEluc3RhbmNlIiwiaWQiOiI1MiIsIl9rZCI6Im4ifQ==', order_by: :name, sort: :asc } } + let(:request) { double('request', url: 'http://localhost') } + let(:request_context) { double('request_context', header: nil, params: params, request: request) } describe '#per_page' do - subject(:per_page) { described_class.new(request).per_page } + subject(:per_page) { described_class.new(request_context).per_page } it { is_expected.to eq 2 } end describe '#cursor' do - subject(:cursor) { described_class.new(request).cursor } + subject(:cursor) { described_class.new(request_context).cursor } it { is_expected.to eq 'eyJuYW1lIjoiR2l0TGFiIEluc3RhbmNlIiwiaWQiOiI1MiIsIl9rZCI6Im4ifQ==' } end + describe '#order_by' do + subject(:order_by) { described_class.new(request_context).order_by } + + it { is_expected.to eq({ name: :asc }) } + end + describe '#apply_headers' do - let(:request) { double('request', url: "http://#{Gitlab.config.gitlab.host}/api/v4/projects?per_page=3", params: params) } + let(:request) { double('request', url: "http://#{Gitlab.config.gitlab.host}/api/v4/projects?per_page=3") } let(:params) { { per_page: 3 } } + let(:request_context) { double('request_context', header: nil, params: params, request: request) } let(:cursor_for_next_page) { 'eyJuYW1lIjoiSDVicCIsImlkIjoiMjgiLCJfa2QiOiJuIn0=' } - subject(:apply_headers) { described_class.new(request).apply_headers(cursor_for_next_page) } + subject(:apply_headers) { described_class.new(request_context).apply_headers(cursor_for_next_page) } it 'sets Link header with same host/path as the original request' do - orig_uri = URI.parse(request.url) + orig_uri = URI.parse(request_context.request.url) - expect(request).to receive(:header).once do |name, header| + expect(request_context).to receive(:header).once do |name, header| first_link, _ = /<([^>]+)>; rel="next"/.match(header).captures uri = URI.parse(first_link) @@ -42,9 +50,9 @@ RSpec.describe Gitlab::Pagination::Keyset::CursorBasedRequestContext do end it 'sets Link header with a cursor to the next page' do - orig_uri = URI.parse(request.url) + orig_uri = URI.parse(request_context.request.url) - expect(request).to receive(:header).once do |name, header| + expect(request_context).to receive(:header).once do |name, header| first_link, _ = /<([^>]+)>; rel="next"/.match(header).captures query = CGI.parse(URI.parse(first_link).query) diff --git a/spec/lib/gitlab/pagination/keyset/cursor_pager_spec.rb b/spec/lib/gitlab/pagination/keyset/cursor_pager_spec.rb index 5ba381834ea..783e728b34c 100644 --- a/spec/lib/gitlab/pagination/keyset/cursor_pager_spec.rb +++ b/spec/lib/gitlab/pagination/keyset/cursor_pager_spec.rb @@ -6,8 +6,8 @@ RSpec.describe Gitlab::Pagination::Keyset::CursorPager do let(:relation) { Group.all.order(:name, :id) } let(:per_page) { 3 } let(:params) { { cursor: nil, per_page: per_page } } - let(:request) { double('request', params: params) } - let(:cursor_based_request_context) { Gitlab::Pagination::Keyset::CursorBasedRequestContext.new(request) } + let(:request_context) { double('request_context', params: params) } + let(:cursor_based_request_context) { Gitlab::Pagination::Keyset::CursorBasedRequestContext.new(request_context) } before_all do create_list(:group, 7) @@ -33,7 +33,7 @@ RSpec.describe Gitlab::Pagination::Keyset::CursorPager do it 'passes information about next page to request' do cursor_for_next_page = relation.keyset_paginate(**params).cursor_for_next_page - expect_next_instance_of(Gitlab::Pagination::Keyset::HeaderBuilder, cursor_based_request_context) do |builder| + expect_next_instance_of(Gitlab::Pagination::Keyset::HeaderBuilder, request_context) do |builder| expect(builder).to receive(:add_next_page_header).with({ cursor: cursor_for_next_page }) end diff --git a/spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb b/spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb new file mode 100644 index 00000000000..b9cc9de88cc --- /dev/null +++ b/spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration!('upsert_base_work_item_types') + +RSpec.describe UpsertBaseWorkItemTypes, :migration do + let!(:work_item_types) { table(:work_item_types) } + + context 'when no default types exist' do + it 'creates default data' do + expect(work_item_types.count).to eq(0) + + reversible_migration do |migration| + migration.before -> { + # Depending on whether the migration has been run before, + # the size could be 4, or 0, so we don't set any expectations + # as we don't delete base types on migration reverse + } + + migration.after -> { + expect(work_item_types.count).to eq(4) + expect(work_item_types.all.pluck(:base_type)).to match_array(WorkItem::Type.base_types.values) + } + end + end + end + + context 'when default types already exist' do + before do + Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.import + end + + it 'does not create default types again' do + expect(work_item_types.all.pluck(:base_type)).to match_array(WorkItem::Type.base_types.values) + + reversible_migration do |migration| + migration.before -> { + expect(work_item_types.all.pluck(:base_type)).to match_array(WorkItem::Type.base_types.values) + } + + migration.after -> { + expect(work_item_types.count).to eq(4) + expect(work_item_types.all.pluck(:base_type)).to match_array(WorkItem::Type.base_types.values) + } + end + end + end +end diff --git a/spec/models/ci/pipeline_variable_spec.rb b/spec/models/ci/pipeline_variable_spec.rb index 04fcaab4c2d..4e8d49585d0 100644 --- a/spec/models/ci/pipeline_variable_spec.rb +++ b/spec/models/ci/pipeline_variable_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Ci::PipelineVariable do it_behaves_like "CI variable" - it { is_expected.to validate_uniqueness_of(:key).scoped_to(:pipeline_id) } + it { is_expected.to validate_presence_of(:key) } describe '#hook_attrs' do let(:variable) { create(:ci_pipeline_variable, key: 'foo', value: 'bar') } diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb index ff0d7ecceb5..c6b4d82bf15 100644 --- a/spec/requests/api/graphql/project/issues_spec.rb +++ b/spec/requests/api/graphql/project/issues_spec.rb @@ -61,6 +61,34 @@ RSpec.describe 'getting an issue list for a project' do end end + context 'filtering by my_reaction_emoji' do + using RSpec::Parameterized::TableSyntax + + let_it_be(:upvote_award) { create(:award_emoji, :upvote, user: current_user, awardable: issue_a) } + + let(:issue_a_gid) { issue_a.to_global_id.to_s } + let(:issue_b_gid) { issue_b.to_global_id.to_s } + + where(:value, :gids) do + 'thumbsup' | lazy { [issue_a_gid] } + 'ANY' | lazy { [issue_a_gid] } + 'any' | lazy { [issue_a_gid] } + 'AnY' | lazy { [issue_a_gid] } + 'NONE' | lazy { [issue_b_gid] } + 'thumbsdown' | lazy { [] } + end + + with_them do + let(:issue_filter_params) { { my_reaction_emoji: value } } + + it 'returns correctly filtered issues' do + post_graphql(query, current_user: current_user) + + expect(graphql_dig_at(issues_data, :node, :id)).to eq(gids) + end + end + end + context 'when limiting the number of results' do let(:query) do <<~GQL diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 30df47ccc41..38abedde7da 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -158,6 +158,127 @@ RSpec.describe API::Groups do end end + context 'pagination strategies' do + let_it_be(:group_1) { create(:group, name: '1_group') } + let_it_be(:group_2) { create(:group, name: '2_group') } + + context 'when the user is anonymous' do + context 'offset pagination' do + context 'on making requests beyond the allowed offset pagination threshold' do + it 'returns error and suggests to use keyset pagination' do + get api('/groups'), params: { page: 3000, per_page: 25 } + + expect(response).to have_gitlab_http_status(:method_not_allowed) + expect(json_response['error']).to eq( + 'Offset pagination has a maximum allowed offset of 50000 for requests that return objects of type Group. '\ + 'Remaining records can be retrieved using keyset pagination.' + ) + end + + context 'when the feature flag `keyset_pagination_for_groups_api` is disabled' do + before do + stub_feature_flags(keyset_pagination_for_groups_api: false) + end + + it 'returns successful response' do + get api('/groups'), params: { page: 3000, per_page: 25 } + + expect(response).to have_gitlab_http_status(:ok) + end + end + end + + context 'on making requests below the allowed offset pagination threshold' do + it 'paginates the records' do + get api('/groups'), params: { page: 1, per_page: 1 } + + expect(response).to have_gitlab_http_status(:ok) + records = json_response + expect(records.size).to eq(1) + expect(records.first['id']).to eq(group_1.id) + + # next page + + get api('/groups'), params: { page: 2, per_page: 1 } + + expect(response).to have_gitlab_http_status(:ok) + records = Gitlab::Json.parse(response.body) + expect(records.size).to eq(1) + expect(records.first['id']).to eq(group_2.id) + end + end + end + + context 'keyset pagination' do + def pagination_links(response) + link = response.headers['LINK'] + return unless link + + link.split(',').map do |link| + match = link.match(/<(?<url>.*)>; rel="(?<rel>\w+)"/) + break nil unless match + + { url: match[:url], rel: match[:rel] } + end.compact + end + + def params_for_next_page(response) + next_url = pagination_links(response).find { |link| link[:rel] == 'next' }[:url] + Rack::Utils.parse_query(URI.parse(next_url).query) + end + + context 'on making requests with supported ordering structure' do + it 'paginates the records correctly' do + # first page + get api('/groups'), params: { pagination: 'keyset', per_page: 1 } + + expect(response).to have_gitlab_http_status(:ok) + records = json_response + expect(records.size).to eq(1) + expect(records.first['id']).to eq(group_1.id) + + params_for_next_page = params_for_next_page(response) + expect(params_for_next_page).to include('cursor') + + get api('/groups'), params: params_for_next_page + + expect(response).to have_gitlab_http_status(:ok) + records = Gitlab::Json.parse(response.body) + expect(records.size).to eq(1) + expect(records.first['id']).to eq(group_2.id) + end + + context 'when the feature flag `keyset_pagination_for_groups_api` is disabled' do + before do + stub_feature_flags(keyset_pagination_for_groups_api: false) + end + + it 'ignores the keyset pagination params and performs offset pagination' do + get api('/groups'), params: { pagination: 'keyset', per_page: 1 } + + expect(response).to have_gitlab_http_status(:ok) + records = json_response + expect(records.size).to eq(1) + expect(records.first['id']).to eq(group_1.id) + + params_for_next_page = params_for_next_page(response) + expect(params_for_next_page).not_to include('cursor') + end + end + end + + context 'on making requests with unsupported ordering structure' do + it 'returns error' do + get api('/groups'), params: { pagination: 'keyset', per_page: 1, order_by: 'path', sort: 'desc' } + + expect(response).to have_gitlab_http_status(:method_not_allowed) + expect(json_response['error']).to eq('Keyset pagination is not yet available for this type of request') + end + end + end + end + end + context "when authenticated as admin" do it "admin: returns an array of all groups" do get api("/groups", admin) diff --git a/spec/support/shared_examples/work_item_base_types_importer.rb b/spec/support/shared_examples/work_item_base_types_importer.rb new file mode 100644 index 00000000000..2c02b76d49b --- /dev/null +++ b/spec/support/shared_examples/work_item_base_types_importer.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'work item base types importer' do + it 'creates all base work item types' do + expect { subject }.to change(WorkItem::Type, :count).from(0).to(WorkItem::Type::BASE_TYPES.count) + end +end |