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-10-31 21:07:22 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-10-31 21:07:22 +0300
commit1d21e1712158ee4e3cf8b71b45ead662529fc3f8 (patch)
treea8435cf28a026d7d7ef681d459e905bcf5609f65 /spec
parent47bf4294773cf15aa755193cdd7df9a491a49f52 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/issues/issue_state_spec.rb4
-rw-r--r--spec/features/issues/move_spec.rb4
-rw-r--r--spec/features/projects/work_items/work_item_spec.rb2
-rw-r--r--spec/frontend/design_management/components/design_notes/design_note_spec.js43
-rw-r--r--spec/frontend/issues/show/components/header_actions_spec.js52
-rw-r--r--spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js358
-rw-r--r--spec/frontend/work_items/components/work_item_milestone_spec.js53
-rw-r--r--spec/frontend/work_items/components/work_item_parent_spec.js5
-rw-r--r--spec/helpers/environments_helper_spec.rb4
-rw-r--r--spec/helpers/ide_helper_spec.rb2
-rw-r--r--spec/helpers/operations_helper_spec.rb2
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_migration_spec.rb11
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb22
-rw-r--r--spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb13
-rw-r--r--spec/lib/gitlab/database/bulk_update_spec.rb2
-rw-r--r--spec/lib/gitlab/database/loose_foreign_keys_spec.rb16
-rw-r--r--spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb40
-rw-r--r--spec/lib/gitlab/database/migrations/instrumentation_spec.rb16
-rw-r--r--spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb104
-rw-r--r--spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb64
-rw-r--r--spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb36
-rw-r--r--spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb27
-rw-r--r--spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb7
-rw-r--r--spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb60
-rw-r--r--spec/lib/gitlab/database/postgres_constraint_spec.rb16
-rw-r--r--spec/lib/gitlab/database/tables_truncate_spec.rb2
-rw-r--r--spec/migrations/20231016001000_fix_design_user_mentions_design_id_note_id_index_for_self_managed_spec.rb114
-rw-r--r--spec/presenters/clusters/cluster_presenter_spec.rb2
-rw-r--r--spec/rubocop/cop/gitlab/doc_url_spec.rb6
-rw-r--r--spec/serializers/issue_entity_spec.rb2
-rw-r--r--spec/support/shared_examples/features/work_items_shared_examples.rb4
31 files changed, 578 insertions, 515 deletions
diff --git a/spec/features/issues/issue_state_spec.rb b/spec/features/issues/issue_state_spec.rb
index 3fe49ff7080..125329764c6 100644
--- a/spec/features/issues/issue_state_spec.rb
+++ b/spec/features/issues/issue_state_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe 'issue state', :js, feature_category: :team_planning do
find('#new-actions-header-dropdown > button').click
end
- it_behaves_like 'issue closed', '.dropdown-menu-right'
+ it_behaves_like 'issue closed', '.gl-new-dropdown-contents'
end
context 'when clicking the bottom `Close issue` button', :aggregate_failures do
@@ -74,7 +74,7 @@ RSpec.describe 'issue state', :js, feature_category: :team_planning do
find('#new-actions-header-dropdown > button').click
end
- it_behaves_like 'issue reopened', '.dropdown-menu-right'
+ it_behaves_like 'issue reopened', '.gl-new-dropdown-contents'
end
context 'when clicking the bottom `Reopen issue` button', :aggregate_failures do
diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb
index 4a38373db71..eca52a3a2c3 100644
--- a/spec/features/issues/move_spec.rb
+++ b/spec/features/issues/move_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe 'issue move to another project', feature_category: :team_planning
it 'moving issue to another project', :js do
click_button _('Move issue')
wait_for_requests
- all('.gl-dropdown-item')[0].click
+ all('.gl-new-dropdown-item')[0].click
click_button _('Move')
expect(page).to have_content("Text with #{cross_reference}#{mr.to_reference}")
@@ -116,7 +116,7 @@ RSpec.describe 'issue move to another project', feature_category: :team_planning
click_button _('Move issue')
wait_for_requests
- find('.gl-dropdown-item', text: project_title).click
+ find('.gl-new-dropdown-item', text: project_title).click
click_button _('Move')
end
diff --git a/spec/features/projects/work_items/work_item_spec.rb b/spec/features/projects/work_items/work_item_spec.rb
index 09a8636359d..876444e451a 100644
--- a/spec/features/projects/work_items/work_item_spec.rb
+++ b/spec/features/projects/work_items/work_item_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Work item', :js, feature_category: :team_planning do
+ include ListboxHelpers
+
let_it_be_with_reload(:user) { create(:user, :no_super_sidebar) }
let_it_be_with_reload(:user2) { create(:user, :no_super_sidebar, name: 'John') }
diff --git a/spec/frontend/design_management/components/design_notes/design_note_spec.js b/spec/frontend/design_management/components/design_notes/design_note_spec.js
index 91c6acd8890..28b264cede9 100644
--- a/spec/frontend/design_management/components/design_notes/design_note_spec.js
+++ b/spec/frontend/design_management/components/design_notes/design_note_spec.js
@@ -51,13 +51,19 @@ describe('Design note component', () => {
const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
const findDropdownItems = () => findDropdown().findAllComponents(GlDisclosureDropdownItem);
const findEditDropdownItem = () => findDropdownItems().at(0);
- const findDeleteDropdownItem = () => findDropdownItems().at(1);
+ const findCopyLinkDropdownItem = () => findDropdownItems().at(1);
+ const findDeleteDropdownItem = () => findDropdownItems().at(2);
+
+ const showToast = jest.fn();
function createComponent({
props = {},
data = { isEditing: false },
mountFn = mountExtended,
mocks = {
+ $toast: {
+ show: showToast,
+ },
$route,
$apollo: {
mutate: jest.fn().mockResolvedValue({ data: { updateNote: {} } }),
@@ -239,6 +245,7 @@ describe('Design note component', () => {
expect(findDropdown().exists()).toBe(true);
expect(findEditDropdownItem().exists()).toBe(true);
+ expect(findCopyLinkDropdownItem().exists()).toBe(true);
expect(findDeleteDropdownItem().exists()).toBe(true);
expect(findDropdown().props('items')[0].extraAttrs.class).toBe('gl-sm-display-none!');
});
@@ -266,6 +273,40 @@ describe('Design note component', () => {
expect(wrapper.emitted()).toEqual({ 'delete-note': [[{ ...payload }]] });
});
+ it('shows a success toast after copying the url to the clipboard', () => {
+ createComponent({
+ props: {
+ note: {
+ ...note,
+ userPermissions: {
+ adminNote: true,
+ },
+ },
+ },
+ });
+
+ findCopyLinkDropdownItem().find('button').trigger('click');
+
+ expect(showToast).toHaveBeenCalledWith('Link copied to clipboard.');
+ });
+
+ it('has data-clipboard-text set to the correct url', () => {
+ createComponent({
+ props: {
+ note: {
+ ...note,
+ userPermissions: {
+ adminNote: true,
+ },
+ },
+ },
+ });
+
+ expect(findCopyLinkDropdownItem().props('item').extraAttrs['data-clipboard-text']).toBe(
+ 'http://test.host/#note_123',
+ );
+ });
+
describe('when user has award emoji permissions', () => {
const findEmojiPicker = () => wrapper.findComponent(EmojiPicker);
const propsData = {
diff --git a/spec/frontend/issues/show/components/header_actions_spec.js b/spec/frontend/issues/show/components/header_actions_spec.js
index e508045eff3..d0c2a1a5f1b 100644
--- a/spec/frontend/issues/show/components/header_actions_spec.js
+++ b/spec/frontend/issues/show/components/header_actions_spec.js
@@ -1,9 +1,16 @@
import Vue, { nextTick } from 'vue';
-import { GlDropdown, GlDropdownItem, GlLink, GlModal, GlButton } from '@gitlab/ui';
+import {
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
+ GlLink,
+ GlModal,
+ GlButton,
+} from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import VueApollo from 'vue-apollo';
+import { stubComponent } from 'helpers/stub_component';
import waitForPromises from 'helpers/wait_for_promises';
import { mockTracking } from 'helpers/tracking_helper';
import { createAlert, VARIANT_SUCCESS } from '~/alert';
@@ -120,8 +127,10 @@ describe('HeaderActions component', () => {
const findDropdownBy = (dataTestId) => wrapper.find(`[data-testid="${dataTestId}"]`);
const findMobileDropdown = () => findDropdownBy('mobile-dropdown');
const findDesktopDropdown = () => findDropdownBy('desktop-dropdown');
- const findMobileDropdownItems = () => findMobileDropdown().findAllComponents(GlDropdownItem);
- const findDesktopDropdownItems = () => findDesktopDropdown().findAllComponents(GlDropdownItem);
+ const findMobileDropdownItems = () =>
+ findMobileDropdown().findAllComponents(GlDisclosureDropdownItem);
+ const findDesktopDropdownItems = () =>
+ findDesktopDropdown().findAllComponents(GlDisclosureDropdownItem);
const findAbuseCategorySelector = () => wrapper.findComponent(AbuseCategorySelector);
const findReportAbuseButton = () => wrapper.find(`[data-testid="report-abuse-item"]`);
const findNotificationWidget = () => wrapper.find(`[data-testid="notification-toggle"]`);
@@ -179,6 +188,11 @@ describe('HeaderActions component', () => {
},
stubs: {
GlButton,
+ GlDisclosureDropdown: stubComponent(GlDisclosureDropdown, {
+ methods: {
+ close: jest.fn(),
+ },
+ }),
},
});
};
@@ -217,7 +231,7 @@ describe('HeaderActions component', () => {
});
it('calls apollo mutation', () => {
- findToggleIssueStateButton().vm.$emit('click');
+ findToggleIssueStateButton().vm.$emit('action');
expect(updateIssueMutationResponseHandler).toHaveBeenCalledWith({
input: {
@@ -229,7 +243,7 @@ describe('HeaderActions component', () => {
});
it('dispatches a custom event to update the issue page', async () => {
- findToggleIssueStateButton().vm.$emit('click');
+ findToggleIssueStateButton().vm.$emit('action');
await waitForPromises();
@@ -286,7 +300,11 @@ describe('HeaderActions component', () => {
it(`${isItemVisible ? 'shows' : 'hides'} "${itemText}" item`, () => {
expect(
findDropdownItems()
- .filter((item) => item.text() === itemText)
+ .filter((item) => {
+ return item.props('item')
+ ? item.props('item').text === itemText
+ : item.text() === itemText;
+ })
.exists(),
).toBe(isItemVisible);
});
@@ -313,7 +331,7 @@ describe('HeaderActions component', () => {
it('should trigger "open.form" event when clicked', async () => {
expect(issuesEventHub.$emit).not.toHaveBeenCalled();
- await findEditButton().trigger('click');
+ await findEditButton().vm.$emit('click');
expect(issuesEventHub.$emit).toHaveBeenCalledWith('open.form');
});
});
@@ -328,7 +346,7 @@ describe('HeaderActions component', () => {
});
it('tracks clicking on button', () => {
- findDesktopDropdownItems().at(4).vm.$emit('click');
+ findDesktopDropdownItems().at(4).vm.$emit('action');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_dropdown', {
label: 'delete_issue',
@@ -345,7 +363,7 @@ describe('HeaderActions component', () => {
promoteToEpicHandler: promoteToEpicMutationSuccessResponseHandler,
});
- wrapper.find('[data-testid="promote-button"]').vm.$emit('click');
+ wrapper.find('[data-testid="promote-button"]').vm.$emit('action');
await waitForPromises();
});
@@ -381,7 +399,7 @@ describe('HeaderActions component', () => {
promoteToEpicHandler: promoteToEpicMutationErrorHandler,
});
- wrapper.find('[data-testid="promote-button"]').vm.$emit('click');
+ wrapper.find('[data-testid="promote-button"]').vm.$emit('action');
await waitForPromises();
});
@@ -483,7 +501,7 @@ describe('HeaderActions component', () => {
});
it('opens the abuse category drawer', async () => {
- findReportAbuseButton().vm.$emit('click');
+ findReportAbuseButton().vm.$emit('action');
await nextTick();
@@ -491,7 +509,7 @@ describe('HeaderActions component', () => {
});
it('closes the abuse category drawer', async () => {
- await findReportAbuseButton().vm.$emit('click');
+ await findReportAbuseButton().vm.$emit('action');
expect(findAbuseCategorySelector().exists()).toEqual(true);
await findAbuseCategorySelector().vm.$emit('close-drawer');
@@ -603,7 +621,7 @@ describe('HeaderActions component', () => {
});
it('shows toast message', () => {
- findCopyRefenceDropdownItem().vm.$emit('click');
+ findCopyRefenceDropdownItem().vm.$emit('action');
expect(toast).toHaveBeenCalledWith('Reference copied');
});
@@ -652,7 +670,7 @@ describe('HeaderActions component', () => {
});
it('shows toast message', () => {
- findCopyEmailItem().vm.$emit('click');
+ findCopyEmailItem().vm.$emit('action');
expect(toast).toHaveBeenCalledWith('Email address copied');
});
@@ -710,11 +728,13 @@ describe('HeaderActions component', () => {
props: { issueType, issuableEmailAddress: 'mock-email-address' },
});
- expect(wrapper.findComponent(GlDropdown).attributes('text')).toBe(
+ expect(wrapper.findComponent(GlDisclosureDropdown).props('toggleText')).toBe(
`${capitalizeFirstCharacter(expectedText)} actions`,
);
expect(findDropdownBy('copy-email').text()).toBe(`Copy ${expectedText} email address`);
- expect(findDesktopDropdownItems().at(1).text()).toBe(`New related ${expectedText}`);
+ expect(findDesktopDropdownItems().at(1).props('item').text).toBe(
+ `New related ${expectedText}`,
+ );
});
});
});
diff --git a/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js b/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js
index 56c915c4cae..f049001ba45 100644
--- a/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js
+++ b/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js
@@ -1,19 +1,9 @@
-import { nextTick } from 'vue';
-import {
- GlIcon,
- GlLoadingIcon,
- GlDropdown,
- GlDropdownForm,
- GlDropdownItem,
- GlSearchBoxByType,
- GlButton,
-} from '@gitlab/ui';
+import { GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils';
import IssuableMoveDropdown from '~/sidebar/components/move/issuable_move_dropdown.vue';
-import { stubComponent } from 'helpers/stub_component';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
const mockProjects = [
@@ -42,318 +32,136 @@ const mockProps = {
disabled: false,
};
-const mockEvent = {
- stopPropagation: jest.fn(),
- preventDefault: jest.fn(),
-};
-
-const focusInputMock = jest.fn();
-const hideMock = jest.fn();
-
describe('IssuableMoveDropdown', () => {
let mock;
let wrapper;
- const createComponent = (propsData = mockProps) => {
- wrapper = shallowMountExtended(IssuableMoveDropdown, {
- propsData,
- stubs: {
- GlDropdown: stubComponent(GlDropdown, {
- methods: {
- hide: hideMock,
- },
- }),
- GlSearchBoxByType: stubComponent(GlSearchBoxByType, {
- methods: {
- focusInput: focusInputMock,
- },
- }),
- },
- });
+ const createComponent = (propsData = {}) => {
+ wrapper = mountExtended(IssuableMoveDropdown, { propsData: { ...mockProps, ...propsData } });
};
beforeEach(() => {
mock = new MockAdapter(axios);
mock.onGet(mockProps.projectsFetchPath).reply(HTTP_STATUS_OK, mockProjects);
-
- createComponent();
});
afterEach(() => {
mock.restore();
});
- const findCollapsedEl = () => wrapper.findByTestId('move-collapsed');
- const findFooter = () => wrapper.findByTestId('footer');
- const findHeader = () => wrapper.findByTestId('header');
- const findFailedLoadResults = () => wrapper.findByTestId('failed-load-results');
- const findDropdownContent = () => wrapper.findByTestId('content');
- const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findDropdownEl = () => wrapper.findComponent(GlDropdown);
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
-
- describe('watch', () => {
- describe('searchKey', () => {
- it('calls `fetchProjects` with value of the prop', async () => {
- jest.spyOn(axios, 'get');
- findSearchBox().vm.$emit('input', 'foo');
-
- await waitForPromises();
-
- expect(axios.get).toHaveBeenCalledWith('/-/autocomplete/projects?project_id=1', {
- params: { search: 'foo' },
- });
- });
- });
- });
-
- describe('methods', () => {
- describe('fetchProjects', () => {
- it('sets projectsListLoading to true and projectsListLoadFailed to false', async () => {
- findDropdownEl().vm.$emit('shown');
- await nextTick();
-
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findFailedLoadResults().exists()).toBe(false);
- });
-
- it('calls `axios.get` with `projectsFetchPath` and query param `search`', async () => {
- jest.spyOn(axios, 'get');
-
- findSearchBox().vm.$emit('input', 'foo');
- await waitForPromises();
-
- expect(axios.get).toHaveBeenCalledWith(
- mockProps.projectsFetchPath,
- expect.objectContaining({
- params: {
- search: 'foo',
- },
- }),
- );
- });
-
- it('sets response to `projects` and focuses on searchInput when request is successful', async () => {
- jest.spyOn(axios, 'get');
-
- findSearchBox().vm.$emit('input', 'foo');
- await waitForPromises();
+ const findDropdownButton = () => wrapper.findByTestId('dropdown-button');
+ const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
+ const findDropdownMoveButton = () => wrapper.findByTestId('dropdown-move-button');
+ const findDropdownItemsText = () =>
+ wrapper.findAllComponents(GlListboxItem).wrappers.map((item) => item.text());
- expect(findAllDropdownItems()).toHaveLength(mockProjects.length);
- expect(focusInputMock).toHaveBeenCalled();
- });
-
- it('sets projectsListLoadFailed to true when request fails', async () => {
- jest.spyOn(axios, 'get').mockRejectedValue({});
-
- findSearchBox().vm.$emit('input', 'foo');
- await waitForPromises();
-
- expect(findFailedLoadResults().exists()).toBe(true);
- });
-
- it('sets projectsListLoading to false when request completes', async () => {
- jest.spyOn(axios, 'get');
-
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
-
- expect(findLoadingIcon().exists()).toBe(false);
- });
- });
-
- describe('isSelectedProject', () => {
- it.each`
- projectIndex | selectedProjectIndex | title | returnValue
- ${0} | ${0} | ${'are same projects'} | ${true}
- ${0} | ${1} | ${'are different projects'} | ${false}
- `(
- 'returns $returnValue when selectedProject and provided project param $title',
- async ({ projectIndex, selectedProjectIndex, returnValue }) => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
-
- findAllDropdownItems().at(selectedProjectIndex).vm.$emit('click', mockEvent);
-
- await nextTick();
-
- expect(findAllDropdownItems().at(projectIndex).props('isChecked')).toBe(returnValue);
- },
- );
-
- it('returns false when selectedProject is null', async () => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ it('renders a dropdown button with provided title and header', () => {
+ createComponent();
- expect(findAllDropdownItems().at(0).props('isChecked')).toBe(false);
- });
- });
+ expect(findDropdownButton().text()).toBe(mockProps.dropdownButtonTitle);
+ expect(findDropdown().props('headerText')).toBe(mockProps.dropdownHeaderTitle);
});
- describe('template', () => {
- it('renders collapsed state element with icon', () => {
- const collapsedEl = findCollapsedEl();
-
- expect(collapsedEl.exists()).toBe(true);
- expect(collapsedEl.attributes('title')).toBe(mockProps.dropdownButtonTitle);
- expect(collapsedEl.findComponent(GlIcon).exists()).toBe(true);
- expect(collapsedEl.findComponent(GlIcon).props('name')).toBe('arrow-right');
- });
-
- describe('gl-dropdown component', () => {
- it('renders component container element', () => {
- expect(findDropdownEl().exists()).toBe(true);
- expect(findDropdownEl().props('block')).toBe(true);
- });
+ it('renders the dropdown button as disabled when disabled prop is true', () => {
+ createComponent({ disabled: true });
- it('renders gl-dropdown-form component', () => {
- expect(findDropdownEl().findComponent(GlDropdownForm).exists()).toBe(true);
- });
-
- it('renders disabled dropdown when `disabled` is true', () => {
- createComponent({ ...mockProps, disabled: true });
- expect(findDropdownEl().props('disabled')).toBe(true);
- });
-
- it('renders header element', () => {
- const headerEl = findHeader();
-
- expect(headerEl.exists()).toBe(true);
- expect(headerEl.find('span').text()).toBe(mockProps.dropdownHeaderTitle);
- expect(headerEl.findComponent(GlButton).props('icon')).toBe('close');
- });
-
- it('renders gl-search-box-by-type component', () => {
- const searchEl = findDropdownEl().findComponent(GlSearchBoxByType);
-
- expect(searchEl.exists()).toBe(true);
- expect(searchEl.attributes()).toMatchObject({
- placeholder: 'Search project',
- debounce: '300',
- });
- });
-
- it('renders gl-loading-icon component when projectsListLoading prop is true', async () => {
- findDropdownEl().vm.$emit('shown');
- await nextTick();
-
- expect(findLoadingIcon().exists()).toBe(true);
- });
-
- it('renders gl-dropdown-item components for available projects', async () => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
-
- findAllDropdownItems().at(0).vm.$emit('click', mockEvent);
- await nextTick();
-
- expect(findAllDropdownItems()).toHaveLength(mockProjects.length);
- expect(findAllDropdownItems().at(0).props()).toMatchObject({
- isCheckItem: true,
- isChecked: true,
- });
- expect(findAllDropdownItems().at(0).text()).toBe(mockProjects[0].name_with_namespace);
- });
-
- it('renders string "No matching results" when search does not yield any matches', async () => {
- mock.onGet(mockProps.projectsFetchPath).reply(HTTP_STATUS_OK, []);
+ expect(findDropdownButton().props('disabled')).toBe(true);
+ });
- findSearchBox().vm.$emit('input', 'foo');
- await waitForPromises();
+ it('triggers a project search when dropdown button is clicked', async () => {
+ createComponent();
- expect(findDropdownContent().text()).toContain('No matching results');
- });
+ await findDropdownButton().trigger('click');
+ await waitForPromises();
- it('renders string "Failed to load projects" when loading projects list fails', async () => {
- mock.onGet(mockProps.projectsFetchPath).reply(HTTP_STATUS_OK, []);
- jest.spyOn(axios, 'get').mockRejectedValue({});
+ expect(mock.history.get).toHaveLength(1);
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ expect(findDropdownItemsText()).toEqual([
+ 'Gitlab Org / Gitlab Shell',
+ 'Gnuwget / Wget2',
+ 'Commit451 / Lab Coat',
+ ]);
+ });
- expect(findDropdownContent().text()).toContain('Failed to load projects');
- });
+ it('shows "No matching results" when no projects are found', async () => {
+ createComponent();
- it('renders gl-button within footer', async () => {
- const moveButtonEl = findFooter().findComponent(GlButton);
+ mock.onGet(mockProps.projectsFetchPath).reply(HTTP_STATUS_OK, []);
- expect(moveButtonEl.text()).toBe('Move');
- expect(moveButtonEl.attributes('disabled')).toBeDefined();
+ await findDropdown().vm.$emit('search', 'foobar');
+ await waitForPromises();
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ expect(findDropdown().text()).toContain('No matching results');
+ expect(findDropdownItemsText()).toEqual([]);
+ });
- findAllDropdownItems().at(0).vm.$emit('click', mockEvent);
- await nextTick();
+ it('shows "Failed to load projects" when request fails', async () => {
+ createComponent();
- expect(findFooter().findComponent(GlButton).attributes('disabled')).not.toBeDefined();
- });
- });
+ mock.onGet(mockProps.projectsFetchPath).networkError();
- describe('events', () => {
- it('collapsed state element emits `toggle-collapse` event on component when clicked', () => {
- findCollapsedEl().trigger('click');
+ await findDropdown().vm.$emit('search', 'foobar');
+ await waitForPromises();
- expect(wrapper.emitted('toggle-collapse')).toHaveLength(1);
- });
+ expect(findDropdown().text()).toContain('Failed to load projects');
+ expect(findDropdownItemsText()).toEqual([]);
+ });
- it('gl-dropdown component calls `fetchProjects` on `shown` event', () => {
- jest.spyOn(axios, 'get');
+ it('disables the Move issuable button if no project is selected', async () => {
+ createComponent();
- findDropdownEl().vm.$emit('shown');
+ await findDropdownButton().trigger('click');
+ await waitForPromises();
- expect(axios.get).toHaveBeenCalled();
- });
+ expect(findDropdownMoveButton().props('disabled')).toBe(true);
+ });
- it('gl-dropdown component prevents dropdown body from closing on `hide` event when `projectItemClick` prop is true', async () => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ it('shows search results when search is successful', async () => {
+ createComponent();
- findAllDropdownItems().at(0).vm.$emit('click', mockEvent);
- await nextTick();
+ mock.onGet(mockProps.projectsFetchPath).reply(HTTP_STATUS_OK, [
+ {
+ id: 2,
+ name_with_namespace: 'Gitlab Org / Gitlab Shell',
+ full_path: 'gitlab-org/gitlab-shell',
+ },
+ ]);
- findDropdownEl().vm.$emit('hide', mockEvent);
+ await findDropdown().vm.$emit('search', 'shell');
+ await waitForPromises();
- expect(mockEvent.preventDefault).toHaveBeenCalled();
- });
+ expect(findDropdownItemsText()).toEqual(['Gitlab Org / Gitlab Shell']);
+ });
- it('gl-dropdown component emits `dropdown-close` event on component from `hide` event', () => {
- findDropdownEl().vm.$emit('hide');
+ it('emits "move-issuable" event when Move issuable button is clicked', async () => {
+ createComponent();
- expect(wrapper.emitted('dropdown-close')).toHaveLength(1);
- });
+ await findDropdownButton().trigger('click');
+ await waitForPromises();
- it('close icon in dropdown header closes the dropdown when clicked', async () => {
- findHeader().findComponent(GlButton).vm.$emit('click', mockEvent);
+ await wrapper.findAllComponents(GlListboxItem).wrappers[0].trigger('click');
+ await findDropdownMoveButton().trigger('click');
- await nextTick();
- expect(hideMock).toHaveBeenCalled();
- });
+ expect(wrapper.emitted('move-issuable')).toEqual([[mockProjects[0]]]);
+ });
- it('sets project for clicked gl-dropdown-item to selectedProject', async () => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ it('disables the Move issuable button when moveInProgress prop is true', async () => {
+ createComponent({ moveInProgress: true });
- findAllDropdownItems().at(0).vm.$emit('click', mockEvent);
- await nextTick();
+ await findDropdownButton().trigger('click');
+ await waitForPromises();
- expect(findAllDropdownItems().at(0).props('isChecked')).toBe(true);
- });
+ expect(findDropdownMoveButton().props('disabled')).toBe(true);
+ });
- it('hides dropdown and emits `move-issuable` event when move button is clicked', async () => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ it('emits "dropdown-close" event when dropdown is hidden', async () => {
+ createComponent();
- findAllDropdownItems().at(0).vm.$emit('click', mockEvent);
- await nextTick();
+ await findDropdownButton().trigger('click');
+ await waitForPromises();
- findFooter().findComponent(GlButton).vm.$emit('click');
+ await findDropdown().vm.$emit('hidden');
- expect(hideMock).toHaveBeenCalled();
- expect(wrapper.emitted('move-issuable')).toHaveLength(1);
- expect(wrapper.emitted('move-issuable')[0]).toEqual([mockProjects[0]]);
- });
- });
+ expect(wrapper.emitted('dropdown-close')).toHaveLength(1);
});
});
diff --git a/spec/frontend/work_items/components/work_item_milestone_spec.js b/spec/frontend/work_items/components/work_item_milestone_spec.js
index e303ad4b481..fc2c5eb2af2 100644
--- a/spec/frontend/work_items/components/work_item_milestone_spec.js
+++ b/spec/frontend/work_items/components/work_item_milestone_spec.js
@@ -1,14 +1,8 @@
-import {
- GlDropdown,
- GlDropdownItem,
- GlSearchBoxByType,
- GlSkeletonLoader,
- GlFormGroup,
- GlDropdownText,
-} from '@gitlab/ui';
+import { GlCollapsibleListbox, GlListboxItem, GlSkeletonLoader, GlFormGroup } from '@gitlab/ui';
+
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
-import WorkItemMilestone from '~/work_items/components/work_item_milestone.vue';
+import WorkItemMilestone, { noMilestoneId } from '~/work_items/components/work_item_milestone.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mockTracking } from 'helpers/tracking_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
@@ -32,17 +26,13 @@ describe('WorkItemMilestone component', () => {
const workItemId = 'gid://gitlab/WorkItem/1';
const workItemType = 'Task';
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+ const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
- const findNoMilestoneDropdownItem = () => wrapper.findByTestId('no-milestone');
- const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findFirstDropdownItem = () => findDropdownItems().at(0);
- const findDropdownTexts = () => wrapper.findAllComponents(GlDropdownText);
- const findDropdownItemAtIndex = (index) => findDropdownItems().at(index);
+ const findNoMilestoneDropdownItem = () => wrapper.findByTestId('listbox-item-no-milestone-id');
+ const findDropdownItems = () => wrapper.findAllComponents(GlListboxItem);
const findDisabledTextSpan = () => wrapper.findByTestId('disabled-text');
- const findDropdownTextAtIndex = (index) => findDropdownTexts().at(index);
const findInputGroup = () => wrapper.findComponent(GlFormGroup);
+ const findNoResultsText = () => wrapper.findByTestId('no-results-text');
const successSearchQueryHandler = jest.fn().mockResolvedValue(projectMilestonesResponse);
const successSearchWithNoMatchingMilestones = jest
@@ -74,8 +64,7 @@ describe('WorkItemMilestone component', () => {
workItemType,
},
stubs: {
- GlDropdown,
- GlSearchBoxByType,
+ GlCollapsibleListbox,
},
});
};
@@ -106,7 +95,7 @@ describe('WorkItemMilestone component', () => {
it(`has a value of "Add to milestone"`, () => {
createComponent({ canUpdate: true, milestone: null });
- expect(findDropdown().props('text')).toBe(WorkItemMilestone.i18n.MILESTONE_PLACEHOLDER);
+ expect(findDropdown().props('toggleText')).toBe(WorkItemMilestone.i18n.MILESTONE_PLACEHOLDER);
});
});
@@ -114,7 +103,7 @@ describe('WorkItemMilestone component', () => {
it('has the search box', () => {
createComponent();
- expect(findSearchBox().exists()).toBe(true);
+ expect(findDropdown().props('searchable')).toBe(true);
});
it('shows no matching results when no items', () => {
@@ -122,9 +111,8 @@ describe('WorkItemMilestone component', () => {
searchQueryHandler: successSearchWithNoMatchingMilestones,
});
- expect(findDropdownTextAtIndex(0).text()).toBe(WorkItemMilestone.i18n.NO_MATCHING_RESULTS);
+ expect(findNoResultsText().text()).toBe(WorkItemMilestone.i18n.NO_MATCHING_RESULTS);
expect(findDropdownItems()).toHaveLength(1);
- expect(findDropdownTexts()).toHaveLength(1);
});
});
@@ -165,16 +153,18 @@ describe('WorkItemMilestone component', () => {
it('changes the milestone to null when clicked on no milestone', async () => {
showDropdown();
- findFirstDropdownItem().vm.$emit('click');
+ findDropdown().vm.$emit('select', noMilestoneId);
hideDropdown();
await nextTick();
expect(findDropdown().props('loading')).toBe(true);
await waitForPromises();
-
- expect(findDropdown().props('loading')).toBe(false);
- expect(findDropdown().props('text')).toBe(WorkItemMilestone.i18n.MILESTONE_PLACEHOLDER);
+ expect(findDropdown().props()).toMatchObject({
+ loading: false,
+ toggleText: WorkItemMilestone.i18n.MILESTONE_PLACEHOLDER,
+ toggleClass: expect.arrayContaining(['gl-text-gray-500!']),
+ });
});
it('changes the milestone to the selected milestone', async () => {
@@ -182,15 +172,16 @@ describe('WorkItemMilestone component', () => {
/** the index is -1 since no matching results is also a dropdown item */
const milestoneAtIndex =
projectMilestonesResponse.data.workspace.attributes.nodes[milestoneIndex - 1];
+
showDropdown();
await waitForPromises();
- findDropdownItemAtIndex(milestoneIndex).vm.$emit('click');
+ findDropdown().vm.$emit('select', milestoneAtIndex.id);
hideDropdown();
await waitForPromises();
- expect(findDropdown().props('text')).toBe(milestoneAtIndex.title);
+ expect(findDropdown().props('toggleText')).toBe(milestoneAtIndex.title);
});
});
@@ -208,7 +199,7 @@ describe('WorkItemMilestone component', () => {
});
showDropdown();
- findFirstDropdownItem().vm.$emit('click');
+ findDropdown().vm.$emit('select', noMilestoneId);
hideDropdown();
await waitForPromises();
@@ -224,7 +215,7 @@ describe('WorkItemMilestone component', () => {
createComponent({ canUpdate: true });
showDropdown();
- findFirstDropdownItem().vm.$emit('click');
+ findDropdown().vm.$emit('select', noMilestoneId);
hideDropdown();
await waitForPromises();
diff --git a/spec/frontend/work_items/components/work_item_parent_spec.js b/spec/frontend/work_items/components/work_item_parent_spec.js
index a977e7d396f..c60620d210a 100644
--- a/spec/frontend/work_items/components/work_item_parent_spec.js
+++ b/spec/frontend/work_items/components/work_item_parent_spec.js
@@ -87,7 +87,6 @@ describe('WorkItemParent component', () => {
headerText: 'Assign parent',
category: 'tertiary',
loading: false,
- noCaret: true,
isCheckCentered: true,
searchable: true,
searching: false,
@@ -96,7 +95,6 @@ describe('WorkItemParent component', () => {
toggleText: 'None',
searchPlaceholder: 'Search',
resetButtonLabel: 'Unassign',
- block: true,
});
});
@@ -104,14 +102,12 @@ describe('WorkItemParent component', () => {
createComponent({ canUpdate: false, parent: mockParentWidgetResponse });
expect(findCollapsibleListbox().exists()).toBe(false);
- expect(findParentText().exists()).toBe(true);
expect(findParentText().text()).toBe('Objective 101');
});
it('shows loading while searching', async () => {
await findCollapsibleListbox().vm.$emit('shown');
expect(findCollapsibleListbox().props('searching')).toBe(true);
- expect(findCollapsibleListbox().props('no-caret')).toBeUndefined();
});
});
@@ -170,7 +166,6 @@ describe('WorkItemParent component', () => {
describe('listbox', () => {
const selectWorkItem = async (workItem) => {
- await findCollapsibleListbox().vm.$emit('shown');
await findCollapsibleListbox().vm.$emit('select', workItem);
};
diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb
index 997f9e6eac7..14f99f144b2 100644
--- a/spec/helpers/environments_helper_spec.rb
+++ b/spec/helpers/environments_helper_spec.rb
@@ -23,8 +23,8 @@ RSpec.describe EnvironmentsHelper, feature_category: :environment_management do
'settings_path' => edit_project_settings_integration_path(project, 'prometheus'),
'clusters_path' => project_clusters_path(project),
'current_environment_name' => environment.name,
- 'documentation_path' => help_page_path('administration/monitoring/prometheus/index.md'),
- 'add_dashboard_documentation_path' => help_page_path('operations/metrics/dashboards/index.md', anchor: 'add-a-new-dashboard-to-your-project'),
+ 'documentation_path' => help_page_path('administration/monitoring/prometheus/index'),
+ 'add_dashboard_documentation_path' => help_page_path('operations/metrics/dashboards/index', anchor: 'add-a-new-dashboard-to-your-project'),
'empty_getting_started_svg_path' => match_asset_path('/assets/illustrations/monitoring/getting_started.svg'),
'empty_loading_svg_path' => match_asset_path('/assets/illustrations/monitoring/loading.svg'),
'empty_no_data_svg_path' => match_asset_path('/assets/illustrations/monitoring/no_data.svg'),
diff --git a/spec/helpers/ide_helper_spec.rb b/spec/helpers/ide_helper_spec.rb
index 47500b8e21e..d5d7f8f72b3 100644
--- a/spec/helpers/ide_helper_spec.rb
+++ b/spec/helpers/ide_helper_spec.rb
@@ -101,7 +101,7 @@ RSpec.describe IdeHelper, feature_category: :web_ide do
'user-preferences-path' => profile_preferences_path,
'sign-in-path' => 'test-sign-in-path',
'new-web-ide-help-page-path' =>
- help_page_path('user/project/web_ide/index.md', anchor: 'vscode-reimplementation'),
+ help_page_path('user/project/web_ide/index', anchor: 'vscode-reimplementation'),
'csp-nonce' => 'test-csp-nonce',
'ide-remote-path' => ide_remote_path(remote_host: ':remote_host', remote_path: ':remote_path')
}
diff --git a/spec/helpers/operations_helper_spec.rb b/spec/helpers/operations_helper_spec.rb
index 9e50712a386..e018ab41a83 100644
--- a/spec/helpers/operations_helper_spec.rb
+++ b/spec/helpers/operations_helper_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe OperationsHelper do
it 'returns the correct values' do
expect(subject).to eq(
- 'alerts_setup_url' => help_page_path('operations/incident_management/integrations.md', anchor: 'configuration'),
+ 'alerts_setup_url' => help_page_path('operations/incident_management/integrations', anchor: 'configuration'),
'alerts_usage_url' => project_alert_management_index_path(project),
'prometheus_form_path' => project_settings_integration_path(project, prometheus_integration),
'prometheus_reset_key_path' => reset_alerting_token_project_settings_operations_path(project),
diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
index 213dee0d19d..f70b38377d8 100644
--- a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
@@ -422,11 +422,12 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
describe '#create_batched_job!' do
let(:batched_migration) do
- create(:batched_background_migration,
- batch_size: 999,
- sub_batch_size: 99,
- pause_ms: 250
- )
+ create(
+ :batched_background_migration,
+ batch_size: 999,
+ sub_batch_size: 99,
+ pause_ms: 250
+ )
end
it 'creates a batched_job with the correct batch configuration' do
diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb
index 8d74d16f4e5..bbcb65109ce 100644
--- a/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb
@@ -32,17 +32,17 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, '
end
it 'runs the migration job' do
- expect(job_class).to receive(:new)
- .with(start_id: 1,
- end_id: 10,
- batch_table: 'events',
- batch_column: 'id',
- sub_batch_size: 1,
- pause_ms: pause_ms,
- job_arguments: active_migration.job_arguments,
- connection: connection,
- sub_batch_exception: sub_batch_exception)
- .and_return(job_instance)
+ expect(job_class).to receive(:new).with(
+ start_id: 1,
+ end_id: 10,
+ batch_table: 'events',
+ batch_column: 'id',
+ sub_batch_size: 1,
+ pause_ms: pause_ms,
+ job_arguments: active_migration.job_arguments,
+ connection: connection,
+ sub_batch_exception: sub_batch_exception
+ ).and_return(job_instance)
expect(job_instance).to receive(:perform).with(no_args)
diff --git a/spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb b/spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb
index 1f256de35ec..8f380a8229c 100644
--- a/spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb
@@ -5,11 +5,14 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::BackgroundMigration::PrometheusMetrics, :prometheus do
describe '#track' do
let(:job_record) do
- build(:batched_background_migration_job, :succeeded,
- started_at: Time.current - 2.minutes,
- finished_at: Time.current - 1.minute,
- updated_at: Time.current,
- metrics: { 'timings' => { 'update_all' => [0.05, 0.2, 0.4, 0.9, 4] } })
+ build(
+ :batched_background_migration_job,
+ :succeeded,
+ started_at: Time.current - 2.minutes,
+ finished_at: Time.current - 1.minute,
+ updated_at: Time.current,
+ metrics: { 'timings' => { 'update_all' => [0.05, 0.2, 0.4, 0.9, 4] } }
+ )
end
let(:labels) { job_record.batched_migration.prometheus_labels }
diff --git a/spec/lib/gitlab/database/bulk_update_spec.rb b/spec/lib/gitlab/database/bulk_update_spec.rb
index fa519cffd6b..2f0859dba74 100644
--- a/spec/lib/gitlab/database/bulk_update_spec.rb
+++ b/spec/lib/gitlab/database/bulk_update_spec.rb
@@ -92,7 +92,7 @@ RSpec.describe Gitlab::Database::BulkUpdate do
end
context 'validates prepared_statements support', :reestablished_active_record_base,
- :suppress_gitlab_schemas_validate_connection do
+ :suppress_gitlab_schemas_validate_connection do
using RSpec::Parameterized::TableSyntax
where(:prepared_statements) do
diff --git a/spec/lib/gitlab/database/loose_foreign_keys_spec.rb b/spec/lib/gitlab/database/loose_foreign_keys_spec.rb
index 552df64096a..1824a50cb28 100644
--- a/spec/lib/gitlab/database/loose_foreign_keys_spec.rb
+++ b/spec/lib/gitlab/database/loose_foreign_keys_spec.rb
@@ -8,14 +8,14 @@ RSpec.describe Gitlab::Database::LooseForeignKeys do
it 'all definitions have assigned a known gitlab_schema and on_delete' do
is_expected.to all(have_attributes(
- options: a_hash_including(
- column: be_a(String),
- gitlab_schema: be_in(Gitlab::Database.schemas_to_base_models.symbolize_keys.keys),
- on_delete: be_in([:async_delete, :async_nullify])
- ),
- from_table: be_a(String),
- to_table: be_a(String)
- ))
+ options: a_hash_including(
+ column: be_a(String),
+ gitlab_schema: be_in(Gitlab::Database.schemas_to_base_models.symbolize_keys.keys),
+ on_delete: be_in([:async_delete, :async_nullify])
+ ),
+ from_table: be_a(String),
+ to_table: be_a(String)
+ ))
end
context 'ensure keys are sorted' do
diff --git a/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb b/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
index 476b5f3a784..4d7c51a3fbf 100644
--- a/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
@@ -13,9 +13,11 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#check_constraint_name' do
it 'returns a valid constraint name' do
- name = model.check_constraint_name(:this_is_a_very_long_table_name,
- :with_a_very_long_column_name,
- :with_a_very_long_type)
+ name = model.check_constraint_name(
+ :this_is_a_very_long_table_name,
+ :with_a_very_long_column_name,
+ :with_a_very_long_type
+ )
expect(name).to be_an_instance_of(String)
expect(name).to start_with('check_')
@@ -404,9 +406,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#add_text_limit' do
context 'when it is called with the default options' do
it 'calls add_check_constraint with an infered constraint name and validate: true' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'max_length')
check = "char_length(name) <= 255"
expect(model).to receive(:check_constraint_name).and_call_original
@@ -440,9 +440,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#validate_text_limit' do
context 'when constraint_name is not provided' do
it 'calls validate_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'max_length')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:validate_check_constraint)
@@ -468,9 +466,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#remove_text_limit' do
context 'when constraint_name is not provided' do
it 'calls remove_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'max_length')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:remove_check_constraint)
@@ -496,9 +492,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#check_text_limit_exists?' do
context 'when constraint_name is not provided' do
it 'calls check_constraint_exists? with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'max_length')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:check_constraint_exists?)
@@ -524,9 +518,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#add_not_null_constraint' do
context 'when it is called with the default options' do
it 'calls add_check_constraint with an infered constraint name and validate: true' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'not_null')
check = "name IS NOT NULL"
expect(model).to receive(:column_is_nullable?).and_return(true)
@@ -571,9 +563,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#validate_not_null_constraint' do
context 'when constraint_name is not provided' do
it 'calls validate_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'not_null')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:validate_check_constraint)
@@ -599,9 +589,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#remove_not_null_constraint' do
context 'when constraint_name is not provided' do
it 'calls remove_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'not_null')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:remove_check_constraint)
@@ -627,9 +615,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#check_not_null_constraint_exists?' do
context 'when constraint_name is not provided' do
it 'calls check_constraint_exists? with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'not_null')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:check_constraint_exists?)
diff --git a/spec/lib/gitlab/database/migrations/instrumentation_spec.rb b/spec/lib/gitlab/database/migrations/instrumentation_spec.rb
index a12e0909dc2..81368dde94d 100644
--- a/spec/lib/gitlab/database/migrations/instrumentation_spec.rb
+++ b/spec/lib/gitlab/database/migrations/instrumentation_spec.rb
@@ -75,8 +75,12 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
context 'on successful execution' do
subject do
- instrumentation.observe(version: migration_version, name: migration_name,
- connection: connection, meta: migration_meta) {}
+ instrumentation.observe(
+ version: migration_version,
+ name: migration_name,
+ connection: connection,
+ meta: migration_meta
+ ) {}
end
it 'records a valid observation', :aggregate_failures do
@@ -98,8 +102,12 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
with_them do
subject(:observe) do
- instrumentation.observe(version: migration_version, name: migration_name,
- connection: connection, meta: migration_meta) { raise exception, error_message }
+ instrumentation.observe(
+ version: migration_version,
+ name: migration_name,
+ connection: connection,
+ meta: migration_meta
+ ) { raise exception, error_message }
end
context 'retrieving observations' do
diff --git a/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb b/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
index 31a194ae883..660c4347ffa 100644
--- a/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
+++ b/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
@@ -80,8 +80,11 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
end
subject(:sample_migration) do
- described_class.new(result_dir: result_dir, connection: connection,
- from_id: from_id).run_jobs(for_duration: 1.minute)
+ described_class.new(
+ result_dir: result_dir,
+ connection: connection,
+ from_id: from_id
+ ).run_jobs(for_duration: 1.minute)
end
it 'runs sampled jobs from the batched background migration' do
@@ -125,12 +128,19 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
calls << args
end
- queue_migration(migration_name, table_name, :id,
- job_interval: 5.minutes,
- batch_size: 100)
+ queue_migration(
+ migration_name,
+ table_name,
+ :id,
+ job_interval: 5.minutes,
+ batch_size: 100
+ )
- described_class.new(result_dir: result_dir, connection: connection,
- from_id: from_id).run_jobs(for_duration: 3.minutes)
+ described_class.new(
+ result_dir: result_dir,
+ connection: connection,
+ from_id: from_id
+ ).run_jobs(for_duration: 3.minutes)
expect(calls).not_to be_empty
end
@@ -142,13 +152,19 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
calls << args
end
- queue_migration(migration_name, table_name, :id,
- job_interval: 5.minutes,
- batch_size: num_rows_in_table * 2,
- sub_batch_size: num_rows_in_table * 2)
+ queue_migration(
+ migration_name,
+ table_name, :id,
+ job_interval: 5.minutes,
+ batch_size: num_rows_in_table * 2,
+ sub_batch_size: num_rows_in_table * 2
+ )
- described_class.new(result_dir: result_dir, connection: connection,
- from_id: from_id).run_jobs(for_duration: 3.minutes)
+ described_class.new(
+ result_dir: result_dir,
+ connection: connection,
+ from_id: from_id
+ ).run_jobs(for_duration: 3.minutes)
expect(calls.size).to eq(1)
end
@@ -161,13 +177,20 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
calls << args
end
- queue_migration(migration_name, table_name, :id,
- job_interval: 5.minutes,
- batch_size: num_rows_in_table * 2,
- sub_batch_size: num_rows_in_table * 2)
-
- described_class.new(result_dir: result_dir, connection: connection,
- from_id: from_id).run_jobs(for_duration: 3.minutes)
+ queue_migration(
+ migration_name,
+ table_name,
+ :id,
+ job_interval: 5.minutes,
+ batch_size: num_rows_in_table * 2,
+ sub_batch_size: num_rows_in_table * 2
+ )
+
+ described_class.new(
+ result_dir: result_dir,
+ connection: connection,
+ from_id: from_id
+ ).run_jobs(for_duration: 3.minutes)
expect(calls.count).to eq(0)
end
@@ -181,26 +204,41 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
it 'runs all pending jobs based on the last migration id' do
old_migration = define_background_migration(migration_name)
- queue_migration(migration_name, table_name, :id,
- job_interval: 5.minutes,
- batch_size: 100)
+ queue_migration(
+ migration_name,
+ table_name,
+ :id,
+ job_interval: 5.minutes,
+ batch_size: 100
+ )
last_id
new_migration = define_background_migration('NewMigration') { travel 1.second }
- queue_migration('NewMigration', table_name, :id,
- job_interval: 5.minutes,
- batch_size: 10,
- sub_batch_size: 5)
+ queue_migration(
+ 'NewMigration',
+ table_name,
+ :id,
+ job_interval: 5.minutes,
+ batch_size: 10,
+ sub_batch_size: 5
+ )
other_new_migration = define_background_migration('NewMigration2') { travel 2.seconds }
- queue_migration('NewMigration2', table_name, :id,
- job_interval: 5.minutes,
- batch_size: 10,
- sub_batch_size: 5)
+ queue_migration(
+ 'NewMigration2',
+ table_name,
+ :id,
+ job_interval: 5.minutes,
+ batch_size: 10,
+ sub_batch_size: 5
+ )
expect_migration_runs(new_migration => 3, other_new_migration => 2, old_migration => 0) do
- described_class.new(result_dir: result_dir, connection: connection,
- from_id: last_id).run_jobs(for_duration: 5.seconds)
+ described_class.new(
+ result_dir: result_dir,
+ connection: connection,
+ from_id: last_id
+ ).run_jobs(for_duration: 5.seconds)
end
end
end
diff --git a/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb b/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb
index 04940028aee..eb78d836be0 100644
--- a/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb
@@ -57,17 +57,19 @@ RSpec.describe Gitlab::Database::Partitioning::DetachedPartitionDropper do
SQL
end
- Postgresql::DetachedPartition.create!(table_name: name,
- drop_after: drop_after)
+ Postgresql::DetachedPartition.create!(table_name: name, drop_after: drop_after)
end
describe '#perform' do
context 'when the partition should not be dropped yet' do
it 'does not drop the partition' do
- create_partition(name: :_test_partition,
- from: 2.months.ago, to: 1.month.ago,
- attached: false,
- drop_after: 1.day.from_now)
+ create_partition(
+ name: :_test_partition,
+ from: 2.months.ago,
+ to: 1.month.ago,
+ attached: false,
+ drop_after: 1.day.from_now
+ )
dropper.perform
@@ -77,11 +79,13 @@ RSpec.describe Gitlab::Database::Partitioning::DetachedPartitionDropper do
context 'with a partition to drop' do
before do
- create_partition(name: :_test_partition,
- from: 2.months.ago,
- to: 1.month.ago.beginning_of_month,
- attached: false,
- drop_after: 1.second.ago)
+ create_partition(
+ name: :_test_partition,
+ from: 2.months.ago,
+ to: 1.month.ago.beginning_of_month,
+ attached: false,
+ drop_after: 1.second.ago
+ )
end
it 'drops the partition' do
@@ -159,11 +163,13 @@ RSpec.describe Gitlab::Database::Partitioning::DetachedPartitionDropper do
context 'when the partition to drop is still attached to its table' do
before do
- create_partition(name: :_test_partition,
- from: 2.months.ago,
- to: 1.month.ago.beginning_of_month,
- attached: true,
- drop_after: 1.second.ago)
+ create_partition(
+ name: :_test_partition,
+ from: 2.months.ago,
+ to: 1.month.ago.beginning_of_month,
+ attached: true,
+ drop_after: 1.second.ago
+ )
end
it 'does not drop the partition, but does remove the DetachedPartition entry' do
@@ -192,17 +198,21 @@ RSpec.describe Gitlab::Database::Partitioning::DetachedPartitionDropper do
context 'with multiple partitions to drop' do
before do
- create_partition(name: :_test_partition_1,
- from: 3.months.ago,
- to: 2.months.ago,
- attached: false,
- drop_after: 1.second.ago)
-
- create_partition(name: :_test_partition_2,
- from: 2.months.ago,
- to: 1.month.ago,
- attached: false,
- drop_after: 1.second.ago)
+ create_partition(
+ name: :_test_partition_1,
+ from: 3.months.ago,
+ to: 2.months.ago,
+ attached: false,
+ drop_after: 1.second.ago
+ )
+
+ create_partition(
+ name: :_test_partition_2,
+ from: 2.months.ago,
+ to: 1.month.ago,
+ attached: false,
+ drop_after: 1.second.ago
+ )
end
it 'drops both partitions' do
diff --git a/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb b/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
index 3afa338fdf7..8b18e5b6d08 100644
--- a/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
@@ -235,8 +235,12 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy, feature_category
subject { described_class.new(model, partitioning_key, retain_for: 3.months).extra_partitions }
it 'prunes the unbounded partition ending 2020-05-01' do
- min_value_to_may = Gitlab::Database::Partitioning::TimePartition.new(model.table_name, nil, '2020-05-01',
- partition_name: '_test_partitioned_test_000000')
+ min_value_to_may = Gitlab::Database::Partitioning::TimePartition.new(
+ model.table_name,
+ nil,
+ '2020-05-01',
+ partition_name: '_test_partitioned_test_000000'
+ )
expect(subject).to contain_exactly(min_value_to_may)
end
@@ -247,8 +251,18 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy, feature_category
it 'prunes the unbounded partition and the partition for May-June' do
expect(subject).to contain_exactly(
- Gitlab::Database::Partitioning::TimePartition.new(model.table_name, nil, '2020-05-01', partition_name: '_test_partitioned_test_000000'),
- Gitlab::Database::Partitioning::TimePartition.new(model.table_name, '2020-05-01', '2020-06-01', partition_name: '_test_partitioned_test_202005')
+ Gitlab::Database::Partitioning::TimePartition.new(
+ model.table_name,
+ nil,
+ '2020-05-01',
+ partition_name: '_test_partitioned_test_000000'
+ ),
+ Gitlab::Database::Partitioning::TimePartition.new(
+ model.table_name,
+ '2020-05-01',
+ '2020-06-01',
+ partition_name: '_test_partitioned_test_202005'
+ )
)
end
@@ -257,8 +271,18 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy, feature_category
it 'prunes empty partitions' do
expect(subject).to contain_exactly(
- Gitlab::Database::Partitioning::TimePartition.new(model.table_name, nil, '2020-05-01', partition_name: '_test_partitioned_test_000000'),
- Gitlab::Database::Partitioning::TimePartition.new(model.table_name, '2020-05-01', '2020-06-01', partition_name: '_test_partitioned_test_202005')
+ Gitlab::Database::Partitioning::TimePartition.new(
+ model.table_name,
+ nil,
+ '2020-05-01',
+ partition_name: '_test_partitioned_test_000000'
+ ),
+ Gitlab::Database::Partitioning::TimePartition.new(
+ model.table_name,
+ '2020-05-01',
+ '2020-06-01',
+ partition_name: '_test_partitioned_test_202005'
+ )
)
end
diff --git a/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb b/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb
index ac4d345271e..9ca0a1b6e57 100644
--- a/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb
@@ -15,9 +15,12 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy, feature_cate
let(:detach_partition_if) { double('detach_partition_if') }
subject(:strategy) do
- described_class.new(model, :partition,
- next_partition_if: next_partition_if,
- detach_partition_if: detach_partition_if)
+ described_class.new(
+ model,
+ :partition,
+ next_partition_if: next_partition_if,
+ detach_partition_if: detach_partition_if
+ )
end
before do
@@ -213,9 +216,9 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy, feature_cate
include PartitionedTable
partitioned_by :partition,
- strategy: :sliding_list,
- next_partition_if: proc { false },
- detach_partition_if: proc { false }
+ strategy: :sliding_list,
+ next_partition_if: proc { false },
+ detach_partition_if: proc { false }
end
end.to raise_error(/ignored_columns/)
end
@@ -228,9 +231,9 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy, feature_cate
self.ignored_columns = [:partition]
partitioned_by :partition,
- strategy: :sliding_list,
- next_partition_if: proc { false },
- detach_partition_if: proc { false }
+ strategy: :sliding_list,
+ next_partition_if: proc { false },
+ detach_partition_if: proc { false }
end
end.not_to raise_error
end
@@ -255,9 +258,9 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy, feature_cate
detach_partition?(...)
end
partitioned_by :partition,
- strategy: :sliding_list,
- next_partition_if: method(:next_partition_if_wrapper),
- detach_partition_if: method(:detach_partition_if_wrapper)
+ strategy: :sliding_list,
+ next_partition_if: method(:next_partition_if_wrapper),
+ detach_partition_if: method(:detach_partition_if_wrapper)
def self.next_partition?(current_partition); end
diff --git a/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb b/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
index a81c8a5a49c..aa644885306 100644
--- a/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
@@ -99,8 +99,11 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::IndexHelpers do
expect(migration).to receive(:add_index)
.with(table_name, column_name, { name: index_name, where: 'x > 0', unique: true })
- migration.add_concurrent_partitioned_index(table_name, column_name,
- { name: index_name, where: 'x > 0', unique: true })
+ migration.add_concurrent_partitioned_index(
+ table_name,
+ column_name,
+ { name: index_name, where: 'x > 0', unique: true }
+ )
end
end
diff --git a/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb b/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb
index 6a947044317..182b6960384 100644
--- a/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb
@@ -51,13 +51,15 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
end
it 'delegates to a method on List::ConvertTable' do
- expect_next_instance_of(Gitlab::Database::Partitioning::List::ConvertTable,
- migration_context: migration,
- table_name: source_table,
- parent_table_name: partitioned_table,
- partitioning_column: partition_column,
- zero_partition_value: min_date,
- **extra_options) do |converter|
+ expect_next_instance_of(
+ Gitlab::Database::Partitioning::List::ConvertTable,
+ migration_context: migration,
+ table_name: source_table,
+ parent_table_name: partitioned_table,
+ partitioning_column: partition_column,
+ zero_partition_value: min_date,
+ **extra_options
+ ) do |converter|
expect(converter).to receive(expected_method)
end
@@ -70,11 +72,13 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
let(:lock_tables) { [source_table] }
let(:expected_method) { :partition }
let(:migrate) do
- migration.convert_table_to_first_list_partition(table_name: source_table,
- partitioning_column: partition_column,
- parent_table_name: partitioned_table,
- initial_partitioning_value: min_date,
- lock_tables: lock_tables)
+ migration.convert_table_to_first_list_partition(
+ table_name: source_table,
+ partitioning_column: partition_column,
+ parent_table_name: partitioned_table,
+ initial_partitioning_value: min_date,
+ lock_tables: lock_tables
+ )
end
end
end
@@ -83,10 +87,12 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
it_behaves_like 'delegates to ConvertTable' do
let(:expected_method) { :revert_partitioning }
let(:migrate) do
- migration.revert_converting_table_to_first_list_partition(table_name: source_table,
- partitioning_column: partition_column,
- parent_table_name: partitioned_table,
- initial_partitioning_value: min_date)
+ migration.revert_converting_table_to_first_list_partition(
+ table_name: source_table,
+ partitioning_column: partition_column,
+ parent_table_name: partitioned_table,
+ initial_partitioning_value: min_date
+ )
end
end
end
@@ -95,11 +101,13 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
it_behaves_like 'delegates to ConvertTable' do
let(:expected_method) { :prepare_for_partitioning }
let(:migrate) do
- migration.prepare_constraint_for_list_partitioning(table_name: source_table,
- partitioning_column: partition_column,
- parent_table_name: partitioned_table,
- initial_partitioning_value: min_date,
- async: false)
+ migration.prepare_constraint_for_list_partitioning(
+ table_name: source_table,
+ partitioning_column: partition_column,
+ parent_table_name: partitioned_table,
+ initial_partitioning_value: min_date,
+ async: false
+ )
end
end
end
@@ -108,10 +116,12 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
it_behaves_like 'delegates to ConvertTable' do
let(:expected_method) { :revert_preparation_for_partitioning }
let(:migrate) do
- migration.revert_preparing_constraint_for_list_partitioning(table_name: source_table,
- partitioning_column: partition_column,
- parent_table_name: partitioned_table,
- initial_partitioning_value: min_date)
+ migration.revert_preparing_constraint_for_list_partitioning(
+ table_name: source_table,
+ partitioning_column: partition_column,
+ parent_table_name: partitioned_table,
+ initial_partitioning_value: min_date
+ )
end
end
end
diff --git a/spec/lib/gitlab/database/postgres_constraint_spec.rb b/spec/lib/gitlab/database/postgres_constraint_spec.rb
index 75084a69115..140180540e0 100644
--- a/spec/lib/gitlab/database/postgres_constraint_spec.rb
+++ b/spec/lib/gitlab/database/postgres_constraint_spec.rb
@@ -51,9 +51,11 @@ RSpec.describe Gitlab::Database::PostgresConstraint, type: :model do
subject(:check_constraints) { described_class.check_constraints.by_table_identifier(table_identifier) }
it 'finds check constraints for the table' do
- expect(check_constraints.map(&:name)).to contain_exactly(check_constraint_a_positive,
- check_constraint_a_gt_b,
- invalid_constraint_a)
+ expect(check_constraints.map(&:name)).to contain_exactly(
+ check_constraint_a_positive,
+ check_constraint_a_gt_b,
+ invalid_constraint_a
+ )
end
it 'includes columns for the check constraints', :aggregate_failures do
@@ -108,8 +110,12 @@ RSpec.describe Gitlab::Database::PostgresConstraint, type: :model do
describe '#including_column' do
it 'only matches constraints on the given column' do
constraints_on_a = described_class.by_table_identifier(table_identifier).including_column('a').map(&:name)
- expect(constraints_on_a).to contain_exactly(check_constraint_a_positive, check_constraint_a_gt_b,
- unique_constraint_a, invalid_constraint_a)
+ expect(constraints_on_a).to contain_exactly(
+ check_constraint_a_positive,
+ check_constraint_a_gt_b,
+ unique_constraint_a,
+ invalid_constraint_a
+ )
end
end
diff --git a/spec/lib/gitlab/database/tables_truncate_spec.rb b/spec/lib/gitlab/database/tables_truncate_spec.rb
index e41c7d34378..350e36ff1f1 100644
--- a/spec/lib/gitlab/database/tables_truncate_spec.rb
+++ b/spec/lib/gitlab/database/tables_truncate_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_base,
- :suppress_gitlab_schemas_validate_connection, feature_category: :cell do
+ :suppress_gitlab_schemas_validate_connection, feature_category: :cell do
include MigrationsHelpers
let(:min_batch_size) { 1 }
diff --git a/spec/migrations/20231016001000_fix_design_user_mentions_design_id_note_id_index_for_self_managed_spec.rb b/spec/migrations/20231016001000_fix_design_user_mentions_design_id_note_id_index_for_self_managed_spec.rb
new file mode 100644
index 00000000000..8d890bb7cac
--- /dev/null
+++ b/spec/migrations/20231016001000_fix_design_user_mentions_design_id_note_id_index_for_self_managed_spec.rb
@@ -0,0 +1,114 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe FixDesignUserMentionsDesignIdNoteIdIndexForSelfManaged, feature_category: :database do
+ let(:connection) { described_class.new.connection }
+ let(:design_user_mentions) { table(:design_user_mentions) }
+
+ shared_examples 'index `design_user_mentions_on_design_id_and_note_id_unique_index` already exists' do
+ it 'does not swap the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ index = connection.indexes(:design_user_mentions).find do |i|
+ i.name == 'design_user_mentions_on_design_id_and_note_id_unique_index'
+ end
+ expect(index.columns).to eq(%w[design_id note_id])
+ }
+
+ migration.after -> {
+ index = connection.indexes(:design_user_mentions).find do |i|
+ i.name == 'design_user_mentions_on_design_id_and_note_id_unique_index'
+ end
+ expect(index.columns).to eq(%w[design_id note_id])
+ }
+ end
+ end
+ end
+ end
+
+ describe '#up' do
+ before do
+ # rubocop:disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to(
+ receive(:com_or_dev_or_test_but_not_jh?).and_return(com_or_dev_or_test_but_not_jh?)
+ )
+ # rubocop:enable RSpec/AnyInstanceOf
+ end
+
+ context 'when GitLab.com, dev, or test' do
+ let(:com_or_dev_or_test_but_not_jh?) { true }
+
+ it_behaves_like 'index `design_user_mentions_on_design_id_and_note_id_unique_index` already exists'
+ end
+
+ context 'when self-managed instance' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ context "when index does not exist" do
+ before do
+ connection.execute('DROP INDEX IF EXISTS design_user_mentions_on_design_id_and_note_id_unique_index')
+ end
+
+ after do
+ connection.execute('CREATE UNIQUE INDEX IF NOT EXISTS
+ design_user_mentions_on_design_id_and_note_id_unique_index
+ ON design_user_mentions (design_id, note_id)')
+ end
+
+ it 'creates the index' do
+ disable_migrations_output { migrate! }
+
+ index = connection.indexes(:design_user_mentions).find do |i|
+ i.name == 'design_user_mentions_on_design_id_and_note_id_unique_index'
+ end
+
+ expect(index.columns).to eq(%w[design_id note_id])
+ end
+ end
+
+ context "when index does exist" do
+ it_behaves_like 'index `design_user_mentions_on_design_id_and_note_id_unique_index` already exists'
+ end
+
+ context "when index does exists on the int4 column" do
+ before do
+ connection.execute('DROP INDEX IF EXISTS design_user_mentions_on_design_id_and_note_id_unique_index')
+ connection.execute(
+ 'ALTER TABLE design_user_mentions ADD COLUMN IF NOT EXISTS note_id_convert_to_bigint integer'
+ )
+ connection.execute('CREATE UNIQUE INDEX
+ design_user_mentions_on_design_id_and_note_id_unique_index
+ ON design_user_mentions (design_id, note_id_convert_to_bigint)')
+ end
+
+ after do
+ connection.execute('DROP INDEX IF EXISTS design_user_mentions_on_design_id_and_note_id_unique_index')
+ connection.execute('ALTER TABLE design_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ connection.execute('CREATE UNIQUE INDEX
+ design_user_mentions_on_design_id_and_note_id_unique_index
+ ON design_user_mentions (design_id, note_id)')
+ end
+
+ it 'creates the index on the int8 column' do
+ index = connection.indexes(:design_user_mentions).find do |i|
+ i.name == 'design_user_mentions_on_design_id_and_note_id_unique_index'
+ end
+
+ expect(index.columns).to eq(%w[design_id note_id_convert_to_bigint])
+
+ disable_migrations_output { migrate! }
+
+ index = connection.indexes(:design_user_mentions).find do |i|
+ i.name == 'design_user_mentions_on_design_id_and_note_id_unique_index'
+ end
+
+ expect(index.columns).to eq(%w[design_id note_id])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/presenters/clusters/cluster_presenter_spec.rb b/spec/presenters/clusters/cluster_presenter_spec.rb
index 755f1ea6078..aacb696a88e 100644
--- a/spec/presenters/clusters/cluster_presenter_spec.rb
+++ b/spec/presenters/clusters/cluster_presenter_spec.rb
@@ -123,7 +123,7 @@ RSpec.describe Clusters::ClusterPresenter do
'clusters-path': clusterable_presenter.index_path,
'dashboard-endpoint': clusterable_presenter.metrics_dashboard_path(cluster),
'documentation-path': help_page_path('user/infrastructure/clusters/manage/clusters_health'),
- 'add-dashboard-documentation-path': help_page_path('operations/metrics/dashboards/index.md', anchor: 'add-a-new-dashboard-to-your-project'),
+ 'add-dashboard-documentation-path': help_page_path('operations/metrics/dashboards/index', anchor: 'add-a-new-dashboard-to-your-project'),
'empty-getting-started-svg-path': match_asset_path('/assets/illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path': match_asset_path('/assets/illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path': match_asset_path('/assets/illustrations/monitoring/no_data.svg'),
diff --git a/spec/rubocop/cop/gitlab/doc_url_spec.rb b/spec/rubocop/cop/gitlab/doc_url_spec.rb
index 957edc8286b..fa055f9b2fe 100644
--- a/spec/rubocop/cop/gitlab/doc_url_spec.rb
+++ b/spec/rubocop/cop/gitlab/doc_url_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe RuboCop::Cop::Gitlab::DocUrl, feature_category: :shared do
it 'registers an offense' do
expect_offense(<<~RUBY)
'See [the docs](https://docs.gitlab.com/ee/user/permissions#roles).'
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `#help_page_url` instead of directly including link. See https://docs.gitlab.com/ee/development/documentation/#linking-to-help-in-ruby.
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `#help_page_url` instead of directly including link. See [...]
RUBY
end
end
@@ -19,7 +19,7 @@ RSpec.describe RuboCop::Cop::Gitlab::DocUrl, feature_category: :shared do
expect_offense(<<~'RUBY')
'See the docs: ' \
'https://docs.gitlab.com/ee/user/permissions#roles'
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `#help_page_url` instead of directly including link. See https://docs.gitlab.com/ee/development/documentation/#linking-to-help-in-ruby.
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `#help_page_url` instead of directly including link. See [...]
RUBY
end
end
@@ -30,7 +30,7 @@ RSpec.describe RuboCop::Cop::Gitlab::DocUrl, feature_category: :shared do
<<-HEREDOC
See the docs:
https://docs.gitlab.com/ee/user/permissions#roles
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `#help_page_url` instead of directly including link. See https://docs.gitlab.com/ee/development/documentation/#linking-to-help-in-ruby.
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `#help_page_url` instead of directly including link. See [...]
HEREDOC
RUBY
end
diff --git a/spec/serializers/issue_entity_spec.rb b/spec/serializers/issue_entity_spec.rb
index a8fd96a03bb..1faf4c6fe4c 100644
--- a/spec/serializers/issue_entity_spec.rb
+++ b/spec/serializers/issue_entity_spec.rb
@@ -149,7 +149,7 @@ RSpec.describe IssueEntity do
end
it 'returns archived project doc' do
- expect(subject[:archived_project_docs_path]).to eq('/help/user/project/settings/index.md#archive-a-project')
+ expect(subject[:archived_project_docs_path]).to eq('/help/user/project/settings/index#archive-a-project')
end
end
end
diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb
index 8c577749107..94db1c55a90 100644
--- a/spec/support/shared_examples/features/work_items_shared_examples.rb
+++ b/spec/support/shared_examples/features/work_items_shared_examples.rb
@@ -371,12 +371,12 @@ RSpec.shared_examples 'work items milestone' do
it 'searches and sets or removes milestone for the work item' do
click_button s_('WorkItem|Add to milestone')
send_keys "\"#{milestone.title}\""
- click_button milestone.title
+ select_listbox_item(milestone.title, exact_text: true)
expect(page).to have_button(milestone.title)
click_button milestone.title
- click_button s_('WorkItem|No milestone')
+ select_listbox_item(s_('WorkItem|No milestone'), exact_text: true)
expect(page).to have_button(s_('WorkItem|Add to milestone'))
end