summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-02-10 12:18:48 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-02-10 12:18:48 +0000
commit190128fc72e015c383e7a96c128276d1833f3beb (patch)
treec9defcce34e8e0661c3a2cebe78847e9d9f14a39 /spec
parentde74d20b2596c8d27987744d24a7fc09fbe8ff37 (diff)
downloadgitlab-ce-190128fc72e015c383e7a96c128276d1833f3beb.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/events/projects/project_deleted_event_spec.rb34
-rw-r--r--spec/features/admin/admin_mode/logout_spec.rb2
-rw-r--r--spec/features/groups/members/leave_group_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/recent_searches_spec.rb2
-rw-r--r--spec/features/profiles/password_spec.rb2
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb2
-rw-r--r--spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb2
-rw-r--r--spec/features/projects/network_graph_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb4
-rw-r--r--spec/features/projects/tree/tree_show_spec.rb8
-rw-r--r--spec/features/projects_spec.rb4
-rw-r--r--spec/features/triggers_spec.rb6
-rw-r--r--spec/features/users/logout_spec.rb2
-rw-r--r--spec/frontend/error_tracking/components/error_details_spec.js32
-rw-r--r--spec/frontend/error_tracking/components/error_tracking_list_spec.js10
-rw-r--r--spec/frontend/feature_flags/components/feature_flags_spec.js20
-rw-r--r--spec/frontend/filtered_search/filtered_search_visual_tokens_spec.js9
-rw-r--r--spec/frontend/flash_spec.js8
-rw-r--r--spec/frontend/gl_form_spec.js15
-rw-r--r--spec/frontend/ide/components/commit_sidebar/list_item_spec.js19
-rw-r--r--spec/frontend/pipeline_wizard/components/editor_spec.js69
-rw-r--r--spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js20
-rw-r--r--spec/frontend/vue_shared/components/confirm_fork_modal_spec.js80
-rw-r--r--spec/frontend/vue_shared/components/web_ide_link_spec.js47
-rw-r--r--spec/lib/gitlab/changelog/release_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb5
-rw-r--r--spec/requests/api/lint_spec.rb17
-rw-r--r--spec/requests/git_http_spec.rb26
-rw-r--r--spec/services/projects/destroy_service_spec.rb26
-rw-r--r--spec/support/matchers/event_store.rb12
-rw-r--r--spec/support/shared_examples/features/variable_list_shared_examples.rb2
-rw-r--r--spec/tooling/quality/test_level_spec.rb4
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb1
-rw-r--r--spec/workers/namespaces/update_root_statistics_worker_spec.rb23
34 files changed, 418 insertions, 109 deletions
diff --git a/spec/events/projects/project_deleted_event_spec.rb b/spec/events/projects/project_deleted_event_spec.rb
new file mode 100644
index 00000000000..fd8cec7271b
--- /dev/null
+++ b/spec/events/projects/project_deleted_event_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::ProjectDeletedEvent do
+ where(:data, :valid) do
+ [
+ [{ project_id: 1, namespace_id: 2 }, true],
+ [{ project_id: 1 }, false],
+ [{ namespace_id: 1 }, false],
+ [{ project_id: 'foo', namespace_id: 2 }, false],
+ [{ project_id: 1, namespace_id: 'foo' }, false],
+ [{ project_id: [], namespace_id: 2 }, false],
+ [{ project_id: 1, namespace_id: [] }, false],
+ [{ project_id: {}, namespace_id: 2 }, false],
+ [{ project_id: 1, namespace_id: {} }, false],
+ ['foo', false],
+ [123, false],
+ [[], false]
+ ]
+ end
+
+ with_them do
+ it 'validates data' do
+ constructor = -> { described_class.new(data: data) }
+
+ if valid
+ expect { constructor.call }.not_to raise_error
+ else
+ expect { constructor.call }.to raise_error(Gitlab::EventStore::InvalidEvent)
+ end
+ end
+ end
+end
diff --git a/spec/features/admin/admin_mode/logout_spec.rb b/spec/features/admin/admin_mode/logout_spec.rb
index 58bea5c4b5f..f2f6e26fbee 100644
--- a/spec/features/admin/admin_mode/logout_spec.rb
+++ b/spec/features/admin/admin_mode/logout_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe 'Admin Mode Logout', :js do
it 'disable shows flash notice' do
gitlab_disable_admin_mode
- expect(page).to have_selector('.flash-notice')
+ expect(page).to have_selector('[data-testid="alert-info"]')
end
context 'on a read-only instance' do
diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb
index e6bf1ffc2f7..9612c6625f6 100644
--- a/spec/features/groups/members/leave_group_spec.rb
+++ b/spec/features/groups/members/leave_group_spec.rb
@@ -79,7 +79,7 @@ RSpec.describe 'Groups > Members > Leave group' do
visit group_path(group, leave: 1)
- expect(find('.flash-alert')).to have_content 'You do not have permission to leave this group'
+ expect(find('[data-testid="alert-danger"]')).to have_content 'You do not have permission to leave this group'
end
def left_group_message(group)
diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb
index 3ddcbf1bd01..3929d3694ff 100644
--- a/spec/features/issues/filtered_search/recent_searches_spec.rb
+++ b/spec/features/issues/filtered_search/recent_searches_spec.rb
@@ -104,7 +104,7 @@ RSpec.describe 'Recent searches', :js do
set_recent_searches(project_1_local_storage_key, 'fail')
visit project_issues_path(project_1)
- expect(find('.flash-alert')).to have_text('An error occurred while parsing recent searches')
+ expect(find('[data-testid="alert-danger"]')).to have_text('An error occurred while parsing recent searches')
end
context 'on tablet/mobile screen' do
diff --git a/spec/features/profiles/password_spec.rb b/spec/features/profiles/password_spec.rb
index 25fe43617fd..898e2c2aa59 100644
--- a/spec/features/profiles/password_spec.rb
+++ b/spec/features/profiles/password_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe 'Profile > Password' do
it 'shows a success message' do
fill_passwords(Gitlab::Password.test_default, Gitlab::Password.test_default)
- page.within('.flash-notice') do
+ page.within('[data-testid="alert-info"]') do
expect(page).to have_content('Password was successfully updated. Please sign in again.')
end
end
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index c8cbf396098..77194fd6ca1 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -984,7 +984,7 @@ RSpec.describe 'File blob', :js do
visit_blob('README.md')
expect(page).to have_selector('.file-content')
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
it 'displays a GPG badge' do
diff --git a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb
index c8a9f959188..c9fee9bee7a 100644
--- a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb
+++ b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb
@@ -21,6 +21,6 @@ RSpec.describe 'Projects > Members > Group member cannot leave group project' do
it 'renders a flash message if attempting to leave by url', :js do
visit project_path(project, leave: 1)
- expect(find('.flash-alert')).to have_content 'You do not have permission to leave this project'
+ expect(find('[data-testid="alert-danger"]')).to have_content 'You do not have permission to leave this project'
end
end
diff --git a/spec/features/projects/network_graph_spec.rb b/spec/features/projects/network_graph_spec.rb
index 4ae809399b6..1ee0ea51e53 100644
--- a/spec/features/projects/network_graph_spec.rb
+++ b/spec/features/projects/network_graph_spec.rb
@@ -96,7 +96,7 @@ RSpec.describe 'Project Network Graph', :js do
find('button').click
end
- expect(page).to have_selector '.flash-alert', text: "Git revision ';' does not exist."
+ expect(page).to have_selector '[data-testid="alert-danger"]', text: "Git revision ';' does not exist."
end
end
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index e941ad7643e..dde8bd48790 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -857,7 +857,7 @@ RSpec.describe 'Pipelines', :js do
it 'increments jobs_cache_index' do
click_button 'Clear runner caches'
wait_for_requests
- expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
+ expect(page.find('[data-testid="alert-info"]')).to have_content 'Project cache successfully reset.'
end
end
@@ -865,7 +865,7 @@ RSpec.describe 'Pipelines', :js do
it 'sets jobs_cache_index to 1' do
click_button 'Clear runner caches'
wait_for_requests
- expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
+ expect(page.find('[data-testid="alert-info"]')).to have_content 'Project cache successfully reset.'
end
end
end
diff --git a/spec/features/projects/tree/tree_show_spec.rb b/spec/features/projects/tree/tree_show_spec.rb
index f8bbaa9535b..cd94e6da018 100644
--- a/spec/features/projects/tree/tree_show_spec.rb
+++ b/spec/features/projects/tree/tree_show_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'Projects tree', :js do
expect(page).to have_selector('.tree-item')
expect(page).to have_content('add tests for .gitattributes custom highlighting')
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
expect(page).not_to have_selector('[data-qa-selector="label-lfs"]', text: 'LFS') # rubocop:disable QA/SelectorUsage
end
@@ -36,7 +36,7 @@ RSpec.describe 'Projects tree', :js do
expect(page).to have_selector('.tree-item')
expect(page).to have_content('add spaces in whitespace file')
expect(page).not_to have_selector('[data-qa-selector="label-lfs"]', text: 'LFS') # rubocop:disable QA/SelectorUsage
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
it 'renders tree table with non-ASCII filenames without errors' do
@@ -46,7 +46,7 @@ RSpec.describe 'Projects tree', :js do
expect(page).to have_selector('.tree-item')
expect(page).to have_content('Files, encoding and much more')
expect(page).to have_content('テスト.txt')
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
context "with a tree that contains pathspec characters" do
@@ -139,7 +139,7 @@ RSpec.describe 'Projects tree', :js do
wait_for_requests
expect(page).to have_selector('.tree-item')
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
context 'for signed commit' do
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 31f30075327..1049f8bc18f 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -236,7 +236,7 @@ RSpec.describe 'Project' do
it 'does not show an error' do
wait_for_requests
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
end
@@ -316,7 +316,7 @@ RSpec.describe 'Project' do
wait_for_requests
expect(page).to have_selector('.tree-item')
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
context 'for signed commit' do
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index 2ddd86dd807..1f1824c897e 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe 'Triggers', :js do
click_button 'Add trigger'
aggregate_failures 'display creation notice and trigger is created' do
- expect(page.find('.flash-notice')).to have_content 'Trigger was created successfully.'
+ expect(page.find('[data-testid="alert-info"]')).to have_content 'Trigger was created successfully.'
expect(page.find('.triggers-list')).to have_content 'trigger desc'
expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
end
@@ -63,7 +63,7 @@ RSpec.describe 'Triggers', :js do
click_button 'Save trigger'
aggregate_failures 'display update notice and trigger is updated' do
- expect(page.find('.flash-notice')).to have_content 'Trigger was successfully updated.'
+ expect(page.find('[data-testid="alert-info"]')).to have_content 'Trigger was successfully updated.'
expect(page.find('.triggers-list')).to have_content new_trigger_title
expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
end
@@ -89,7 +89,7 @@ RSpec.describe 'Triggers', :js do
end
aggregate_failures 'trigger is removed' do
- expect(page.find('.flash-notice')).to have_content 'Trigger removed'
+ expect(page.find('[data-testid="alert-info"]')).to have_content 'Trigger removed'
expect(page).to have_css('[data-testid="no_triggers_content"]')
end
end
diff --git a/spec/features/users/logout_spec.rb b/spec/features/users/logout_spec.rb
index ffb8785b277..3129eb5e6f3 100644
--- a/spec/features/users/logout_spec.rb
+++ b/spec/features/users/logout_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe 'Logout/Sign out', :js do
it 'sign out does not show signed out flash notice' do
gitlab_sign_out
- expect(page).not_to have_selector('.flash-notice')
+ expect(page).not_to have_selector('[data-testid="alert-info"]')
end
context 'on a read-only instance' do
diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js
index 493a96c207b..03ae437a89e 100644
--- a/spec/frontend/error_tracking/components/error_details_spec.js
+++ b/spec/frontend/error_tracking/components/error_details_spec.js
@@ -583,33 +583,25 @@ describe('ErrorDetails', () => {
expect(Tracking.event).toHaveBeenCalledWith(category, action);
});
- it('should track IGNORE status update', () => {
+ it('should track IGNORE status update', async () => {
Tracking.event.mockClear();
- findUpdateIgnoreStatusButton().vm.$emit('click');
- setImmediate(() => {
- const { category, action } = trackErrorStatusUpdateOptions('ignored');
- expect(Tracking.event).toHaveBeenCalledWith(category, action);
- });
+ await findUpdateIgnoreStatusButton().trigger('click');
+ const { category, action } = trackErrorStatusUpdateOptions('ignored');
+ expect(Tracking.event).toHaveBeenCalledWith(category, action);
});
- it('should track RESOLVE status update', () => {
+ it('should track RESOLVE status update', async () => {
Tracking.event.mockClear();
- findUpdateResolveStatusButton().vm.$emit('click');
- setImmediate(() => {
- const { category, action } = trackErrorStatusUpdateOptions('resolved');
- expect(Tracking.event).toHaveBeenCalledWith(category, action);
- });
+ await findUpdateResolveStatusButton().trigger('click');
+ const { category, action } = trackErrorStatusUpdateOptions('resolved');
+ expect(Tracking.event).toHaveBeenCalledWith(category, action);
});
- it('should track external Sentry link views', () => {
+ it('should track external Sentry link views', async () => {
Tracking.event.mockClear();
- findExternalUrl().trigger('click');
- setImmediate(() => {
- const { category, action, label, property } = trackClickErrorLinkToSentryOptions(
- externalUrl,
- );
- expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property });
- });
+ await findExternalUrl().trigger('click');
+ const { category, action, label, property } = trackClickErrorLinkToSentryOptions(externalUrl);
+ expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property });
});
});
});
diff --git a/spec/frontend/error_tracking/components/error_tracking_list_spec.js b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
index d4d145b5840..59671c175e7 100644
--- a/spec/frontend/error_tracking/components/error_tracking_list_spec.js
+++ b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
@@ -447,7 +447,7 @@ describe('ErrorTrackingList', () => {
expect(Tracking.event).toHaveBeenCalledWith(category, action);
});
- it('should track status updates', () => {
+ it('should track status updates', async () => {
Tracking.event.mockClear();
const status = 'ignored';
findErrorActions().vm.$emit('update-issue-status', {
@@ -455,10 +455,10 @@ describe('ErrorTrackingList', () => {
status,
});
- setImmediate(() => {
- const { category, action } = trackErrorStatusUpdateOptions(status);
- expect(Tracking.event).toHaveBeenCalledWith(category, action);
- });
+ await nextTick();
+
+ const { category, action } = trackErrorStatusUpdateOptions(status);
+ expect(Tracking.event).toHaveBeenCalledWith(category, action);
});
});
});
diff --git a/spec/frontend/feature_flags/components/feature_flags_spec.js b/spec/frontend/feature_flags/components/feature_flags_spec.js
index 728c6abb23a..d27b23c5cd1 100644
--- a/spec/frontend/feature_flags/components/feature_flags_spec.js
+++ b/spec/frontend/feature_flags/components/feature_flags_spec.js
@@ -71,12 +71,12 @@ describe('Feature flags', () => {
describe('when limit exceeded', () => {
const provideData = { ...mockData, featureFlagsLimitExceeded: true };
- beforeEach((done) => {
+ beforeEach(() => {
mock
.onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } })
.reply(200, getRequestData, {});
factory(provideData);
- setImmediate(done);
+ return waitForPromises();
});
it('makes the new feature flag button do nothing if clicked', () => {
@@ -116,12 +116,12 @@ describe('Feature flags', () => {
userListPath: null,
};
- beforeEach((done) => {
+ beforeEach(() => {
mock
.onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } })
.reply(200, getRequestData, {});
factory(provideData);
- setImmediate(done);
+ return waitForPromises();
});
it('does not render configure button', () => {
@@ -202,7 +202,7 @@ describe('Feature flags', () => {
});
describe('with paginated feature flags', () => {
- beforeEach((done) => {
+ beforeEach(() => {
mock.onGet(mockState.endpoint, { params: { page: '1' } }).replyOnce(200, getRequestData, {
'x-next-page': '2',
'x-page': '1',
@@ -214,7 +214,7 @@ describe('Feature flags', () => {
factory();
jest.spyOn(store, 'dispatch');
- setImmediate(done);
+ return waitForPromises();
});
it('should render a table with feature flags', () => {
@@ -270,11 +270,11 @@ describe('Feature flags', () => {
});
describe('unsuccessful request', () => {
- beforeEach((done) => {
+ beforeEach(() => {
mock.onGet(mockState.endpoint, { params: { page: '1' } }).replyOnce(500, {});
factory();
- setImmediate(done);
+ return waitForPromises();
});
it('should render error state', () => {
@@ -300,12 +300,12 @@ describe('Feature flags', () => {
});
describe('rotate instance id', () => {
- beforeEach((done) => {
+ beforeEach(() => {
mock
.onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } })
.reply(200, getRequestData, {});
factory();
- setImmediate(done);
+ return waitForPromises();
});
it('should fire the rotate action when a `token` event is received', () => {
diff --git a/spec/frontend/filtered_search/filtered_search_visual_tokens_spec.js b/spec/frontend/filtered_search/filtered_search_visual_tokens_spec.js
index 44f67f269a2..c4e125e96da 100644
--- a/spec/frontend/filtered_search/filtered_search_visual_tokens_spec.js
+++ b/spec/frontend/filtered_search/filtered_search_visual_tokens_spec.js
@@ -1,6 +1,7 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import FilteredSearchSpecHelper from 'helpers/filtered_search_spec_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import FilteredSearchVisualTokens from '~/filtered_search/filtered_search_visual_tokens';
describe('Filtered Search Visual Tokens', () => {
@@ -715,18 +716,16 @@ describe('Filtered Search Visual Tokens', () => {
`);
});
- it('renders a author token value element', () => {
+ it('renders a author token value element', async () => {
const { tokenNameElement, tokenValueElement } = findElements(authorToken);
const tokenName = tokenNameElement.textContent;
const tokenValue = 'new value';
subject.renderVisualTokenValue(authorToken, tokenName, tokenValue);
- jest.runOnlyPendingTimers();
+ await waitForPromises();
- setImmediate(() => {
- expect(tokenValueElement.textContent).toBe(tokenValue);
- });
+ expect(tokenValueElement.textContent).toBe(tokenValue);
});
});
});
diff --git a/spec/frontend/flash_spec.js b/spec/frontend/flash_spec.js
index d5451ec2064..942e2c330fa 100644
--- a/spec/frontend/flash_spec.js
+++ b/spec/frontend/flash_spec.js
@@ -517,16 +517,12 @@ describe('Flash', () => {
`;
});
- it('removes global flash on click', (done) => {
+ it('removes global flash on click', () => {
addDismissFlashClickListener(el, false);
el.querySelector('.js-close-icon').click();
- setImmediate(() => {
- expect(document.querySelector('.flash')).toBeNull();
-
- done();
- });
+ expect(document.querySelector('.flash')).toBeNull();
});
});
diff --git a/spec/frontend/gl_form_spec.js b/spec/frontend/gl_form_spec.js
index 07487fbb60e..ab5627ce216 100644
--- a/spec/frontend/gl_form_spec.js
+++ b/spec/frontend/gl_form_spec.js
@@ -8,7 +8,7 @@ describe('GLForm', () => {
const testContext = {};
describe('when instantiated', () => {
- beforeEach((done) => {
+ beforeEach(() => {
window.gl = window.gl || {};
testContext.form = $('<form class="gfm-form"><textarea class="js-gfm-input"></form>');
@@ -18,22 +18,11 @@ describe('GLForm', () => {
jest.spyOn($.prototype, 'css').mockImplementation(() => {});
testContext.glForm = new GLForm(testContext.form, false);
-
- setImmediate(() => {
- $.prototype.off.mockClear();
- $.prototype.on.mockClear();
- $.prototype.css.mockClear();
- done();
- });
});
describe('setupAutosize', () => {
- beforeEach((done) => {
+ beforeEach(() => {
testContext.glForm.setupAutosize();
-
- setImmediate(() => {
- done();
- });
});
it('should register an autosize event handler on the textarea', () => {
diff --git a/spec/frontend/ide/components/commit_sidebar/list_item_spec.js b/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
index 78810da7f2c..dea920ecb5e 100644
--- a/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
@@ -1,5 +1,6 @@
import Vue, { nextTick } from 'vue';
import { trimText } from 'helpers/text_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
import listItem from '~/ide/components/commit_sidebar/list_item.vue';
import { createRouter } from '~/ide/ide_router';
@@ -55,32 +56,28 @@ describe('Multi-file editor commit sidebar list item', () => {
expect(findPathText()).toEqual(f.name);
});
- it('opens a closed file in the editor when clicking the file path', (done) => {
+ it('opens a closed file in the editor when clicking the file path', async () => {
jest.spyOn(vm, 'openPendingTab');
jest.spyOn(router, 'push').mockImplementation(() => {});
findPathEl.click();
- setImmediate(() => {
- expect(vm.openPendingTab).toHaveBeenCalled();
- expect(router.push).toHaveBeenCalled();
+ await nextTick();
- done();
- });
+ expect(vm.openPendingTab).toHaveBeenCalled();
+ expect(router.push).toHaveBeenCalled();
});
- it('calls updateViewer with diff when clicking file', (done) => {
+ it('calls updateViewer with diff when clicking file', async () => {
jest.spyOn(vm, 'openFileInEditor');
jest.spyOn(vm, 'updateViewer');
jest.spyOn(router, 'push').mockImplementation(() => {});
findPathEl.click();
- setImmediate(() => {
- expect(vm.updateViewer).toHaveBeenCalledWith('diff');
+ await waitForPromises();
- done();
- });
+ expect(vm.updateViewer).toHaveBeenCalledWith('diff');
});
describe('computed', () => {
diff --git a/spec/frontend/pipeline_wizard/components/editor_spec.js b/spec/frontend/pipeline_wizard/components/editor_spec.js
new file mode 100644
index 00000000000..446412a4f02
--- /dev/null
+++ b/spec/frontend/pipeline_wizard/components/editor_spec.js
@@ -0,0 +1,69 @@
+import { mount } from '@vue/test-utils';
+import { Document } from 'yaml';
+import YamlEditor from '~/pipeline_wizard/components/editor.vue';
+
+describe('Pages Yaml Editor wrapper', () => {
+ const defaultOptions = {
+ propsData: { doc: new Document({ foo: 'bar' }), filename: 'foo.yml' },
+ };
+
+ describe('mount hook', () => {
+ const wrapper = mount(YamlEditor, defaultOptions);
+
+ it('editor is mounted', () => {
+ expect(wrapper.vm.editor).not.toBeFalsy();
+ expect(wrapper.find('.gl-source-editor').exists()).toBe(true);
+ });
+ });
+
+ describe('watchers', () => {
+ describe('doc', () => {
+ const doc = new Document({ baz: ['bar'] });
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = mount(YamlEditor, defaultOptions);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it("causes the editor's value to be set to the stringified document", async () => {
+ await wrapper.setProps({ doc });
+ expect(wrapper.vm.editor.getValue()).toEqual(doc.toString());
+ });
+
+ it('emits an update:yaml event with the yaml representation of doc', async () => {
+ await wrapper.setProps({ doc });
+ const changeEvents = wrapper.emitted('update:yaml');
+ expect(changeEvents[2]).toEqual([doc.toString()]);
+ });
+
+ it('does not cause the touch event to be emitted', () => {
+ wrapper.setProps({ doc });
+ expect(wrapper.emitted('touch')).not.toBeTruthy();
+ });
+ });
+
+ describe('highlight', () => {
+ const highlight = 'foo';
+ const wrapper = mount(YamlEditor, defaultOptions);
+
+ it('calls editor.highlight(path, keep=true)', async () => {
+ const highlightSpy = jest.spyOn(wrapper.vm.yamlEditorExtension.obj, 'highlight');
+ await wrapper.setProps({ highlight });
+ expect(highlightSpy).toHaveBeenCalledWith(expect.anything(), highlight, true);
+ });
+ });
+ });
+
+ describe('events', () => {
+ const wrapper = mount(YamlEditor, defaultOptions);
+
+ it('emits touch if content is changed in editor', async () => {
+ await wrapper.vm.editor.setValue('foo: boo');
+ expect(wrapper.emitted('touch')).toBeTruthy();
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js b/spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js
index 1ff98d4aec5..663ebd3e12f 100644
--- a/spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js
+++ b/spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js
@@ -2,16 +2,20 @@ import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { HIGHLIGHT_CLASS_NAME } from '~/vue_shared/components/blob_viewers/constants';
import SimpleViewer from '~/vue_shared/components/blob_viewers/simple_viewer.vue';
+import LineHighlighter from '~/blob/line_highlighter';
+
+jest.mock('~/blob/line_highlighter');
describe('Blob Simple Viewer component', () => {
let wrapper;
const contentMock = `<span id="LC1">First</span>\n<span id="LC2">Second</span>\n<span id="LC3">Third</span>`;
const blobHash = 'foo-bar';
- function createComponent(content = contentMock, isRawContent = false) {
+ function createComponent(content = contentMock, isRawContent = false, glFeatures = {}) {
wrapper = shallowMount(SimpleViewer, {
provide: {
blobHash,
+ glFeatures,
},
propsData: {
content,
@@ -26,6 +30,20 @@ describe('Blob Simple Viewer component', () => {
wrapper.destroy();
});
+ describe('refactorBlobViewer feature flag', () => {
+ it('loads the LineHighlighter if refactorBlobViewer is enabled', () => {
+ createComponent('', false, { refactorBlobViewer: true });
+
+ expect(LineHighlighter).toHaveBeenCalled();
+ });
+
+ it('does not load the LineHighlighter if refactorBlobViewer is disabled', () => {
+ createComponent('', false, { refactorBlobViewer: false });
+
+ expect(LineHighlighter).not.toHaveBeenCalled();
+ });
+ });
+
it('does not fail if content is empty', () => {
const spy = jest.spyOn(window.console, 'error');
createComponent('');
diff --git a/spec/frontend/vue_shared/components/confirm_fork_modal_spec.js b/spec/frontend/vue_shared/components/confirm_fork_modal_spec.js
new file mode 100644
index 00000000000..1cde92cf522
--- /dev/null
+++ b/spec/frontend/vue_shared/components/confirm_fork_modal_spec.js
@@ -0,0 +1,80 @@
+import { GlModal } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ConfirmForkModal, { i18n } from '~/vue_shared/components/confirm_fork_modal.vue';
+
+describe('vue_shared/components/confirm_fork_modal', () => {
+ let wrapper = null;
+
+ const forkPath = '/fake/fork/path';
+ const modalId = 'confirm-fork-modal';
+ const defaultProps = { modalId, forkPath };
+
+ const findModal = () => wrapper.findComponent(GlModal);
+ const findModalProp = (prop) => findModal().props(prop);
+ const findModalActionProps = () => findModalProp('actionPrimary');
+
+ const createComponent = (props = {}) =>
+ shallowMountExtended(ConfirmForkModal, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('visible = false', () => {
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ it('sets the visible prop to `false`', () => {
+ expect(findModalProp('visible')).toBe(false);
+ });
+
+ it('sets the modal title', () => {
+ const title = findModalProp('title');
+ expect(title).toBe(i18n.title);
+ });
+
+ it('sets the modal id', () => {
+ const fakeModalId = findModalProp('modalId');
+ expect(fakeModalId).toBe(modalId);
+ });
+
+ it('has the fork path button', () => {
+ const modalProps = findModalActionProps();
+ expect(modalProps.text).toBe(i18n.btnText);
+ expect(modalProps.attributes.variant).toBe('confirm');
+ });
+
+ it('sets the correct fork path', () => {
+ const modalProps = findModalActionProps();
+ expect(modalProps.attributes.href).toBe(forkPath);
+ });
+
+ it('has the fork message', () => {
+ expect(findModal().text()).toContain(i18n.message);
+ });
+ });
+
+ describe('visible = true', () => {
+ beforeEach(() => {
+ wrapper = createComponent({ visible: true });
+ });
+
+ it('sets the visible prop to `true`', () => {
+ expect(findModalProp('visible')).toBe(true);
+ });
+
+ it('emits the `change` event if the modal is hidden', () => {
+ expect(wrapper.emitted('change')).toBeUndefined();
+
+ findModal().vm.$emit('change', false);
+
+ expect(wrapper.emitted('change')).toEqual([[false]]);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/web_ide_link_spec.js b/spec/frontend/vue_shared/components/web_ide_link_spec.js
index 9b7c594b910..5589cbfd08f 100644
--- a/spec/frontend/vue_shared/components/web_ide_link_spec.js
+++ b/spec/frontend/vue_shared/components/web_ide_link_spec.js
@@ -4,6 +4,7 @@ import { nextTick } from 'vue';
import ActionsButton from '~/vue_shared/components/actions_button.vue';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
+import ConfirmForkModal from '~/vue_shared/components/confirm_fork_modal.vue';
import { stubComponent } from 'helpers/stub_component';
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
@@ -13,6 +14,7 @@ const TEST_WEB_IDE_URL = '/-/ide/project/gitlab-test/test/edit/main/-/';
const TEST_GITPOD_URL = 'https://gitpod.test/';
const TEST_USER_PREFERENCES_GITPOD_PATH = '/-/profile/preferences#user_gitpod_enabled';
const TEST_USER_PROFILE_ENABLE_GITPOD_PATH = '/-/profile?user%5Bgitpod_enabled%5D=true';
+const forkPath = '/some/fork/path';
const ACTION_EDIT = {
href: TEST_EDIT_URL,
@@ -74,6 +76,7 @@ describe('Web IDE link component', () => {
editUrl: TEST_EDIT_URL,
webIdeUrl: TEST_WEB_IDE_URL,
gitpodUrl: TEST_GITPOD_URL,
+ forkPath,
...props,
},
stubs: {
@@ -96,6 +99,7 @@ describe('Web IDE link component', () => {
const findActionsButton = () => wrapper.find(ActionsButton);
const findLocalStorageSync = () => wrapper.find(LocalStorageSync);
const findModal = () => wrapper.findComponent(GlModal);
+ const findForkConfirmModal = () => wrapper.findComponent(ConfirmForkModal);
it.each([
{
@@ -231,16 +235,28 @@ describe('Web IDE link component', () => {
});
describe('edit actions', () => {
- it.each([
+ const testActions = [
{
- props: { showWebIdeButton: true, showEditButton: false },
+ props: {
+ showWebIdeButton: true,
+ showEditButton: false,
+ forkPath,
+ forkModalId: 'edit-modal',
+ },
expectedEventPayload: 'ide',
},
{
- props: { showWebIdeButton: false, showEditButton: true },
+ props: {
+ showWebIdeButton: false,
+ showEditButton: true,
+ forkPath,
+ forkModalId: 'webide-modal',
+ },
expectedEventPayload: 'simple',
},
- ])(
+ ];
+
+ it.each(testActions)(
'emits the correct event when an action handler is called',
async ({ props, expectedEventPayload }) => {
createComponent({ ...props, needsToFork: true, disableForkModal: true });
@@ -250,6 +266,29 @@ describe('Web IDE link component', () => {
expect(wrapper.emitted('edit')).toEqual([[expectedEventPayload]]);
},
);
+
+ it.each(testActions)('renders the fork confirmation modal', async ({ props }) => {
+ createComponent({ ...props, needsToFork: true });
+
+ expect(findForkConfirmModal().exists()).toBe(true);
+ expect(findForkConfirmModal().props()).toEqual({
+ visible: false,
+ forkPath,
+ modalId: props.forkModalId,
+ });
+ });
+
+ it.each(testActions)('opens the modal when the button is clicked', async ({ props }) => {
+ createComponent({ ...props, needsToFork: true }, mountExtended);
+
+ await findActionsButton().trigger('click');
+
+ expect(findForkConfirmModal().props()).toEqual({
+ visible: true,
+ forkPath,
+ modalId: props.forkModalId,
+ });
+ });
});
describe('when Gitpod is not enabled', () => {
diff --git a/spec/lib/gitlab/changelog/release_spec.rb b/spec/lib/gitlab/changelog/release_spec.rb
index d8434821640..defcec5aa65 100644
--- a/spec/lib/gitlab/changelog/release_spec.rb
+++ b/spec/lib/gitlab/changelog/release_spec.rb
@@ -139,6 +139,16 @@ RSpec.describe Gitlab::Changelog::Release do
OUT
end
end
+
+ context 'when template parser raises an error' do
+ before do
+ allow(config).to receive(:template).and_raise(Gitlab::TemplateParser::Error)
+ end
+
+ it 'raises a Changelog error' do
+ expect { release.to_markdown }.to raise_error(Gitlab::Changelog::Error)
+ end
+ end
end
describe '#header_start_position' do
diff --git a/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb
index bcc99b78805..b657f73fa77 100644
--- a/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb
@@ -66,6 +66,11 @@ RSpec.describe 'Jobs/Deploy.gitlab-ci.yml' do
expect(build_names).not_to include('review')
end
+ it 'when CI_DEPLOY_FREEZE is present' do
+ create(:ci_variable, project: project, key: 'CI_DEPLOY_FREEZE', value: 'true')
+ expect(build_names).to eq %w(placeholder)
+ end
+
it 'when CANARY_ENABLED' do
create(:ci_variable, project: project, key: 'CANARY_ENABLED', value: 'true')
diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb
index abb8948f13a..73bc4a5d1f3 100644
--- a/spec/requests/api/lint_spec.rb
+++ b/spec/requests/api/lint_spec.rb
@@ -110,7 +110,7 @@ RSpec.describe API::Lint do
context 'when authenticated' do
let_it_be(:api_user) { create(:user) }
- context 'with valid .gitlab-ci.yaml content' do
+ context 'with valid .gitlab-ci.yml content' do
let(:yaml_content) do
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
end
@@ -140,7 +140,7 @@ RSpec.describe API::Lint do
end
end
- context 'with valid .gitlab-ci.yaml with warnings' do
+ context 'with valid .gitlab-ci.yml with warnings' do
let(:yaml_content) { { job: { script: 'ls', rules: [{ when: 'always' }] } }.to_yaml }
it 'passes validation but returns warnings' do
@@ -153,7 +153,7 @@ RSpec.describe API::Lint do
end
end
- context 'with valid .gitlab-ci.yaml using deprecated keywords' do
+ context 'with valid .gitlab-ci.yml using deprecated keywords' do
let(:yaml_content) { { job: { script: 'ls', type: 'test' }, types: ['test'] }.to_yaml }
it 'passes validation but returns warnings' do
@@ -166,7 +166,7 @@ RSpec.describe API::Lint do
end
end
- context 'with an invalid .gitlab_ci.yml' do
+ context 'with an invalid .gitlab-ci.yml' do
context 'with invalid syntax' do
let(:yaml_content) { 'invalid content' }
@@ -384,6 +384,15 @@ RSpec.describe API::Lint do
project.add_developer(api_user)
end
+ context 'with no commit' do
+ it 'returns error about providing content' do
+ ci_lint
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['errors']).to match_array(['Please provide content of .gitlab-ci.yml'])
+ end
+ end
+
context 'with valid .gitlab-ci.yml content' do
let(:yaml_content) do
{ include: { local: 'another-gitlab-ci.yml' }, test: { stage: 'test', script: 'echo 1' } }.to_yaml
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 623cf24b9cb..340ed7bde53 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -836,6 +836,24 @@ RSpec.describe 'Git HTTP requests' do
end
end
end
+
+ context "when the user is admin" do
+ let(:admin) { create(:admin) }
+ let(:env) { { user: admin.username, password: admin.password } }
+
+ # Currently, the admin mode is bypassed for git operations.
+ # Once the admin mode is considered for git operations, this test will fail.
+ # Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/296509
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it_behaves_like 'pulls are allowed'
+ it_behaves_like 'pushes are allowed'
+ end
+
+ context 'when admin mode is disabled' do
+ it_behaves_like 'pulls are allowed'
+ it_behaves_like 'pushes are allowed'
+ end
+ end
end
end
@@ -929,10 +947,10 @@ RSpec.describe 'Git HTTP requests' do
context 'when admin mode is disabled' do
it_behaves_like 'can download code only'
- it 'downloads from other project get status 404' do
+ it 'downloads from other project get status 403' do
clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token
- expect(response).to have_gitlab_http_status(:not_found)
+ expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
@@ -1534,10 +1552,10 @@ RSpec.describe 'Git HTTP requests' do
context 'when admin mode is disabled' do
it_behaves_like 'can download code only'
- it 'downloads from other project get status 404' do
+ it 'downloads from other project get status 403' do
clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token
- expect(response).to have_gitlab_http_status(:not_found)
+ expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index a6aa76c7e6c..0beb5157ed6 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -18,17 +18,35 @@ RSpec.describe Projects::DestroyService, :aggregate_failures do
end
shared_examples 'deleting the project' do
- before do
- # Run sidekiq immediately to check that renamed repository will be removed
+ it 'deletes the project', :sidekiq_inline do
destroy_project(project, user, {})
- end
- it 'deletes the project', :sidekiq_inline do
expect(Project.unscoped.all).not_to include(project)
expect(project.gitlab_shell.repository_exists?(project.repository_storage, path + '.git')).to be_falsey
expect(project.gitlab_shell.repository_exists?(project.repository_storage, remove_path + '.git')).to be_falsey
end
+
+ it 'publishes a ProjectDeleted event with project id and namespace id' do
+ expected_data = { project_id: project.id, namespace_id: project.namespace_id }
+ expect(Gitlab::EventStore)
+ .to receive(:publish)
+ .with(event_type(Projects::ProjectDeletedEvent).containing(expected_data))
+
+ destroy_project(project, user, {})
+ end
+
+ context 'when feature flag publish_project_deleted_event is disabled' do
+ before do
+ stub_feature_flags(publish_project_deleted_event: false)
+ end
+
+ it 'does not publish an event' do
+ expect(Gitlab::EventStore).not_to receive(:publish)
+
+ destroy_project(project, user, {})
+ end
+ end
end
shared_examples 'deleting the project with pipeline and build' do
diff --git a/spec/support/matchers/event_store.rb b/spec/support/matchers/event_store.rb
new file mode 100644
index 00000000000..96a71ae3c22
--- /dev/null
+++ b/spec/support/matchers/event_store.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+RSpec::Matchers.define :event_type do |event_class|
+ match do |actual|
+ actual.instance_of?(event_class) &&
+ actual.data == @expected_data
+ end
+
+ chain :containing do |expected_data|
+ @expected_data = expected_data
+ end
+end
diff --git a/spec/support/shared_examples/features/variable_list_shared_examples.rb b/spec/support/shared_examples/features/variable_list_shared_examples.rb
index 52451839281..c63faace6b2 100644
--- a/spec/support/shared_examples/features/variable_list_shared_examples.rb
+++ b/spec/support/shared_examples/features/variable_list_shared_examples.rb
@@ -166,7 +166,7 @@ RSpec.shared_examples 'variable list' do
wait_for_requests
expect(find('.flash-container')).to be_present
- expect(find('.flash-text').text).to have_content('Variables key (key) has already been taken')
+ expect(find('[data-testid="alert-danger"]').text).to have_content('Variables key (key) has already been taken')
end
it 'prevents a variable to be added if no values are provided when a variable is set to masked' do
diff --git a/spec/tooling/quality/test_level_spec.rb b/spec/tooling/quality/test_level_spec.rb
index 8a944a473d7..33d3a5b49b3 100644
--- a/spec/tooling/quality/test_level_spec.rb
+++ b/spec/tooling/quality/test_level_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe Quality::TestLevel do
context 'when level is unit' do
it 'returns a pattern' do
expect(subject.pattern(:unit))
- .to eq("spec/{bin,channels,config,db,dependencies,elastic,elastic_integration,experiments,factories,finders,frontend,graphql,haml_lint,helpers,initializers,javascripts,lib,metrics_server,models,policies,presenters,rack_servers,replicators,routing,rubocop,scripts,serializers,services,sidekiq,sidekiq_cluster,spam,support_specs,tasks,uploaders,validators,views,workers,tooling}{,/**/}*_spec.rb")
+ .to eq("spec/{bin,channels,config,db,dependencies,elastic,elastic_integration,experiments,events,factories,finders,frontend,graphql,haml_lint,helpers,initializers,javascripts,lib,metrics_server,models,policies,presenters,rack_servers,replicators,routing,rubocop,scripts,serializers,services,sidekiq,sidekiq_cluster,spam,support_specs,tasks,uploaders,validators,views,workers,tooling}{,/**/}*_spec.rb")
end
end
@@ -110,7 +110,7 @@ RSpec.describe Quality::TestLevel do
context 'when level is unit' do
it 'returns a regexp' do
expect(subject.regexp(:unit))
- .to eq(%r{spec/(bin|channels|config|db|dependencies|elastic|elastic_integration|experiments|factories|finders|frontend|graphql|haml_lint|helpers|initializers|javascripts|lib|metrics_server|models|policies|presenters|rack_servers|replicators|routing|rubocop|scripts|serializers|services|sidekiq|sidekiq_cluster|spam|support_specs|tasks|uploaders|validators|views|workers|tooling)})
+ .to eq(%r{spec/(bin|channels|config|db|dependencies|elastic|elastic_integration|experiments|events|factories|finders|frontend|graphql|haml_lint|helpers|initializers|javascripts|lib|metrics_server|models|policies|presenters|rack_servers|replicators|routing|rubocop|scripts|serializers|services|sidekiq|sidekiq_cluster|spam|support_specs|tasks|uploaders|validators|views|workers|tooling)})
end
end
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index a21cf3ed5f6..1cd5d23d8fc 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -349,6 +349,7 @@ RSpec.describe 'Every Sidekiq worker' do
'Namespaces::OnboardingPipelineCreatedWorker' => 3,
'Namespaces::OnboardingProgressWorker' => 3,
'Namespaces::OnboardingUserAddedWorker' => 3,
+ 'Namespaces::RefreshRootStatisticsWorker' => 3,
'Namespaces::RootStatisticsWorker' => 3,
'Namespaces::ScheduleAggregationWorker' => 3,
'NetworkPolicyMetricsWorker' => 3,
diff --git a/spec/workers/namespaces/update_root_statistics_worker_spec.rb b/spec/workers/namespaces/update_root_statistics_worker_spec.rb
new file mode 100644
index 00000000000..a525904b757
--- /dev/null
+++ b/spec/workers/namespaces/update_root_statistics_worker_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Namespaces::UpdateRootStatisticsWorker do
+ let(:namespace_id) { 123 }
+
+ let(:event) do
+ Projects::ProjectDeletedEvent.new(data: { project_id: 1, namespace_id: namespace_id })
+ end
+
+ subject { consume_event(event) }
+
+ def consume_event(event)
+ described_class.new.perform(event.class.name, event.data)
+ end
+
+ it 'enqueues ScheduleAggregationWorker' do
+ expect(Namespaces::ScheduleAggregationWorker).to receive(:perform_async).with(namespace_id)
+
+ subject
+ end
+end