diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-09 12:10:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-09 12:10:54 +0300 |
commit | c2de38f36d2fb75a17ce161fa69f2b8a5e670f3e (patch) | |
tree | d24a576c60f21055b8e2bc7f0d9954830d8a229c /spec | |
parent | 40338034578aca9d622651a060cbf157a941361b (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
9 files changed, 218 insertions, 39 deletions
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 5f03d721fe7..4b091e9221e 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -373,7 +373,7 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d end context 'when stop action' do - it 'returns action url for single stop action' do + it 'returns job url for a stop action when job is build' do action = create(:ci_build, :manual) allow_any_instance_of(Environment) @@ -387,6 +387,20 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d project_job_url(project, action) }) end + it 'returns pipeline url for a stop action when job is bridge' do + action = create(:ci_bridge, :manual) + + allow_any_instance_of(Environment) + .to receive_messages(available?: true, stop_with_actions!: [action]) + + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to eq( + { 'redirect_url' => + project_pipeline_url(project, action.pipeline_id) }) + end + it 'returns environment url for multiple stop actions' do actions = create_list(:ci_build, 2, :manual) diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index d53aefe5a4e..838ac67ee3d 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -156,6 +156,7 @@ RSpec.describe 'Projects > Settings > Repository settings', feature_category: :g before do visit project_settings_repository_path(project) + click_button 'Add new' end it 'shows push mirror settings', :js do diff --git a/spec/frontend/comment_templates/components/form_spec.js b/spec/frontend/comment_templates/components/form_spec.js index 053a5099c37..b48feba5290 100644 --- a/spec/frontend/comment_templates/components/form_spec.js +++ b/spec/frontend/comment_templates/components/form_spec.js @@ -5,6 +5,7 @@ import VueApollo from 'vue-apollo'; import createdSavedReplyResponse from 'test_fixtures/graphql/comment_templates/create_saved_reply.mutation.graphql.json'; import createdSavedReplyErrorResponse from 'test_fixtures/graphql/comment_templates/create_saved_reply_with_errors.mutation.graphql.json'; import createMockApollo from 'helpers/mock_apollo_helper'; +import { mockTracking } from 'helpers/tracking_helper'; import waitForPromises from 'helpers/wait_for_promises'; import Form from '~/comment_templates/components/form.vue'; import createSavedReplyMutation from '~/comment_templates/queries/create_saved_reply.mutation.graphql'; @@ -52,6 +53,12 @@ const findSubmitBtn = () => wrapper.find('[data-testid="comment-template-form-su describe('Comment templates form component', () => { describe('creates comment template', () => { + let trackingSpy; + + beforeEach(() => { + trackingSpy = mockTracking(undefined, window.document, jest.spyOn); + }); + it('calls apollo mutation', async () => { wrapper = createComponent(); @@ -66,6 +73,11 @@ describe('Comment templates form component', () => { content: 'Test content', name: 'Test', }); + expect(trackingSpy).toHaveBeenCalledWith( + expect.any(String), + 'i_code_review_saved_replies_create', + expect.any(Object), + ); }); it('does not submit when form validation fails', async () => { diff --git a/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js b/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js index 6a9e482a184..e9e7f7fdb88 100644 --- a/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js +++ b/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js @@ -45,7 +45,9 @@ describe('Deploy freeze table', () => { it('displays empty', () => { expect(findEmptyFreezePeriods().exists()).toBe(true); expect(findEmptyFreezePeriods().text()).toBe( - 'No deploy freezes exist for this project. To add one, select Add deploy freeze', + `No deploy freezes exist for this project. To add one, select + Add deploy freeze + above.`, ); }); diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js index 0cbb9eab018..8b8241f395f 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js @@ -9,6 +9,7 @@ import component from '~/packages_and_registries/container_registry/explorer/com import TagsListRow from '~/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue'; import TagsLoader from '~/packages_and_registries/shared/components/tags_loader.vue'; import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue'; +import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue'; import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue'; import getContainerRepositoryTagsQuery from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql'; import deleteContainerRepositoryTagsMutation from '~/packages_and_registries/container_registry/explorer/graphql/mutations/delete_container_repository_tags.mutation.graphql'; @@ -40,6 +41,7 @@ describe('Tags List', () => { }; const findDeleteModal = () => wrapper.findComponent(DeleteModal); + const findPersistedPagination = () => wrapper.findComponent(PersistedPagination); const findPersistedSearch = () => wrapper.findComponent(PersistedSearch); const findTagsListRow = () => wrapper.findAllComponents(TagsListRow); const findRegistryList = () => wrapper.findComponent(RegistryList); @@ -47,7 +49,7 @@ describe('Tags List', () => { const findTagsLoader = () => wrapper.findComponent(TagsLoader); const fireFirstSortUpdate = () => { - findPersistedSearch().vm.$emit('update', { sort: 'NAME_ASC', filters: [] }); + findPersistedSearch().vm.$emit('update', { sort: 'NAME_ASC', filters: [], pageInfo: {} }); }; const waitForApolloRequestRender = async () => { @@ -103,18 +105,24 @@ describe('Tags List', () => { it('binds the correct props', () => { expect(findRegistryList().props()).toMatchObject({ title: '2 tags', - pagination: tagsPageInfo, items: tags, idProperty: 'name', hiddenDelete: false, }); }); + it('has persisted pagination', () => { + expect(findPersistedPagination().props('pagination')).toEqual(tagsPageInfo); + }); + describe('events', () => { - it('prev-page fetch the previous page', async () => { - findRegistryList().vm.$emit('prev-page'); + it('prev-page fetches the previous page', async () => { + findPersistedPagination().vm.$emit('prev'); await waitForPromises(); + // we are fetching previous page after load, + // so we expect the resolver to have been called twice + expect(resolver).toHaveBeenCalledTimes(2); expect(resolver).toHaveBeenCalledWith({ first: null, name: '', @@ -125,10 +133,13 @@ describe('Tags List', () => { }); }); - it('next-page fetch the previous page', async () => { - findRegistryList().vm.$emit('next-page'); + it('next-page fetches the next page', async () => { + findPersistedPagination().vm.$emit('next'); await waitForPromises(); + // we are fetching next page after load, + // so we expect the resolver to have been called twice + expect(resolver).toHaveBeenCalledTimes(2); expect(resolver).toHaveBeenCalledWith({ after: tagsPageInfo.endCursor, first: GRAPHQL_PAGE_SIZE, @@ -182,6 +193,49 @@ describe('Tags List', () => { }); }); + describe('when persisted search emits update', () => { + beforeEach(() => { + mountComponent(); + }); + + it('with before calls resolver with pagination params', async () => { + findPersistedSearch().vm.$emit('update', { + sort: 'NAME_ASC', + filters: [], + pageInfo: { before: tagsPageInfo.startCursor }, + }); + await waitForPromises(); + + expect(resolver).toHaveBeenCalledTimes(1); + expect(resolver).toHaveBeenCalledWith({ + first: null, + name: '', + sort: 'NAME_ASC', + before: tagsPageInfo.startCursor, + last: GRAPHQL_PAGE_SIZE, + id: '1', + }); + }); + + it('with after calls resolver with pagination params', async () => { + findPersistedSearch().vm.$emit('update', { + sort: 'NAME_ASC', + filters: [], + pageInfo: { after: tagsPageInfo.endCursor }, + }); + await waitForPromises(); + + expect(resolver).toHaveBeenCalledTimes(1); + expect(resolver).toHaveBeenCalledWith({ + after: tagsPageInfo.endCursor, + first: GRAPHQL_PAGE_SIZE, + name: '', + sort: 'NAME_ASC', + id: '1', + }); + }); + }); + describe('list rows', () => { it('one row exist for each tag', async () => { mountComponent(); @@ -334,31 +388,44 @@ describe('Tags List', () => { let mutationResolver; describe('when mutation', () => { - beforeEach(() => { + beforeEach(async () => { mutationResolver = jest.fn().mockResolvedValue(graphQLDeleteImageRepositoryTagsMock); mountComponent({ mutationResolver }); - return waitForApolloRequestRender(); - }); - - it('is started renders loader', async () => { + await waitForApolloRequestRender(); findRegistryList().vm.$emit('delete', [tags[0]]); findDeleteModal().vm.$emit('confirmDelete'); - await nextTick(); + }); + + describe('starts', () => { + beforeEach(async () => { + await nextTick(); + }); + + it('renders loader', () => { + expect(findTagsLoader().exists()).toBe(true); + expect(findTagsListRow().exists()).toBe(false); + }); - expect(findTagsLoader().exists()).toBe(true); - expect(findTagsListRow().exists()).toBe(false); + it('hides pagination', () => { + expect(findPersistedPagination().exists()).toEqual(false); + }); }); - it('ends, loader is hidden', async () => { - findRegistryList().vm.$emit('delete', [tags[0]]); + describe('is resolved', () => { + beforeEach(async () => { + await waitForPromises(); + }); - findDeleteModal().vm.$emit('confirmDelete'); - await waitForPromises(); + it('loader is hidden', () => { + expect(findTagsLoader().exists()).toBe(false); + expect(findTagsListRow().exists()).toBe(true); + }); - expect(findTagsLoader().exists()).toBe(false); - expect(findTagsListRow().exists()).toBe(true); + it('pagination is shown', () => { + expect(findPersistedPagination().props('pagination')).toEqual(tagsPageInfo); + }); }); }); @@ -495,6 +562,11 @@ describe('Tags List', () => { expect(findTagsLoader().exists()).toBe(loadingVisible); expect(findTagsListRow().exists()).toBe(!loadingVisible); + if (queryExecuting) { + expect(findPersistedPagination().props('pagination')).toEqual({}); + } else { + expect(findPersistedPagination().props('pagination')).toEqual(tagsPageInfo); + } }, ); }); diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js index c039870b768..1f1f010e0c4 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js @@ -228,7 +228,7 @@ describe('List Page', () => { expect(findPersistedPagination().props('pagination')).toEqual({}); }); - it('cli commands is not visible', () => { + it('cli commands are not visible', () => { mountComponent(); expect(findCliCommands().exists()).toBe(false); @@ -243,11 +243,42 @@ describe('List Page', () => { }); }); + describe('when mutation is loading', () => { + beforeEach(async () => { + mountComponent(); + fireFirstSortUpdate(); + await waitForApolloRequestRender(); + findImageList().vm.$emit('delete', deletedContainerRepository); + findDeleteModal().vm.$emit('confirmDelete'); + findDeleteImage().vm.$emit('start'); + }); + + it('shows the skeleton loader', () => { + expect(findSkeletonLoader().exists()).toBe(true); + }); + + it('imagesList is not visible', () => { + expect(findImageList().exists()).toBe(false); + }); + + it('pagination is hidden', () => { + expect(findPersistedPagination().exists()).toBe(false); + }); + + it('cli commands are not visible', () => { + expect(findCliCommands().exists()).toBe(false); + }); + + it('title has the metadataLoading props set to true', () => { + expect(findRegistryHeader().props('metadataLoading')).toBe(true); + }); + }); + describe('list is empty', () => { describe('project page', () => { const resolver = jest.fn().mockResolvedValue(graphQLEmptyImageListMock); - it('cli commands is not visible', async () => { + it('cli commands are not visible', async () => { mountComponent({ resolver }); await waitForApolloRequestRender(); @@ -279,7 +310,7 @@ describe('List Page', () => { expect(findGroupEmptyState().exists()).toBe(true); }); - it('cli commands is not visible', async () => { + it('cli commands are not visible', async () => { mountComponent({ resolver, config }); await waitForApolloRequestRender(); diff --git a/spec/lib/gitlab/database/health_status/indicators/patroni_apdex_spec.rb b/spec/lib/gitlab/database/health_status/indicators/patroni_apdex_spec.rb index e0e3a0a7c23..a526d951db9 100644 --- a/spec/lib/gitlab/database/health_status/indicators/patroni_apdex_spec.rb +++ b/spec/lib/gitlab/database/health_status/indicators/patroni_apdex_spec.rb @@ -33,7 +33,7 @@ RSpec.describe Gitlab::Database::HealthStatus::Indicators::PatroniApdex, :aggreg let(:database_apdex_sli_query_ci) { 'Apdex query for ci' } let(:database_apdex_slo_main) { 0.99 } let(:database_apdex_slo_ci) { 0.95 } - let(:database_apdex_settings) do + let(:prometheus_alert_db_indicators_settings) do { prometheus_api_url: prometheus_url, apdex_sli_query: { @@ -50,7 +50,7 @@ RSpec.describe Gitlab::Database::HealthStatus::Indicators::PatroniApdex, :aggreg subject(:evaluate) { described_class.new(context).evaluate } before do - stub_application_setting(database_apdex_settings: database_apdex_settings) + stub_application_setting(prometheus_alert_db_indicators_settings: prometheus_alert_db_indicators_settings) allow(Gitlab::PrometheusClient).to receive(:new).with(*prometheus_config).and_return(prometheus_client) allow(prometheus_client).to receive(:ready?).and_return(client_ready) @@ -69,8 +69,8 @@ RSpec.describe Gitlab::Database::HealthStatus::Indicators::PatroniApdex, :aggreg expect(evaluate.reason).to include('indicator disabled') end - context 'without database_apdex_settings' do - let(:database_apdex_settings) { nil } + context 'without prometheus_alert_db_indicators_settings' do + let(:prometheus_alert_db_indicators_settings) { nil } it 'returns Unknown signal' do expect(evaluate).to be_a(Gitlab::Database::HealthStatus::Signals::Unknown) diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index b2275be5893..f447278f812 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -33,7 +33,7 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do let(:ftp) { 'ftp://example.com' } let(:javascript) { 'javascript:alert(window.opener.document.location)' } - let_it_be(:valid_database_apdex_settings) do + let_it_be(:valid_prometheus_alert_db_indicators_settings) do { prometheus_api_url: 'Prometheus URL', apdex_sli_query: { @@ -260,9 +260,9 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do it { is_expected.to allow_value(true, false).for(:gitlab_dedicated_instance) } it { is_expected.not_to allow_value(nil).for(:gitlab_dedicated_instance) } - it { is_expected.not_to allow_value(random: :value).for(:database_apdex_settings) } - it { is_expected.to allow_value(nil).for(:database_apdex_settings) } - it { is_expected.to allow_value(valid_database_apdex_settings).for(:database_apdex_settings) } + it { is_expected.not_to allow_value(random: :value).for(:prometheus_alert_db_indicators_settings) } + it { is_expected.to allow_value(nil).for(:prometheus_alert_db_indicators_settings) } + it { is_expected.to allow_value(valid_prometheus_alert_db_indicators_settings).for(:prometheus_alert_db_indicators_settings) } it { is_expected.to allow_value([true, false]).for(:silent_mode_enabled) } it { is_expected.not_to allow_value(nil).for(:silent_mode_enabled) } diff --git a/spec/requests/projects/merge_requests/creations_spec.rb b/spec/requests/projects/merge_requests/creations_spec.rb index e8a073fef5f..8f55aa90bee 100644 --- a/spec/requests/projects/merge_requests/creations_spec.rb +++ b/spec/requests/projects/merge_requests/creations_spec.rb @@ -10,6 +10,17 @@ RSpec.describe 'merge requests creations', feature_category: :code_review_workfl let_it_be(:project) { create(:project, :repository, group: group) } let_it_be(:user) { create(:user) } + let(:get_params) do + { + namespace_id: project.namespace.to_param, + project_id: project, + merge_request: { + source_branch: 'two-commits', + target_branch: 'master' + } + } + end + before_all do group.add_developer(user) end @@ -18,16 +29,52 @@ RSpec.describe 'merge requests creations', feature_category: :code_review_workfl login_as(user) end - def get_new - get namespace_project_new_merge_request_path(namespace_id: project.namespace, project_id: project) + def get_new(params = get_params) + get namespace_project_new_merge_request_path(params) end - it 'avoids N+1 DB queries even with forked projects' do - control = ActiveRecord::QueryRecorder.new(skip_cached: false) { get_new } + describe 'GET new' do + context 'without merge_request params' do + it 'avoids N+1 DB queries even with forked projects' do + control = ActiveRecord::QueryRecorder.new(skip_cached: false) { get_new } + + 5.times { fork_project(project, user) } + + expect { get_new }.not_to exceed_query_limit(control) + end + + it 'renders branch selection screen' do + get_new(get_params.except(:merge_request)) + + expect(response).to be_successful + expect(response).to render_template(partial: '_new_compare') + end + end + + context 'with merge_request params' do + it 'renders new merge request widget template' do + get_new + + expect(response).to be_successful + expect(response).to render_template(partial: '_new_submit') + expect(response).not_to render_template(partial: '_new_compare') + end - 5.times { fork_project(project, user) } + context 'when existing merge request with same target and source branches' do + let_it_be(:existing_mr) { create(:merge_request) } - expect { get_new }.not_to exceed_query_limit(control) + it 'renders branch selection screen' do + allow_next_instance_of(MergeRequest) do |instance| + allow(instance).to receive(:existing_mrs_targeting_same_branch).and_return([existing_mr]) + end + + get_new + + expect(response).to be_successful + expect(response).to render_template(partial: '_new_compare') + end + end + end end it_behaves_like "observability csp policy", Projects::MergeRequests::CreationsController do |