Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-06-20 00:10:01 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-06-20 00:10:01 +0300
commit7361375554b55ca52e0282bbe6cd063e2848bc2b (patch)
tree17a82da8e5ecd722da643554d521900d7e60f29b /spec
parent2f00709f337c76982dfe69cbc62dc3cb148131f2 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/vue_shared/alert_details/alert_status_spec.js120
-rw-r--r--spec/lib/gitlab/i18n/pluralization_spec.rb1
-rw-r--r--spec/rubocop/cop/background_migration/avoid_silent_rescue_exceptions_spec.rb107
3 files changed, 170 insertions, 58 deletions
diff --git a/spec/frontend/vue_shared/alert_details/alert_status_spec.js b/spec/frontend/vue_shared/alert_details/alert_status_spec.js
index 98cb2f5cb0b..90d29f0bfd4 100644
--- a/spec/frontend/vue_shared/alert_details/alert_status_spec.js
+++ b/spec/frontend/vue_shared/alert_details/alert_status_spec.js
@@ -1,7 +1,9 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
+import createMockApollo from 'helpers/mock_apollo_helper';
import updateAlertStatusMutation from '~/graphql_shared//mutations/alert_status_update.mutation.graphql';
import Tracking from '~/tracking';
import AlertManagementStatus from '~/vue_shared/alert_details/components/alert_status.vue';
@@ -11,6 +13,27 @@ const mockAlert = mockAlerts[0];
describe('AlertManagementStatus', () => {
let wrapper;
+ let requestHandler;
+
+ const iid = '1527542';
+ const mockUpdatedMutationResult = ({ errors = [], nodes = [] } = {}) =>
+ jest.fn().mockResolvedValue({
+ data: {
+ updateAlertStatus: {
+ errors,
+ alert: {
+ id: '1',
+ iid,
+ status: 'acknowledged',
+ endedAt: 'endedAt',
+ notes: {
+ nodes,
+ },
+ },
+ },
+ },
+ });
+
const findStatusDropdown = () => wrapper.findComponent(GlDropdown);
const findFirstStatusOption = () => findStatusDropdown().findComponent(GlDropdownItem);
const findAllStatusOptions = () => findStatusDropdown().findAllComponents(GlDropdownItem);
@@ -22,8 +45,20 @@ describe('AlertManagementStatus', () => {
return waitForPromises();
};
- function mountComponent({ props = {}, provide = {}, loading = false, stubs = {} } = {}) {
+ const createMockApolloProvider = (handler) => {
+ Vue.use(VueApollo);
+ requestHandler = handler;
+
+ return createMockApollo([[updateAlertStatusMutation, handler]]);
+ };
+
+ function mountComponent({
+ props = {},
+ provide = {},
+ handler = mockUpdatedMutationResult(),
+ } = {}) {
wrapper = shallowMountExtended(AlertManagementStatus, {
+ apolloProvider: createMockApolloProvider(handler),
propsData: {
alert: { ...mockAlert },
projectPath: 'gitlab-org/gitlab',
@@ -31,17 +66,6 @@ describe('AlertManagementStatus', () => {
...props,
},
provide,
- mocks: {
- $apollo: {
- mutate: jest.fn(),
- queries: {
- alert: {
- loading,
- },
- },
- },
- },
- stubs,
});
}
@@ -63,43 +87,32 @@ describe('AlertManagementStatus', () => {
});
describe('updating the alert status', () => {
- const iid = '1527542';
- const mockUpdatedMutationResult = {
- data: {
- updateAlertStatus: {
- errors: [],
- alert: {
- iid,
- status: 'acknowledged',
- },
- },
- },
- };
-
beforeEach(() => {
- mountComponent({});
+ mountComponent();
});
- it('calls `$apollo.mutate` with `updateAlertStatus` mutation and variables containing `iid`, `status`, & `projectPath`', () => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationResult);
+ it('calls `$apollo.mutate` with `updateAlertStatus` mutation and variables containing `iid`, `status`, & `projectPath`', async () => {
findFirstStatusOption().vm.$emit('click');
+ await waitForPromises();
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: updateAlertStatusMutation,
- variables: {
- iid,
- status: 'TRIGGERED',
- projectPath: 'gitlab-org/gitlab',
- },
+ expect(requestHandler).toHaveBeenCalledWith({
+ iid,
+ status: 'TRIGGERED',
+ projectPath: 'gitlab-org/gitlab',
});
});
describe('when a request fails', () => {
- beforeEach(() => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error()));
+ beforeEach(async () => {
+ mountComponent({
+ handler: mockUpdatedMutationResult({ errors: ['<span data-testid="htmlError" />'] }),
+ });
+ await waitForPromises();
});
it('emits an error', async () => {
+ mountComponent({ handler: jest.fn().mockRejectedValue({}) });
+ await waitForPromises();
await selectFirstStatusOption();
expect(wrapper.emitted('alert-error')[0]).toEqual([
@@ -116,7 +129,6 @@ describe('AlertManagementStatus', () => {
it('emits an error when triggered a second time', async () => {
await selectFirstStatusOption();
- await nextTick();
await selectFirstStatusOption();
// Should emit two errors [0,1]
expect(wrapper.emitted('alert-error').length > 1).toBe(true);
@@ -124,19 +136,9 @@ describe('AlertManagementStatus', () => {
});
it('shows an error when response includes HTML errors', async () => {
- const mockUpdatedMutationErrorResult = {
- data: {
- updateAlertStatus: {
- errors: ['<span data-testid="htmlError" />'],
- alert: {
- iid,
- status: 'acknowledged',
- },
- },
- },
- };
-
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationErrorResult);
+ mountComponent({
+ handler: mockUpdatedMutationResult({ errors: ['<span data-testid="htmlError" />'] }),
+ });
await selectFirstStatusOption();
@@ -160,7 +162,7 @@ describe('AlertManagementStatus', () => {
mountComponent({
props: { alert: { ...mockAlert, status }, statuses: { [status]: translatedStatus } },
});
- expect(findAllStatusOptions().length).toBe(1);
+ expect(findAllStatusOptions()).toHaveLength(1);
expect(findFirstStatusOption().text()).toBe(translatedStatus);
});
});
@@ -173,10 +175,10 @@ describe('AlertManagementStatus', () => {
it('should not track alert status updates when the tracking options do not exist', async () => {
mountComponent({});
Tracking.event.mockClear();
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({});
+
findFirstStatusOption().vm.$emit('click');
- await nextTick();
+ await waitForPromises();
expect(Tracking.event).not.toHaveBeenCalled();
});
@@ -187,12 +189,14 @@ describe('AlertManagementStatus', () => {
action: 'update_alert_status',
label: 'Status',
};
- mountComponent({ provide: { trackAlertStatusUpdateOptions } });
+ mountComponent({
+ provide: { trackAlertStatusUpdateOptions },
+ handler: mockUpdatedMutationResult({ nodes: mockAlerts }),
+ });
Tracking.event.mockClear();
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({});
findFirstStatusOption().vm.$emit('click');
- await nextTick();
+ await waitForPromises();
const status = findFirstStatusOption().text();
const { category, action, label } = trackAlertStatusUpdateOptions;
diff --git a/spec/lib/gitlab/i18n/pluralization_spec.rb b/spec/lib/gitlab/i18n/pluralization_spec.rb
index 857562d549c..6bfc500c8b8 100644
--- a/spec/lib/gitlab/i18n/pluralization_spec.rb
+++ b/spec/lib/gitlab/i18n/pluralization_spec.rb
@@ -2,6 +2,7 @@
require 'fast_spec_helper'
require 'rspec-parameterized'
+require 'rails/version'
require 'gettext_i18n_rails'
RSpec.describe Gitlab::I18n::Pluralization, feature_category: :internationalization do
diff --git a/spec/rubocop/cop/background_migration/avoid_silent_rescue_exceptions_spec.rb b/spec/rubocop/cop/background_migration/avoid_silent_rescue_exceptions_spec.rb
new file mode 100644
index 00000000000..ea4f7d5fca8
--- /dev/null
+++ b/spec/rubocop/cop/background_migration/avoid_silent_rescue_exceptions_spec.rb
@@ -0,0 +1,107 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+require_relative '../../../../rubocop/cop/background_migration/avoid_silent_rescue_exceptions'
+
+RSpec.describe RuboCop::Cop::BackgroundMigration::AvoidSilentRescueExceptions, feature_category: :database do
+ shared_examples 'expecting offense when' do |node|
+ it 'throws offense when rescuing exceptions without re-raising them' do
+ %w[Gitlab::BackgroundMigration::BatchedMigrationJob BatchedMigrationJob].each do |base_class|
+ expect_offense(<<~RUBY)
+ module Gitlab
+ module BackgroundMigration
+ class MyJob < #{base_class}
+ #{node}
+ end
+ end
+ end
+ RUBY
+ end
+ end
+ end
+
+ shared_examples 'not expecting offense when' do |node|
+ it 'does not throw any offense if exception is re-raised' do
+ %w[Gitlab::BackgroundMigration::BatchedMigrationJob BatchedMigrationJob].each do |base_class|
+ expect_no_offenses(<<~RUBY)
+ module Gitlab
+ module BackgroundMigration
+ class MyJob < #{base_class}
+ #{node}
+ end
+ end
+ end
+ RUBY
+ end
+ end
+ end
+
+ context "when the migration class doesn't inherits from BatchedMigrationJob" do
+ it 'does not throw any offense' do
+ expect_no_offenses(<<~RUBY)
+ module Gitlab
+ module BackgroundMigration
+ class MyClass < ::Gitlab::BackgroundMigration::Logger
+ def my_method
+ execute
+ rescue StandardError => error
+ puts error.message
+ end
+ end
+ end
+ end
+ RUBY
+ end
+ end
+
+ context 'when the migration class inherits from BatchedMigrationJob' do
+ context 'when specifying an error class' do
+ it_behaves_like 'expecting offense when', <<~RUBY
+ def perform
+ connection.execute('SELECT 1;')
+ rescue JSON::ParserError
+ ^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::MSG}
+ logger.error(message: error.message, class: self.class.name)
+ end
+ RUBY
+
+ it_behaves_like 'expecting offense when', <<~RUBY
+ def perform
+ connection.execute('SELECT 1;')
+ rescue StandardError, ActiveRecord::StatementTimeout => error
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::MSG}
+ logger.error(message: error.message, class: self.class.name)
+ end
+ RUBY
+
+ it_behaves_like 'not expecting offense when', <<~RUBY
+ def perform
+ connection.execute('SELECT 1;')
+ rescue StandardError, ActiveRecord::StatementTimeout => error
+ logger.error(message: error.message, class: self.class.name)
+ raise error
+ end
+ RUBY
+ end
+
+ context 'without specifying an error class' do
+ it_behaves_like 'expecting offense when', <<~RUBY
+ def perform
+ connection.execute('SELECT 1;')
+ rescue => error
+ ^^^^^^ #{described_class::MSG}
+ logger.error(message: error.message, class: self.class.name)
+ end
+ RUBY
+
+ it_behaves_like 'not expecting offense when', <<~RUBY
+ def perform
+ connection.execute('SELECT 1;')
+ rescue => error
+ logger.error(message: error.message, class: self.class.name)
+ raise error
+ end
+ RUBY
+ end
+ end
+end