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-19 18:09:36 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-06-19 18:09:36 +0300
commit8bb837c4d180720d4d923ef2e7bd2c9a46ca97a0 (patch)
tree7dcb166661ba29fb6cd5935f0db34eee6c935388 /spec
parenteef2437c0a359ec3437d31d1b1ea959e54c71458 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/contracts/provider/spec_helper.rb2
-rw-r--r--spec/fast_spec_helper.rb1
-rw-r--r--spec/features/groups/members/manage_groups_spec.rb4
-rw-r--r--spec/features/groups/members/manage_members_spec.rb4
-rw-r--r--spec/features/projects/members/groups_with_access_list_spec.rb4
-rw-r--r--spec/features/projects/members/manage_members_spec.rb11
-rw-r--r--spec/frontend/admin/users/components/user_actions_spec.js2
-rw-r--r--spec/frontend/error_tracking/components/error_details_spec.js37
-rw-r--r--spec/frontend/error_tracking/components/error_tracking_list_spec.js25
-rw-r--r--spec/frontend/error_tracking/components/list_mock.json38
-rw-r--r--spec/frontend/error_tracking/components/timeline_chart_spec.js94
-rw-r--r--spec/frontend/fixtures/users.rb3
-rw-r--r--spec/frontend/members/components/table/role_dropdown_spec.js96
-rw-r--r--spec/frontend/profile/components/user_achievements_spec.js9
-rw-r--r--spec/frontend/work_items/components/notes/work_item_add_note_spec.js13
-rw-r--r--spec/frontend/work_items/mock_data.js13
-rw-r--r--spec/lib/gitlab/email/handler/service_desk_handler_spec.rb119
-rw-r--r--spec/lib/gitlab/metrics/environment_spec.rb3
-rw-r--r--spec/requests/api/projects_spec.rb8
-rw-r--r--spec/scripts/generate_failed_package_and_test_mr_message_spec.rb2
-rw-r--r--spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb2
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb57
-rw-r--r--spec/support/helpers/stub_env.rb52
-rw-r--r--spec/support/rspec.rb3
-rw-r--r--spec/support/shared_contexts/email_shared_context.rb5
-rw-r--r--spec/tooling/danger/project_helper_spec.rb2
-rw-r--r--spec/tooling/lib/tooling/find_changes_spec.rb2
-rw-r--r--spec/tooling/lib/tooling/find_tests_spec.rb2
-rw-r--r--spec/tooling/lib/tooling/gettext_extractor_spec.rb2
-rw-r--r--spec/tooling/lib/tooling/predictive_tests_spec.rb2
-rw-r--r--spec/tooling/rspec_flaky/config_spec.rb2
-rw-r--r--spec/tooling/rspec_flaky/flaky_example_spec.rb2
-rw-r--r--spec/tooling/rspec_flaky/listener_spec.rb2
33 files changed, 474 insertions, 149 deletions
diff --git a/spec/contracts/provider/spec_helper.rb b/spec/contracts/provider/spec_helper.rb
index 44e4d29c18e..f1ceca16b4b 100644
--- a/spec/contracts/provider/spec_helper.rb
+++ b/spec/contracts/provider/spec_helper.rb
@@ -2,10 +2,10 @@
require 'spec_helper'
require 'zeitwerk'
+require 'gitlab/rspec/all'
require_relative 'helpers/users_helper'
require_relative('../../../ee/spec/contracts/provider/spec_helper') if Gitlab.ee?
require Rails.root.join("spec/support/helpers/rails_helpers.rb")
-require Rails.root.join("spec/support/helpers/stub_env.rb")
# Opt out of telemetry collection. We can't allow all engineers, and users who install GitLab from source, to be
# automatically enrolled in sending data on their usage without their knowledge.
diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb
index fcf0c43243f..03c8919912c 100644
--- a/spec/fast_spec_helper.rb
+++ b/spec/fast_spec_helper.rb
@@ -22,6 +22,7 @@ require_relative 'rails_autoload'
require_relative '../config/settings'
require_relative 'support/rspec'
+require_relative '../lib/gitlab'
require_relative '../lib/gitlab/utils'
require_relative '../lib/gitlab/utils/strong_memoize'
diff --git a/spec/features/groups/members/manage_groups_spec.rb b/spec/features/groups/members/manage_groups_spec.rb
index 599b31827da..87de0e2e46b 100644
--- a/spec/features/groups/members/manage_groups_spec.rb
+++ b/spec/features/groups/members/manage_groups_spec.rb
@@ -3,6 +3,7 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Manage groups', :js, feature_category: :groups_and_projects do
+ include ListboxHelpers
include Features::MembersHelpers
include Features::InviteMembersModalHelpers
include Spec::Support::Helpers::ModalHelpers
@@ -75,8 +76,7 @@ RSpec.describe 'Groups > Members > Manage groups', :js, feature_category: :group
click_groups_tab
page.within(first_row) do
- click_button('Developer')
- click_button('Maintainer')
+ select_from_listbox('Maintainer', from: 'Developer')
wait_for_requests
diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb
index 3c1425fc9ca..138031ffaac 100644
--- a/spec/features/groups/members/manage_members_spec.rb
+++ b/spec/features/groups/members/manage_members_spec.rb
@@ -3,6 +3,7 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Manage members', feature_category: :groups_and_projects do
+ include ListboxHelpers
include Features::MembersHelpers
include Features::InviteMembersModalHelpers
include Spec::Support::Helpers::ModalHelpers
@@ -35,8 +36,7 @@ RSpec.describe 'Groups > Members > Manage members', feature_category: :groups_an
visit group_group_members_path(group)
page.within(second_row) do
- click_button('Developer')
- click_button('Owner')
+ select_from_listbox('Owner', from: 'Developer')
expect(page).to have_button('Owner')
end
diff --git a/spec/features/projects/members/groups_with_access_list_spec.rb b/spec/features/projects/members/groups_with_access_list_spec.rb
index 0f80c6cb3b8..a2a04ada627 100644
--- a/spec/features/projects/members/groups_with_access_list_spec.rb
+++ b/spec/features/projects/members/groups_with_access_list_spec.rb
@@ -3,6 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Members > Groups with access list', :js, feature_category: :groups_and_projects do
+ include ListboxHelpers
include Features::MembersHelpers
include Spec::Support::Helpers::ModalHelpers
include Features::InviteMembersModalHelpers
@@ -26,8 +27,7 @@ RSpec.describe 'Projects > Members > Groups with access list', :js, feature_cate
end
it 'updates group access level' do
- click_button group_link.human_access
- click_button 'Guest'
+ select_from_listbox('Guest', from: group_link.human_access)
wait_for_requests
diff --git a/spec/features/projects/members/manage_members_spec.rb b/spec/features/projects/members/manage_members_spec.rb
index 5ae6eb83b6b..0e3ac5ff3ac 100644
--- a/spec/features/projects/members/manage_members_spec.rb
+++ b/spec/features/projects/members/manage_members_spec.rb
@@ -3,6 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Members > Manage members', :js, feature_category: :onboarding do
+ include ListboxHelpers
include Features::MembersHelpers
include Features::InviteMembersModalHelpers
include Spec::Support::Helpers::ModalHelpers
@@ -61,11 +62,8 @@ RSpec.describe 'Projects > Members > Manage members', :js, feature_category: :on
page.within find_member_row(project_developer) do
click_button('Developer')
- page.within '.dropdown-menu' do
- expect(page).not_to have_button('Owner')
- end
-
- click_button('Reporter')
+ expect_no_listbox_item('Owner')
+ select_listbox_item('Reporter')
expect(page).to have_button('Reporter')
end
@@ -87,8 +85,7 @@ RSpec.describe 'Projects > Members > Manage members', :js, feature_category: :on
visit_members_page
page.within find_member_row(project_owner) do
- click_button('Owner')
- click_button('Reporter')
+ select_from_listbox('Reporter', from: 'Owner')
expect(page).to have_button('Reporter')
end
diff --git a/spec/frontend/admin/users/components/user_actions_spec.js b/spec/frontend/admin/users/components/user_actions_spec.js
index 73d8c082bb9..69755c6142a 100644
--- a/spec/frontend/admin/users/components/user_actions_spec.js
+++ b/spec/frontend/admin/users/components/user_actions_spec.js
@@ -91,7 +91,7 @@ describe('AdminUserActions component', () => {
initComponent({ actions: [LDAP] });
});
- it('renders the LDAP dropdown item without a link', () => {
+ it('renders the LDAP dropdown footer without a link', () => {
const dropdownAction = wrapper.find(`[data-testid="${LDAP}"]`);
expect(dropdownAction.exists()).toBe(true);
expect(dropdownAction.attributes('href')).toBe(undefined);
diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js
index 92f2e62b3a7..c9238c4b636 100644
--- a/spec/frontend/error_tracking/components/error_details_spec.js
+++ b/spec/frontend/error_tracking/components/error_details_spec.js
@@ -17,6 +17,7 @@ import ErrorDetailsInfo from '~/error_tracking/components/error_details_info.vue
import { createAlert, VARIANT_WARNING } from '~/alert';
import { __ } from '~/locale';
import Tracking from '~/tracking';
+import TimelineChart from '~/error_tracking/components/timeline_chart.vue';
jest.mock('~/alert');
jest.mock('~/tracking');
@@ -159,6 +160,7 @@ describe('ErrorDetails', () => {
mocks.$apollo.queries.error.loading = false;
mountComponent();
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
error: {
@@ -183,6 +185,7 @@ describe('ErrorDetails', () => {
beforeEach(() => {
store.state.details.loadingStacktrace = false;
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
error: {
@@ -204,6 +207,7 @@ describe('ErrorDetails', () => {
describe('Badges', () => {
it('should show language and error level badges', async () => {
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
error: {
@@ -216,6 +220,7 @@ describe('ErrorDetails', () => {
it('should NOT show the badge if the tag is not present', async () => {
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
error: {
@@ -230,6 +235,7 @@ describe('ErrorDetails', () => {
'should set correct severity level variant for %s badge',
async (level) => {
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
error: {
@@ -245,6 +251,7 @@ describe('ErrorDetails', () => {
it('should fallback for ERROR severityLevelVariant when severityLevel is unknown', async () => {
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
error: {
@@ -268,6 +275,32 @@ describe('ErrorDetails', () => {
});
});
+ describe('timeline chart', () => {
+ it('should not show timeline chart if frequency data does not exist', () => {
+ expect(wrapper.findComponent(TimelineChart).exists()).toBe(false);
+ expect(wrapper.text()).not.toContain('Last 24 hours');
+ });
+
+ it('should show timeline chart', async () => {
+ const mockFrequency = [
+ [0, 1],
+ [2, 3],
+ ];
+ // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
+ // eslint-disable-next-line no-restricted-syntax
+ wrapper.setData({
+ error: {
+ frequency: mockFrequency,
+ },
+ });
+ await nextTick();
+ expect(wrapper.findComponent(TimelineChart).exists()).toBe(true);
+ expect(wrapper.findComponent(TimelineChart).props('timelineData')).toEqual(mockFrequency);
+ expect(wrapper.text()).toContain('Last 24 hours');
+ });
+ });
+
describe('Stacktrace', () => {
it('should show stacktrace', async () => {
store.state.details.loadingStacktrace = false;
@@ -402,6 +435,7 @@ describe('ErrorDetails', () => {
it('should show alert with closed issueId', async () => {
const closedIssueId = 123;
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
isAlertVisible: true,
@@ -424,6 +458,7 @@ describe('ErrorDetails', () => {
describe('is present', () => {
beforeEach(() => {
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
error: {
@@ -448,6 +483,7 @@ describe('ErrorDetails', () => {
describe('is not present', () => {
beforeEach(() => {
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
error: {
@@ -482,6 +518,7 @@ describe('ErrorDetails', () => {
beforeEach(() => {
mountComponent({ integratedErrorTrackingEnabled: integrated });
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
error: {},
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 5483500e1dd..49f365e8c60 100644
--- a/spec/frontend/error_tracking/components/error_tracking_list_spec.js
+++ b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
@@ -12,6 +12,7 @@ import Vuex from 'vuex';
import stubChildren from 'helpers/stub_children';
import ErrorTrackingActions from '~/error_tracking/components/error_tracking_actions.vue';
import ErrorTrackingList from '~/error_tracking/components/error_tracking_list.vue';
+import TimelineChart from '~/error_tracking/components/timeline_chart.vue';
import Tracking from '~/tracking';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import errorsList from './list_mock.json';
@@ -158,6 +159,30 @@ describe('ErrorTrackingList', () => {
});
});
+ describe('timeline graph', () => {
+ it('should show the timeline chart', () => {
+ findErrorListRows().wrappers.forEach((row, index) => {
+ expect(row.findComponent(TimelineChart).exists()).toBe(true);
+ const mockFrequency = errorsList[index].frequency;
+ expect(row.findComponent(TimelineChart).props('timelineData')).toEqual(mockFrequency);
+ });
+ });
+
+ it('should not show the timeline chart if frequency data does not exist', () => {
+ store.state.list.errors = errorsList.map((e) => ({ ...e, frequency: undefined }));
+ mountComponent({
+ stubs: {
+ GlTable: false,
+ GlLink: false,
+ },
+ });
+
+ findErrorListRows().wrappers.forEach((row) => {
+ expect(row.findComponent(TimelineChart).exists()).toBe(false);
+ });
+ });
+ });
+
describe('filtering', () => {
const findSearchBox = () => wrapper.findComponent(GlFormInput);
diff --git a/spec/frontend/error_tracking/components/list_mock.json b/spec/frontend/error_tracking/components/list_mock.json
index 54ae0a4c7cf..f8addef324e 100644
--- a/spec/frontend/error_tracking/components/list_mock.json
+++ b/spec/frontend/error_tracking/components/list_mock.json
@@ -7,7 +7,17 @@
"count": "52",
"firstSeen": "2019-05-30T07:21:46Z",
"lastSeen": "2019-11-06T03:21:39Z",
- "status": "unresolved"
+ "status": "unresolved",
+ "frequency": [
+ [
+ 0,
+ 1
+ ],
+ [
+ 1,
+ 2
+ ]
+ ]
},
{
"id": "2",
@@ -17,7 +27,17 @@
"count": "12",
"firstSeen": "2019-10-19T03:53:56Z",
"lastSeen": "2019-11-05T03:51:54Z",
- "status": "unresolved"
+ "status": "unresolved",
+ "frequency": [
+ [
+ 0,
+ 1
+ ],
+ [
+ 1,
+ 2
+ ]
+ ]
},
{
"id": "3",
@@ -27,6 +47,16 @@
"count": "275",
"firstSeen": "2019-02-12T07:22:36Z",
"lastSeen": "2019-10-22T03:20:48Z",
- "status": "unresolved"
+ "status": "unresolved",
+ "frequency": [
+ [
+ 0,
+ 1
+ ],
+ [
+ 1,
+ 2
+ ]
+ ]
}
-] \ No newline at end of file
+]
diff --git a/spec/frontend/error_tracking/components/timeline_chart_spec.js b/spec/frontend/error_tracking/components/timeline_chart_spec.js
new file mode 100644
index 00000000000..f864d11804c
--- /dev/null
+++ b/spec/frontend/error_tracking/components/timeline_chart_spec.js
@@ -0,0 +1,94 @@
+import { GlChart } from '@gitlab/ui/dist/charts';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import TimelineChart from '~/error_tracking/components/timeline_chart.vue';
+
+const MOCK_HEIGHT = 123;
+
+describe('TimelineChart', () => {
+ let wrapper;
+
+ function mountComponent(timelineData = []) {
+ wrapper = shallowMountExtended(TimelineChart, {
+ stubs: { GlChart: true },
+ propsData: {
+ timelineData: [...timelineData],
+ height: MOCK_HEIGHT,
+ },
+ });
+ }
+
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('renders the component', () => {
+ expect(wrapper.exists()).toBe(true);
+ });
+
+ it('does not render a chart if timelineData is missing', () => {
+ wrapper = shallowMountExtended(TimelineChart, {
+ stubs: { GlChart: true },
+ propsData: {
+ timelineData: undefined,
+ height: MOCK_HEIGHT,
+ },
+ });
+ expect(wrapper.findComponent(GlChart).exists()).toBe(false);
+ });
+
+ it('renders a gl-chart', () => {
+ expect(wrapper.findComponent(GlChart).exists()).toBe(true);
+ expect(wrapper.findComponent(GlChart).props('height')).toBe(MOCK_HEIGHT);
+ });
+
+ describe('timeline-data', () => {
+ describe.each([
+ {
+ mockItems: [
+ [1686218400, 1],
+ [1686222000, 2],
+ ],
+ expectedX: ['Jun 8, 2023 10:00am UTC', 'Jun 8, 2023 11:00am UTC'],
+ expectedY: [1, 2],
+ description: 'tuples with dates as timestamps in seconds',
+ },
+ {
+ mockItems: [
+ ['06-05-2023', 1],
+ ['06-06-2023', 2],
+ ],
+ expectedX: ['Jun 5, 2023 12:00am UTC', 'Jun 6, 2023 12:00am UTC'],
+ expectedY: [1, 2],
+ description: 'tuples with non-numeric dates',
+ },
+ {
+ mockItems: [
+ { time: 1686218400, count: 1 },
+ { time: 1686222000, count: 2 },
+ ],
+ expectedX: ['Jun 8, 2023 10:00am UTC', 'Jun 8, 2023 11:00am UTC'],
+ expectedY: [1, 2],
+ description: 'objects with dates as timestamps in seconds',
+ },
+ {
+ mockItems: [
+ { time: '06-05-2023', count: 1 },
+ { time: '06-06-2023', count: 2 },
+ ],
+ expectedX: ['Jun 5, 2023 12:00am UTC', 'Jun 6, 2023 12:00am UTC'],
+ expectedY: [1, 2],
+ description: 'objects with non-numeric dates',
+ },
+ ])('when timeline-data items are $description', ({ mockItems, expectedX, expectedY }) => {
+ it(`renders the chart correctly`, () => {
+ mountComponent(mockItems);
+
+ const chartOptions = wrapper.findComponent(GlChart).props('options');
+ const xData = chartOptions.xAxis.data;
+ const yData = chartOptions.series[0].data;
+ expect(xData).toEqual(expectedX);
+ expect(yData).toEqual(expectedY);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/fixtures/users.rb b/spec/frontend/fixtures/users.rb
index 90a6895af91..89bffea7e4c 100644
--- a/spec/frontend/fixtures/users.rb
+++ b/spec/frontend/fixtures/users.rb
@@ -42,7 +42,7 @@ RSpec.describe 'Users (JavaScript fixtures)', feature_category: :user_profile do
context 'for user achievements' do
let_it_be(:group) { create(:group, :public) }
let_it_be(:private_group) { create(:group, :private) }
- let_it_be(:achievement1) { create(:achievement, namespace: group) }
+ let_it_be(:achievement1) { create(:achievement, namespace: group, name: 'Multiple') }
let_it_be(:achievement2) { create(:achievement, namespace: group) }
let_it_be(:achievement3) { create(:achievement, namespace: group) }
let_it_be(:achievement_from_private_group) { create(:achievement, namespace: private_group) }
@@ -94,6 +94,7 @@ RSpec.describe 'Users (JavaScript fixtures)', feature_category: :user_profile do
[achievement1, achievement2, achievement3, achievement_with_avatar_and_description].each do |achievement|
create(:user_achievement, user: user, achievement: achievement)
end
+ create(:user_achievement, user: user, achievement: achievement1)
post_graphql(query, current_user: user, variables: { id: user.to_global_id })
diff --git a/spec/frontend/members/components/table/role_dropdown_spec.js b/spec/frontend/members/components/table/role_dropdown_spec.js
index 1045e3f9849..1285404fd9f 100644
--- a/spec/frontend/members/components/table/role_dropdown_spec.js
+++ b/spec/frontend/members/components/table/role_dropdown_spec.js
@@ -1,8 +1,7 @@
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import * as Sentry from '@sentry/browser';
-import { within } from '@testing-library/dom';
-import { mount, createWrapper } from '@vue/test-utils';
+import { mount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import waitForPromises from 'helpers/wait_for_promises';
@@ -55,59 +54,50 @@ describe('RoleDropdown', () => {
});
};
- const getDropdownMenu = () => within(wrapper.element).getByRole('menu');
- const getByTextInDropdownMenu = (text, options = {}) =>
- createWrapper(within(getDropdownMenu()).getByText(text, options));
- const getDropdownItemByText = (text) =>
- createWrapper(
- within(getDropdownMenu())
- .getByText(text, { selector: '[role="menuitem"] p' })
- .closest('[role="menuitem"]'),
- );
- const getCheckedDropdownItem = () =>
- wrapper
- .findAllComponents(GlDropdownItem)
- .wrappers.find((dropdownItemWrapper) => dropdownItemWrapper.props('isChecked'));
-
- const findDropdownToggle = () => wrapper.find('button[aria-haspopup="menu"]');
- const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findListbox = () => wrapper.findComponent(GlCollapsibleListbox);
+ const findListboxItems = () => wrapper.findAllComponents(GlListboxItem);
+ const findListboxItemByText = (text) =>
+ findListboxItems().wrappers.find((item) => item.text() === text);
beforeEach(() => {
gon.features = { showOverageOnRolePromotion: true };
});
- describe('when dropdown is open', () => {
+ it('has correct header text props', () => {
+ createComponent();
+ expect(findListbox().props('headerText')).toBe('Change role');
+ });
+
+ it('has items prop with all valid roles', () => {
+ createComponent();
+ const roles = findListbox()
+ .props('items')
+ .map((item) => item.text);
+ expect(roles).toEqual(Object.keys(member.validRoles));
+ });
+
+ describe('when listbox is open', () => {
beforeEach(async () => {
guestOverageConfirmAction.mockReturnValue(true);
createComponent();
- await findDropdownToggle().trigger('click');
- });
-
- it('renders all valid roles', () => {
- Object.keys(member.validRoles).forEach((role) => {
- expect(getDropdownItemByText(role).exists()).toBe(true);
- });
- });
-
- it('renders dropdown header', () => {
- expect(getByTextInDropdownMenu('Change role').exists()).toBe(true);
+ await findListbox().vm.$emit('click');
});
it('sets dropdown toggle and checks selected role', () => {
- expect(findDropdownToggle().text()).toBe('Owner');
- expect(getCheckedDropdownItem().text()).toBe('Owner');
+ expect(findListbox().props('toggleText')).toBe('Owner');
+ expect(findListbox().find('[aria-selected=true]').text()).toBe('Owner');
});
describe('when dropdown item is selected', () => {
it('does nothing if the item selected was already selected', async () => {
- await getDropdownItemByText('Owner').trigger('click');
+ await findListboxItemByText('Owner').trigger('click');
expect(actions.updateMemberRole).not.toHaveBeenCalled();
});
it('calls `updateMemberRole` Vuex action', async () => {
- await getDropdownItemByText('Developer').trigger('click');
+ await findListboxItemByText('Developer').trigger('click');
expect(actions.updateMemberRole).toHaveBeenCalledWith(expect.any(Object), {
memberId: member.id,
@@ -117,7 +107,7 @@ describe('RoleDropdown', () => {
describe('when updateMemberRole is successful', () => {
it('displays toast', async () => {
- await getDropdownItemByText('Developer').trigger('click');
+ await findListboxItemByText('Developer').trigger('click');
await nextTick();
@@ -125,21 +115,21 @@ describe('RoleDropdown', () => {
});
it('puts dropdown in loading state while waiting for `updateMemberRole` to resolve', async () => {
- await getDropdownItemByText('Developer').trigger('click');
+ await findListboxItemByText('Developer').trigger('click');
- expect(findDropdown().props('loading')).toBe(true);
+ expect(findListbox().props('loading')).toBe(true);
});
it('enables dropdown after `updateMemberRole` resolves', async () => {
- await getDropdownItemByText('Developer').trigger('click');
+ await findListboxItemByText('Developer').trigger('click');
await waitForPromises();
- expect(findDropdown().props('disabled')).toBe(false);
+ expect(findListbox().props('disabled')).toBe(false);
});
it('does not log error to Sentry', async () => {
- await getDropdownItemByText('Developer').trigger('click');
+ await findListboxItemByText('Developer').trigger('click');
await waitForPromises();
@@ -155,7 +145,7 @@ describe('RoleDropdown', () => {
});
it('does not display toast', async () => {
- await getDropdownItemByText('Developer').trigger('click');
+ await findListboxItemByText('Developer').trigger('click');
await nextTick();
@@ -163,21 +153,21 @@ describe('RoleDropdown', () => {
});
it('puts dropdown in loading state while waiting for `updateMemberRole` to resolve', async () => {
- await getDropdownItemByText('Developer').trigger('click');
+ await findListboxItemByText('Developer').trigger('click');
- expect(findDropdown().props('loading')).toBe(true);
+ expect(findListbox().props('loading')).toBe(true);
});
it('enables dropdown after `updateMemberRole` resolves', async () => {
- await getDropdownItemByText('Developer').trigger('click');
+ await findListboxItemByText('Developer').trigger('click');
await waitForPromises();
- expect(findDropdown().props('disabled')).toBe(false);
+ expect(findListbox().props('disabled')).toBe(false);
});
it('logs error to Sentry', async () => {
- await getDropdownItemByText('Developer').trigger('click');
+ await findListboxItemByText('Developer').trigger('click');
await waitForPromises();
@@ -190,7 +180,7 @@ describe('RoleDropdown', () => {
it("sets initial dropdown toggle value to member's role", () => {
createComponent();
- expect(findDropdownToggle().text()).toBe('Owner');
+ expect(findListbox().props('toggleText')).toBe('Owner');
});
it('sets the dropdown alignment to right on mobile', async () => {
@@ -199,7 +189,7 @@ describe('RoleDropdown', () => {
await nextTick();
- expect(findDropdown().props('right')).toBe(true);
+ expect(findListbox().props('placement')).toBe('right');
});
it('sets the dropdown alignment to left on desktop', async () => {
@@ -208,7 +198,7 @@ describe('RoleDropdown', () => {
await nextTick();
- expect(findDropdown().props('right')).toBe(false);
+ expect(findListbox().props('placement')).toBe('left');
});
describe('guestOverageConfirmAction', () => {
@@ -219,7 +209,7 @@ describe('RoleDropdown', () => {
beforeEach(() => {
createComponent();
- findDropdownToggle().trigger('click');
+ findListbox().vm.$emit('click');
});
afterEach(() => {
@@ -230,7 +220,7 @@ describe('RoleDropdown', () => {
beforeEach(() => {
mockConfirmAction({ confirmed: true });
- getDropdownItemByText('Reporter').trigger('click');
+ findListboxItemByText('Reporter').trigger('click');
});
it('calls updateMemberRole', () => {
@@ -242,7 +232,7 @@ describe('RoleDropdown', () => {
beforeEach(() => {
mockConfirmAction({ confirmed: false });
- getDropdownItemByText('Reporter').trigger('click');
+ findListboxItemByText('Reporter').trigger('click');
});
it('does not call updateMemberRole', () => {
diff --git a/spec/frontend/profile/components/user_achievements_spec.js b/spec/frontend/profile/components/user_achievements_spec.js
index ff6f323621a..5743c8575d5 100644
--- a/spec/frontend/profile/components/user_achievements_spec.js
+++ b/spec/frontend/profile/components/user_achievements_spec.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
+import { GlBadge } from '@gitlab/ui';
import getUserAchievementsEmptyResponse from 'test_fixtures/graphql/get_user_achievements_empty_response.json';
import getUserAchievementsLongResponse from 'test_fixtures/graphql/get_user_achievements_long_response.json';
import getUserAchievementsResponse from 'test_fixtures/graphql/get_user_achievements_with_avatar_and_description_response.json';
@@ -63,6 +64,14 @@ describe('UserAchievements', () => {
expect(wrapper.findAllByTestId('user-achievement').length).toBe(3);
});
+ it('renders count for achievements awarded more than once', async () => {
+ createComponent({ queryHandler: jest.fn().mockResolvedValue(getUserAchievementsLongResponse) });
+
+ await waitForPromises();
+
+ expect(achievement().findComponent(GlBadge).text()).toBe('2x');
+ });
+
it('renders correctly if the achievement is from a private namespace', async () => {
createComponent({
queryHandler: jest.fn().mockResolvedValue(getUserAchievementsPrivateGroupResponse),
diff --git a/spec/frontend/work_items/components/notes/work_item_add_note_spec.js b/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
index 9bb84947db5..e6d20dcb0d9 100644
--- a/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
@@ -32,12 +32,14 @@ describe('Work item add note', () => {
const findCommentForm = () => wrapper.findComponent(WorkItemCommentForm);
const findTextarea = () => wrapper.findByTestId('note-reply-textarea');
+ const findWorkItemLockedComponent = () => wrapper.findComponent(WorkItemCommentLocked);
const createComponent = async ({
mutationHandler = mutationSuccessHandler,
canUpdate = true,
+ canCreateNote = true,
workItemIid = '1',
- workItemResponse = workItemByIidResponseFactory({ canUpdate }),
+ workItemResponse = workItemByIidResponseFactory({ canUpdate, canCreateNote }),
signedIn = true,
isEditing = true,
workItemType = 'Task',
@@ -265,4 +267,13 @@ describe('Work item add note', () => {
expect(wrapper.attributes('class')).toContain('internal-note');
});
+
+ describe('when work item`createNote` permission false', () => {
+ it('cannot add comment', async () => {
+ await createComponent({ isEditing: false, canCreateNote: false });
+
+ expect(findWorkItemLockedComponent().exists()).toBe(true);
+ expect(findCommentForm().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index 84e5e76cb4c..a873462ea63 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -110,6 +110,7 @@ export const workItemQueryResponse = {
updateWorkItem: false,
setWorkItemMetadata: false,
adminParentLink: false,
+ createNote: false,
__typename: 'WorkItemPermissions',
},
widgets: [
@@ -214,6 +215,7 @@ export const updateWorkItemMutationResponse = {
updateWorkItem: false,
setWorkItemMetadata: false,
adminParentLink: false,
+ createNote: false,
__typename: 'WorkItemPermissions',
},
reference: 'test-project-path#1',
@@ -322,6 +324,7 @@ export const convertWorkItemMutationResponse = {
updateWorkItem: false,
setWorkItemMetadata: false,
adminParentLink: false,
+ createNote: false,
__typename: 'WorkItemPermissions',
},
reference: 'gitlab-org/gitlab-test#1',
@@ -418,6 +421,7 @@ export const objectiveType = {
export const workItemResponseFactory = ({
canUpdate = false,
canDelete = false,
+ canCreateNote = false,
adminParentLink = false,
notificationsWidgetPresent = true,
currentUserTodosWidgetPresent = true,
@@ -473,6 +477,7 @@ export const workItemResponseFactory = ({
updateWorkItem: canUpdate,
setWorkItemMetadata: canUpdate,
adminParentLink,
+ createNote: canCreateNote,
__typename: 'WorkItemPermissions',
},
reference: 'test-project-path#1',
@@ -751,6 +756,7 @@ export const createWorkItemMutationResponse = {
updateWorkItem: false,
setWorkItemMetadata: false,
adminParentLink: false,
+ createNote: false,
__typename: 'WorkItemPermissions',
},
reference: 'test-project-path#1',
@@ -980,6 +986,7 @@ export const workItemHierarchyEmptyResponse = {
updateWorkItem: false,
setWorkItemMetadata: false,
adminParentLink: false,
+ createNote: false,
__typename: 'WorkItemPermissions',
},
confidential: false,
@@ -1029,6 +1036,7 @@ export const workItemHierarchyNoUpdatePermissionResponse = {
updateWorkItem: false,
setWorkItemMetadata: false,
adminParentLink: false,
+ createNote: false,
__typename: 'WorkItemPermissions',
},
project: {
@@ -1178,6 +1186,7 @@ export const workItemHierarchyResponse = {
updateWorkItem: true,
setWorkItemMetadata: true,
adminParentLink: true,
+ createNote: true,
__typename: 'WorkItemPermissions',
},
author: {
@@ -1277,6 +1286,7 @@ export const workItemObjectiveWithChild = {
updateWorkItem: true,
setWorkItemMetadata: true,
adminParentLink: true,
+ createNote: true,
__typename: 'WorkItemPermissions',
},
author: {
@@ -1346,6 +1356,7 @@ export const workItemHierarchyTreeResponse = {
updateWorkItem: true,
setWorkItemMetadata: true,
adminParentLink: true,
+ createNote: true,
__typename: 'WorkItemPermissions',
},
confidential: false,
@@ -1426,6 +1437,7 @@ export const changeIndirectWorkItemParentMutationResponse = {
updateWorkItem: true,
setWorkItemMetadata: true,
adminParentLink: true,
+ createNote: true,
__typename: 'WorkItemPermissions',
},
description: null,
@@ -1493,6 +1505,7 @@ export const changeWorkItemParentMutationResponse = {
updateWorkItem: true,
setWorkItemMetadata: true,
adminParentLink: true,
+ createNote: true,
__typename: 'WorkItemPermissions',
},
description: null,
diff --git a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
index ef2acc9ec92..98522c53a47 100644
--- a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
@@ -381,6 +381,125 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
it_behaves_like 'a new issue request'
end
end
+
+ context 'when receiving a service desk custom email address verification email' do
+ let(:email_raw) { service_desk_fixture('emails/service_desk_custom_email_address_verification.eml') }
+
+ shared_examples 'an early exiting handler' do
+ it 'does not trigger the verification process and does not add an issue' do
+ expect(ServiceDesk::CustomEmailVerifications::UpdateService).to receive(:execute).exactly(0).times
+ expect { receiver.execute }.to not_change { Issue.count }
+ end
+ end
+
+ shared_examples 'a handler that does not verify the custom email' do |error_identifier|
+ it 'does not verify the custom email address' do
+ # project has no owner, so only notify verification triggerer
+ expect(Notify).to receive(:service_desk_verification_result_email).once
+
+ receiver.execute
+
+ expect(settings.reload.custom_email_enabled).to be false
+ expect(verification.reload).to have_attributes(
+ state: 'failed',
+ error: error_identifier
+ )
+ end
+ end
+
+ shared_examples 'a handler that verifies Service Desk custom email verification emails' do
+ it_behaves_like 'an early exiting handler'
+
+ context 'with valid service desk settings' do
+ let_it_be(:user) { create(:user) }
+
+ let!(:settings) { create(:service_desk_setting, project: project, custom_email: 'custom-support-email@example.com') }
+ let!(:verification) { create(:service_desk_custom_email_verification, project: project, token: 'ZROT4ZZXA-Y6', triggerer: user) }
+
+ let(:message_delivery) { instance_double(ActionMailer::MessageDelivery) }
+
+ before do
+ project.add_maintainer(user)
+
+ allow(message_delivery).to receive(:deliver_later)
+ allow(Notify).to receive(:service_desk_verification_result_email).and_return(message_delivery)
+ end
+
+ it 'successfully verifies the custom email address' do
+ # project has no owner, so only notify verification triggerer
+ expect(Notify).to receive(:service_desk_verification_result_email).once
+
+ receiver.execute
+
+ expect(settings.reload.custom_email_enabled).to be false
+ expect(verification.reload).to have_attributes(
+ state: 'finished',
+ error: nil
+ )
+ end
+
+ context 'and custom email address is not the configured subaddress of the project' do
+ before do
+ settings.update!(custom_email: 'custom-support-email@example.com')
+ end
+
+ it_behaves_like 'an early exiting handler'
+ end
+
+ context 'and verification tokens do not match' do
+ before do
+ verification.update!(token: 'XXXXXXXXXXXX')
+ end
+
+ it_behaves_like 'a handler that does not verify the custom email', 'incorrect_token'
+ end
+
+ context 'and verification email ingested too late' do
+ before do
+ verification.update!(triggered_at: ServiceDesk::CustomEmailVerification::TIMEFRAME.ago)
+ end
+
+ it_behaves_like 'a handler that does not verify the custom email', 'mail_not_received_within_timeframe'
+ end
+
+ context 'and from header differs from custom email address' do
+ before do
+ settings.update!(custom_email: 'different-from@example.com')
+ end
+
+ it_behaves_like 'a handler that does not verify the custom email', 'incorrect_from'
+ end
+ end
+
+ context 'when service_desk_custom_email feature flag is disabled' do
+ before do
+ stub_feature_flags(service_desk_custom_email: false)
+ end
+
+ it 'does not trigger the verification process and adds an issue instead' do
+ expect { receiver.execute }.to change { Issue.count }.by(1)
+ end
+ end
+ end
+
+ context 'when using incoming_email address' do
+ before do
+ stub_incoming_email_setting(enabled: true, address: 'support+%{key}@example.com')
+ end
+
+ it_behaves_like 'a handler that verifies Service Desk custom email verification emails'
+ end
+
+ context 'when using service_desk_email address' do
+ let(:receiver) { Gitlab::Email::ServiceDeskReceiver.new(email_raw) }
+
+ before do
+ stub_service_desk_email_setting(enabled: true, address: 'support+%{key}@example.com')
+ end
+
+ it_behaves_like 'a handler that verifies Service Desk custom email verification emails'
+ end
+ end
end
context 'when issue email creation fails' do
diff --git a/spec/lib/gitlab/metrics/environment_spec.rb b/spec/lib/gitlab/metrics/environment_spec.rb
index e94162e625e..4e3b1b5273e 100644
--- a/spec/lib/gitlab/metrics/environment_spec.rb
+++ b/spec/lib/gitlab/metrics/environment_spec.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rspec-parameterized'
-
-require_relative '../../../support/helpers/stub_env'
+require 'gitlab/rspec/all'
RSpec.describe Gitlab::Metrics::Environment, feature_category: :error_budgets do
include StubENV
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index bb96771b3d5..53e216323d1 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -223,14 +223,6 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :groups_and
include_examples 'includes container_registry_access_level'
- context 'when projects_preloader_fix is disabled' do
- before do
- stub_feature_flags(projects_preloader_fix: false)
- end
-
- include_examples 'includes container_registry_access_level'
- end
-
it 'includes various project feature fields' do
get api(path, user)
project_response = json_response.find { |p| p['id'] == project.id }
diff --git a/spec/scripts/generate_failed_package_and_test_mr_message_spec.rb b/spec/scripts/generate_failed_package_and_test_mr_message_spec.rb
index 79e63c95f65..7aff33855aa 100644
--- a/spec/scripts/generate_failed_package_and_test_mr_message_spec.rb
+++ b/spec/scripts/generate_failed_package_and_test_mr_message_spec.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'fast_spec_helper'
+require 'gitlab/rspec/all'
require_relative '../../scripts/generate-failed-package-and-test-mr-message'
-require_relative '../support/helpers/stub_env'
RSpec.describe GenerateFailedPackageAndTestMrMessage, feature_category: :tooling do
include StubENV
diff --git a/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb b/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb
index aee16334003..61307937101 100644
--- a/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb
+++ b/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb
@@ -3,8 +3,8 @@
# rubocop:disable RSpec/VerifiedDoubles
require 'fast_spec_helper'
+require 'gitlab/rspec/all'
require_relative '../../scripts/generate-message-to-run-e2e-pipeline'
-require_relative '../support/helpers/stub_env'
RSpec.describe GenerateMessageToRunE2ePipeline, feature_category: :tooling do
include StubENV
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 4d533b67690..4271a71372e 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -1024,4 +1024,61 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor
end
end
end
+
+ describe '#abort_auto_merges' do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:author) { user }
+
+ let_it_be(:merge_request, refind: true) do
+ create(
+ :merge_request,
+ source_project: project,
+ target_project: project,
+ merge_user: user,
+ auto_merge_enabled: true,
+ auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS
+ )
+ end
+
+ let(:service) { described_class.new(project: project, current_user: user) }
+ let(:oldrev) { merge_request.diff_refs.base_sha }
+ let(:newrev) { merge_request.diff_refs.head_sha }
+ let(:merge_sha) { oldrev }
+ let(:fix_interrupted_mwps) { true }
+
+ before do
+ stub_feature_flags(fix_interrupted_mwps: fix_interrupted_mwps)
+
+ merge_request.merge_params[:sha] = merge_sha
+ merge_request.save!
+
+ service.execute(oldrev, newrev, "refs/heads/#{merge_request.source_branch}")
+
+ merge_request.reload
+ end
+
+ it 'aborts MWPS for merge requests' do
+ expect(merge_request.auto_merge_enabled?).to be_falsey
+ expect(merge_request.merge_user).to be_nil
+ end
+
+ context 'when merge params contains up-to-date sha' do
+ let(:merge_sha) { newrev }
+
+ it 'maintains MWPS for merge requests' do
+ expect(merge_request.auto_merge_enabled?).to be_truthy
+ expect(merge_request.merge_user).to eq(user)
+ end
+
+ context 'when fix_interrupted_mwps ff is disabled' do
+ let(:fix_interrupted_mwps) { false }
+
+ it 'aborts MWPS for merge requests' do
+ expect(merge_request.auto_merge_enabled?).to be_falsey
+ expect(merge_request.merge_user).to be_nil
+ end
+ end
+ end
+ end
end
diff --git a/spec/support/helpers/stub_env.rb b/spec/support/helpers/stub_env.rb
deleted file mode 100644
index afa501d6279..00000000000
--- a/spec/support/helpers/stub_env.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-# Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb
-module StubENV
- # Stub ENV variables
- #
- # You can provide either a key and value as separate params or both in a Hash format
- #
- # Keys and values will always be converted to String, to comply with how ENV behaves
- #
- # @param key_or_hash [String, Hash<String,String>]
- # @param value [String]
- def stub_env(key_or_hash, value = nil)
- init_stub unless env_stubbed?
-
- if key_or_hash.is_a? Hash
- key_or_hash.each do |key, value|
- add_stubbed_value(key, ensure_env_type(value))
- end
- else
- add_stubbed_value key_or_hash, ensure_env_type(value)
- end
- end
-
- private
-
- STUBBED_KEY = '__STUBBED__'
-
- def add_stubbed_value(key, value)
- allow(ENV).to receive(:[]).with(key).and_return(value)
- allow(ENV).to receive(:key?).with(key).and_return(true)
- allow(ENV).to receive(:fetch).with(key).and_return(value)
- allow(ENV).to receive(:fetch).with(key, anything) do |_, default_val|
- value || default_val
- end
- end
-
- def env_stubbed?
- ENV[STUBBED_KEY]
- end
-
- def init_stub
- allow(ENV).to receive(:[]).and_call_original
- allow(ENV).to receive(:key?).and_call_original
- allow(ENV).to receive(:fetch).and_call_original
- add_stubbed_value(STUBBED_KEY, true)
- end
-
- def ensure_env_type(value)
- value.nil? ? value : value.to_s
- end
-end
diff --git a/spec/support/rspec.rb b/spec/support/rspec.rb
index 94c43669173..b34f8fe9a22 100644
--- a/spec/support/rspec.rb
+++ b/spec/support/rspec.rb
@@ -5,10 +5,9 @@ require_relative "system_exit_detected"
require_relative "helpers/stub_configuration"
require_relative "helpers/stub_metrics"
require_relative "helpers/stub_object_storage"
-require_relative "helpers/stub_env"
require_relative "helpers/fast_rails_root"
-require_relative "../../lib/gitlab/utils"
+require 'gitlab/rspec/all'
RSpec::Expectations.configuration.on_potential_false_positives = :raise
diff --git a/spec/support/shared_contexts/email_shared_context.rb b/spec/support/shared_contexts/email_shared_context.rb
index 12d4af5170b..8b4c1c1e243 100644
--- a/spec/support/shared_contexts/email_shared_context.rb
+++ b/spec/support/shared_contexts/email_shared_context.rb
@@ -24,7 +24,10 @@ end
def service_desk_fixture(path, slug: nil, key: 'mykey')
slug ||= project.full_path_slug.to_s
- fixture_file(path).gsub('project_slug', slug).gsub('project_key', key)
+ fixture_file(path)
+ .gsub('project_slug', slug)
+ .gsub('project_key', key)
+ .gsub('project_id', project.project_id.to_s)
end
RSpec.shared_examples 'reply processing shared examples' do
diff --git a/spec/tooling/danger/project_helper_spec.rb b/spec/tooling/danger/project_helper_spec.rb
index 3910f569400..fb0603a207a 100644
--- a/spec/tooling/danger/project_helper_spec.rb
+++ b/spec/tooling/danger/project_helper_spec.rb
@@ -5,9 +5,9 @@ require 'gitlab-dangerfiles'
require 'danger'
require 'danger/plugins/internal/helper'
require 'gitlab/dangerfiles/spec_helper'
+require 'gitlab/rspec/all'
require_relative '../../../danger/plugins/project_helper'
-require_relative '../../../spec/support/helpers/stub_env'
RSpec.describe Tooling::Danger::ProjectHelper do
include StubENV
diff --git a/spec/tooling/lib/tooling/find_changes_spec.rb b/spec/tooling/lib/tooling/find_changes_spec.rb
index 43c3da5699d..fef29ad3f2c 100644
--- a/spec/tooling/lib/tooling/find_changes_spec.rb
+++ b/spec/tooling/lib/tooling/find_changes_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require_relative '../../../../tooling/lib/tooling/find_changes'
-require_relative '../../../support/helpers/stub_env'
+require 'gitlab/rspec/all'
require 'json'
require 'tempfile'
diff --git a/spec/tooling/lib/tooling/find_tests_spec.rb b/spec/tooling/lib/tooling/find_tests_spec.rb
index 905f81c4bbd..67b6650b335 100644
--- a/spec/tooling/lib/tooling/find_tests_spec.rb
+++ b/spec/tooling/lib/tooling/find_tests_spec.rb
@@ -2,7 +2,7 @@
require 'tempfile'
require_relative '../../../../tooling/lib/tooling/find_tests'
-require_relative '../../../support/helpers/stub_env'
+require 'gitlab/rspec/all'
RSpec.describe Tooling::FindTests, feature_category: :tooling do
include StubENV
diff --git a/spec/tooling/lib/tooling/gettext_extractor_spec.rb b/spec/tooling/lib/tooling/gettext_extractor_spec.rb
index 3c0f91342c2..14310c804f1 100644
--- a/spec/tooling/lib/tooling/gettext_extractor_spec.rb
+++ b/spec/tooling/lib/tooling/gettext_extractor_spec.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
require 'rspec/parameterized'
+require 'gitlab/rspec/all'
require_relative '../../../../tooling/lib/tooling/gettext_extractor'
-require_relative '../../../support/helpers/stub_env'
require_relative '../../../support/tmpdir'
RSpec.describe Tooling::GettextExtractor, feature_category: :tooling do
diff --git a/spec/tooling/lib/tooling/predictive_tests_spec.rb b/spec/tooling/lib/tooling/predictive_tests_spec.rb
index b82364fe6f6..fdb7d09a3e2 100644
--- a/spec/tooling/lib/tooling/predictive_tests_spec.rb
+++ b/spec/tooling/lib/tooling/predictive_tests_spec.rb
@@ -2,8 +2,8 @@
require 'tempfile'
require 'fileutils'
+require 'gitlab/rspec/all'
require_relative '../../../../tooling/lib/tooling/predictive_tests'
-require_relative '../../../support/helpers/stub_env'
RSpec.describe Tooling::PredictiveTests, feature_category: :tooling do
include StubENV
diff --git a/spec/tooling/rspec_flaky/config_spec.rb b/spec/tooling/rspec_flaky/config_spec.rb
index 63f42d7c6cc..8ba4dd1640e 100644
--- a/spec/tooling/rspec_flaky/config_spec.rb
+++ b/spec/tooling/rspec_flaky/config_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'rspec-parameterized'
-require_relative '../../support/helpers/stub_env'
+require 'gitlab/rspec/all'
require_relative '../../../tooling/rspec_flaky/config'
diff --git a/spec/tooling/rspec_flaky/flaky_example_spec.rb b/spec/tooling/rspec_flaky/flaky_example_spec.rb
index 511f3286f56..68e40bc1050 100644
--- a/spec/tooling/rspec_flaky/flaky_example_spec.rb
+++ b/spec/tooling/rspec_flaky/flaky_example_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require_relative '../../support/helpers/stub_env'
+require 'gitlab/rspec/all'
require_relative '../../support/time_travel'
require_relative '../../../tooling/rspec_flaky/flaky_example'
diff --git a/spec/tooling/rspec_flaky/listener_spec.rb b/spec/tooling/rspec_flaky/listener_spec.rb
index 0bbd6454969..c0b71403347 100644
--- a/spec/tooling/rspec_flaky/listener_spec.rb
+++ b/spec/tooling/rspec_flaky/listener_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require_relative '../../support/helpers/stub_env'
+require 'gitlab/rspec/all'
require_relative '../../support/time_travel'
require_relative '../../../tooling/rspec_flaky/listener'