summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-08-24 18:12:18 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-08-24 18:12:18 +0000
commit06c57a837802f789b9276e23d7f505d95270f033 (patch)
treeb45a80632d84a459b11376e1b575928c911eb045 /spec
parent53ab147992c8e791582f625c80811fdda5ba4d5a (diff)
downloadgitlab-ce-06c57a837802f789b9276e23d7f505d95270f033.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/help_dropdown_spec.rb3
-rw-r--r--spec/frontend/blob/blob_blame_link_spec.js47
-rw-r--r--spec/frontend/blob/blob_links_tracking_spec.js4
-rw-r--r--spec/frontend/boards/components/board_card_move_to_position_spec.js70
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js126
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/code_block_bubble_menu_spec.js4
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js7
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js20
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js7
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js75
-rw-r--r--spec/frontend/work_items/components/work_item_information_spec.js9
-rw-r--r--spec/lib/gitlab/alert_management/payload/base_spec.rb22
-rw-r--r--spec/lib/gitlab/alert_management/payload/generic_spec.rb36
-rw-r--r--spec/lib/gitlab/background_migration/rename_task_system_note_to_checklist_item_spec.rb4
-rw-r--r--spec/requests/api/branches_spec.rb79
-rw-r--r--spec/support/shared_examples/graphql/resolvers/issuable_resolvers_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb8
17 files changed, 437 insertions, 88 deletions
diff --git a/spec/features/help_dropdown_spec.rb b/spec/features/help_dropdown_spec.rb
index db98f58240d..e64c19d4708 100644
--- a/spec/features/help_dropdown_spec.rb
+++ b/spec/features/help_dropdown_spec.rb
@@ -51,7 +51,8 @@ RSpec.describe "Help Dropdown", :js do
visit root_path
end
- it 'renders correct version badge variant' do
+ it 'renders correct version badge variant',
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/369850' do
page.within '.header-help' do
find('.header-help-dropdown-toggle').click
diff --git a/spec/frontend/blob/blob_blame_link_spec.js b/spec/frontend/blob/blob_blame_link_spec.js
new file mode 100644
index 00000000000..0d19177a11f
--- /dev/null
+++ b/spec/frontend/blob/blob_blame_link_spec.js
@@ -0,0 +1,47 @@
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import addBlameLink from '~/blob/blob_blame_link';
+
+describe('Blob links', () => {
+ const mouseoverEvent = new MouseEvent('mouseover', {
+ view: window,
+ bubbles: true,
+ cancelable: true,
+ });
+
+ beforeEach(() => {
+ setHTMLFixture(`
+ <div id="blob-content-holder">
+ <div class="line-numbers" data-blame-path="/blamePath">
+ <a id="L5" href="#L5" data-line-number="5" class="file-line-num js-line-links">5</a>
+ </div>
+ <pre id="LC5">Line 5 content</pre>
+ </div>
+ `);
+
+ addBlameLink('#blob-content-holder', 'js-line-links');
+ document.querySelector('.file-line-num').dispatchEvent(mouseoverEvent);
+ });
+
+ afterEach(() => {
+ resetHTMLFixture();
+ });
+
+ it('adds wrapper elements with correct classes', () => {
+ const wrapper = document.querySelector('.line-links');
+
+ expect(wrapper).toBeTruthy();
+ expect(wrapper.classList).toContain('diff-line-num');
+ });
+
+ it('adds blame link with correct classes and path', () => {
+ const blameLink = document.querySelector('.file-line-blame');
+ expect(blameLink).toBeTruthy();
+ expect(blameLink.getAttribute('href')).toBe('/blamePath#L5');
+ });
+
+ it('adds line link within wraper with correct classes and path', () => {
+ const lineLink = document.querySelector('.file-line-num');
+ expect(lineLink).toBeTruthy();
+ expect(lineLink.getAttribute('href')).toBe('#L5');
+ });
+});
diff --git a/spec/frontend/blob/blob_links_tracking_spec.js b/spec/frontend/blob/blob_links_tracking_spec.js
index 22e087bc180..8ef1e9f0ac9 100644
--- a/spec/frontend/blob/blob_links_tracking_spec.js
+++ b/spec/frontend/blob/blob_links_tracking_spec.js
@@ -15,7 +15,7 @@ describe('Blob links Tracking', () => {
beforeEach(() => {
setHTMLFixture(`
- <div id="blob-content-holder">
+ <div class="file-holder">
<div class="line-links diff-line-num">
<a href="#L5" class="file-line-blame"></a>
<a id="L5" href="#L5" data-line-number="5" class="file-line-num">5</a>
@@ -23,7 +23,7 @@ describe('Blob links Tracking', () => {
<pre id="LC5">Line 5 content</pre>
</div>
`);
- addBlobLinksTracking('#blob-content-holder', eventsToTrack);
+ addBlobLinksTracking();
jest.spyOn(Tracking, 'event');
});
diff --git a/spec/frontend/boards/components/board_card_move_to_position_spec.js b/spec/frontend/boards/components/board_card_move_to_position_spec.js
index f6c66baa6aa..01bad53d9e1 100644
--- a/spec/frontend/boards/components/board_card_move_to_position_spec.js
+++ b/spec/frontend/boards/components/board_card_move_to_position_spec.js
@@ -4,8 +4,7 @@ import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue';
-import { createStore } from '~/boards/stores';
-import { mockList, mockIssue2 } from 'jest/boards/mock_data';
+import { mockList, mockIssue2, mockIssue, mockIssue3, mockIssue4 } from 'jest/boards/mock_data';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
Vue.use(Vuex);
@@ -21,7 +20,26 @@ describe('Board Card Move to position', () => {
let store;
let dispatch;
- store = new Vuex.Store();
+ const createStoreOptions = () => {
+ const state = {
+ pageInfoByListId: {
+ 'gid://gitlab/List/1': {},
+ 'gid://gitlab/List/2': { hasNextPage: true },
+ },
+ };
+ const getters = {
+ getBoardItemsByList: () => () => [mockIssue, mockIssue2, mockIssue3, mockIssue4],
+ };
+ const actions = {
+ moveItem: jest.fn(),
+ };
+
+ return {
+ state,
+ getters,
+ actions,
+ };
+ };
const createComponent = (propsData) => {
wrapper = shallowMountExtended(BoardCardMoveToPosition, {
@@ -40,7 +58,7 @@ describe('Board Card Move to position', () => {
};
beforeEach(() => {
- store = createStore();
+ store = new Vuex.Store(createStoreOptions());
createComponent();
});
@@ -62,13 +80,26 @@ describe('Board Card Move to position', () => {
it('is opened on the click of vertical ellipsis and has 2 dropdown items when number of list items < 10', () => {
findMoveToPositionDropdown().vm.$emit('click');
-
expect(findDropdownItems()).toHaveLength(dropdownOptions.length);
});
+
+ it('is opened on the click of vertical ellipsis and has 1 dropdown items when number of list items > 10', () => {
+ wrapper.destroy();
+
+ createComponent({
+ list: {
+ ...mockList,
+ id: 'gid://gitlab/List/2',
+ },
+ });
+ findMoveToPositionDropdown().vm.$emit('click');
+ expect(findDropdownItems()).toHaveLength(1);
+ });
});
describe('Dropdown options', () => {
beforeEach(() => {
+ createComponent({ index: 1 });
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
dispatch = jest.spyOn(store, 'dispatch').mockImplementation(() => {});
});
@@ -78,12 +109,12 @@ describe('Board Card Move to position', () => {
});
it.each`
- dropdownIndex | dropdownLabel | startActionCalledTimes | trackLabel
- ${0} | ${BoardCardMoveToPosition.i18n.moveToStartText} | ${0} | ${'move_to_start'}
- ${1} | ${BoardCardMoveToPosition.i18n.moveToEndText} | ${1} | ${'move_to_end'}
+ dropdownIndex | dropdownLabel | trackLabel | moveAfterId | moveBeforeId
+ ${0} | ${BoardCardMoveToPosition.i18n.moveToStartText} | ${'move_to_start'} | ${mockIssue.id} | ${undefined}
+ ${1} | ${BoardCardMoveToPosition.i18n.moveToEndText} | ${'move_to_end'} | ${undefined} | ${mockIssue4.id}
`(
'on click of dropdown index $dropdownIndex with label $dropdownLabel should call moveItem action with tracking label $trackLabel',
- async ({ dropdownIndex, startActionCalledTimes, dropdownLabel, trackLabel }) => {
+ async ({ dropdownIndex, dropdownLabel, trackLabel, moveAfterId, moveBeforeId }) => {
await findEllipsesButton().vm.$emit('click');
expect(findDropdownItemAtIndex(dropdownIndex).text()).toBe(dropdownLabel);
@@ -98,18 +129,15 @@ describe('Board Card Move to position', () => {
label: trackLabel,
property: 'type_card',
});
- expect(dispatch).toHaveBeenCalledTimes(startActionCalledTimes);
- if (startActionCalledTimes) {
- expect(dispatch).toHaveBeenCalledWith('moveItem', {
- fromListId: mockList.id,
- itemId: mockIssue2.id,
- itemIid: mockIssue2.iid,
- itemPath: mockIssue2.referencePath,
- moveBeforeId: undefined,
- moveAfterId: undefined,
- toListId: mockList.id,
- });
- }
+ expect(dispatch).toHaveBeenCalledWith('moveItem', {
+ fromListId: mockList.id,
+ itemId: mockIssue2.id,
+ itemIid: mockIssue2.iid,
+ itemPath: mockIssue2.referencePath,
+ moveBeforeId,
+ moveAfterId,
+ toListId: mockList.id,
+ });
},
);
});
diff --git a/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js
new file mode 100644
index 00000000000..0700cf5d529
--- /dev/null
+++ b/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js
@@ -0,0 +1,126 @@
+import { BubbleMenuPlugin } from '@tiptap/extension-bubble-menu';
+import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue';
+import { createTestEditor } from '../../test_utils';
+
+jest.mock('@tiptap/extension-bubble-menu');
+
+describe('content_editor/components/bubble_menus/bubble_menu', () => {
+ let wrapper;
+ let tiptapEditor;
+ const pluginKey = 'key';
+ const shouldShow = jest.fn();
+ const tippyOptions = { placement: 'bottom' };
+ const pluginInitializationResult = {};
+
+ const buildEditor = () => {
+ tiptapEditor = createTestEditor();
+ };
+
+ const createWrapper = (propsData = {}) => {
+ wrapper = shallowMountExtended(BubbleMenu, {
+ provide: {
+ tiptapEditor,
+ },
+ propsData: {
+ pluginKey,
+ shouldShow,
+ tippyOptions,
+ ...propsData,
+ },
+ slots: {
+ default: '<div>menu content</div>',
+ },
+ });
+ };
+
+ const setupMocks = () => {
+ BubbleMenuPlugin.mockReturnValueOnce(pluginInitializationResult);
+ jest.spyOn(tiptapEditor, 'registerPlugin').mockImplementationOnce(() => true);
+ };
+
+ const invokeTippyEvent = (eventName, eventArgs) => {
+ const pluginConfig = BubbleMenuPlugin.mock.calls[0][0];
+
+ pluginConfig.tippyOptions[eventName](eventArgs);
+ };
+
+ beforeEach(() => {
+ buildEditor();
+ setupMocks();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('initializes BubbleMenuPlugin', async () => {
+ createWrapper({});
+
+ await nextTick();
+
+ expect(BubbleMenuPlugin).toHaveBeenCalledWith({
+ pluginKey,
+ editor: tiptapEditor,
+ shouldShow,
+ element: wrapper.vm.$el,
+ tippyOptions: expect.objectContaining({
+ onHidden: expect.any(Function),
+ onShow: expect.any(Function),
+ ...tippyOptions,
+ }),
+ });
+
+ expect(tiptapEditor.registerPlugin).toHaveBeenCalledWith(pluginInitializationResult);
+ });
+
+ it('does not render default slot by default', async () => {
+ createWrapper({});
+
+ await nextTick();
+
+ expect(wrapper.text()).not.toContain('menu content');
+ });
+
+ describe('when onShow event handler is invoked', () => {
+ const onShowArgs = {};
+
+ beforeEach(async () => {
+ createWrapper({});
+
+ await nextTick();
+
+ invokeTippyEvent('onShow', onShowArgs);
+ });
+
+ it('displays the menu content', () => {
+ expect(wrapper.text()).toContain('menu content');
+ });
+
+ it('emits show event', () => {
+ expect(wrapper.emitted('show')).toEqual([[onShowArgs]]);
+ });
+ });
+
+ describe('when onHidden event handler is invoked', () => {
+ const onHiddenArgs = {};
+
+ beforeEach(async () => {
+ createWrapper({});
+
+ await nextTick();
+
+ invokeTippyEvent('onShow', onHiddenArgs);
+ invokeTippyEvent('onHidden', onHiddenArgs);
+ });
+
+ it('displays the menu content', () => {
+ expect(wrapper.text()).not.toContain('menu content');
+ });
+
+ it('emits show event', () => {
+ expect(wrapper.emitted('hidden')).toEqual([[onHiddenArgs]]);
+ });
+ });
+});
diff --git a/spec/frontend/content_editor/components/bubble_menus/code_block_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/code_block_bubble_menu_spec.js
index f2c0ec59ccd..378b11f4ae9 100644
--- a/spec/frontend/content_editor/components/bubble_menus/code_block_bubble_menu_spec.js
+++ b/spec/frontend/content_editor/components/bubble_menus/code_block_bubble_menu_spec.js
@@ -1,4 +1,3 @@
-import { BubbleMenu } from '@tiptap/vue-2';
import {
GlDropdown,
GlDropdownForm,
@@ -11,6 +10,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent } from 'helpers/stub_component';
import CodeBlockBubbleMenu from '~/content_editor/components/bubble_menus/code_block_bubble_menu.vue';
import eventHubFactory from '~/helpers/event_hub_factory';
+import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue';
import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
import Diagram from '~/content_editor/extensions/diagram';
import codeBlockLanguageLoader from '~/content_editor/services/code_block_language_loader';
@@ -40,6 +40,7 @@ describe('content_editor/components/bubble_menus/code_block_bubble_menu', () =>
},
stubs: {
GlDropdownItem: stubComponent(GlDropdownItem),
+ BubbleMenu: stubComponent(BubbleMenu),
},
});
};
@@ -73,7 +74,6 @@ describe('content_editor/components/bubble_menus/code_block_bubble_menu', () =>
await emitEditorEvent({ event: 'transaction', tiptapEditor });
- expect(bubbleMenu.props('editor')).toBe(tiptapEditor);
expect(bubbleMenu.classes()).toEqual(['gl-shadow', 'gl-rounded-base', 'gl-bg-white']);
});
diff --git a/spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js
index 38ea9dc2b21..cce17176129 100644
--- a/spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js
+++ b/spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js
@@ -1,7 +1,8 @@
-import { BubbleMenu } from '@tiptap/vue-2';
import { mockTracking } from 'helpers/tracking_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import FormattingBubbleMenu from '~/content_editor/components/bubble_menus/formatting_bubble_menu.vue';
+import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue';
+import { stubComponent } from 'helpers/stub_component';
import {
BUBBLE_MENU_TRACKING_ACTION,
@@ -25,6 +26,9 @@ describe('content_editor/components/bubble_menus/formatting_bubble_menu', () =>
provide: {
tiptapEditor,
},
+ stubs: {
+ BubbleMenu: stubComponent(BubbleMenu),
+ },
});
};
@@ -41,7 +45,6 @@ describe('content_editor/components/bubble_menus/formatting_bubble_menu', () =>
buildWrapper();
const bubbleMenu = wrapper.findComponent(BubbleMenu);
- expect(bubbleMenu.props().editor).toBe(tiptapEditor);
expect(bubbleMenu.classes()).toEqual(['gl-shadow', 'gl-rounded-base', 'gl-bg-white']);
});
diff --git a/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js
index 04bf4efb7e2..7f8c770e503 100644
--- a/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js
+++ b/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js
@@ -1,8 +1,9 @@
import { GlLink, GlForm } from '@gitlab/ui';
-import { BubbleMenu } from '@tiptap/vue-2';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import LinkBubbleMenu from '~/content_editor/components/bubble_menus/link_bubble_menu.vue';
import eventHubFactory from '~/helpers/event_hub_factory';
+import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue';
+import { stubComponent } from 'helpers/stub_component';
import Link from '~/content_editor/extensions/link';
import { createTestEditor, emitEditorEvent } from '../../test_utils';
@@ -28,6 +29,9 @@ describe('content_editor/components/bubble_menus/link_bubble_menu', () => {
contentEditor,
eventHub,
},
+ stubs: {
+ BubbleMenu: stubComponent(BubbleMenu),
+ },
});
};
@@ -60,7 +64,6 @@ describe('content_editor/components/bubble_menus/link_bubble_menu', () => {
});
it('renders bubble menu component', async () => {
- expect(bubbleMenu.props('editor')).toBe(tiptapEditor);
expect(bubbleMenu.classes()).toEqual(['gl-shadow', 'gl-rounded-base', 'gl-bg-white']);
});
@@ -157,19 +160,6 @@ describe('content_editor/components/bubble_menus/link_bubble_menu', () => {
expect(to).toBe(18);
});
- it('shows the copy/edit/remove link buttons again if selection changes to another non-link and then back again to a link', async () => {
- expectLinkButtonsToExist(false);
-
- tiptapEditor.commands.setTextSelection(3);
- await emitEditorEvent({ event: 'transaction', tiptapEditor });
-
- tiptapEditor.commands.setTextSelection(14);
- await emitEditorEvent({ event: 'transaction', tiptapEditor });
-
- expectLinkButtonsToExist(true);
- expect(wrapper.findComponent(GlForm).exists()).toBe(false);
- });
-
describe('after making changes in the form and clicking apply', () => {
beforeEach(async () => {
linkHrefInput.setValue('https://google.com');
diff --git a/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js
index 51f46389526..c34862b6f3f 100644
--- a/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js
+++ b/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js
@@ -1,7 +1,8 @@
import { GlLink, GlForm } from '@gitlab/ui';
-import { BubbleMenu } from '@tiptap/vue-2';
import { mountExtended } from 'helpers/vue_test_utils_helper';
+import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue';
import MediaBubbleMenu from '~/content_editor/components/bubble_menus/media_bubble_menu.vue';
+import { stubComponent } from 'helpers/stub_component';
import eventHubFactory from '~/helpers/event_hub_factory';
import Image from '~/content_editor/extensions/image';
import Audio from '~/content_editor/extensions/audio';
@@ -54,6 +55,9 @@ describe.each`
contentEditor,
eventHub,
},
+ stubs: {
+ BubbleMenu: stubComponent(BubbleMenu),
+ },
});
};
@@ -94,7 +98,6 @@ describe.each`
});
it('renders bubble menu component', async () => {
- expect(bubbleMenu.props('editor')).toBe(tiptapEditor);
expect(bubbleMenu.classes()).toEqual(['gl-shadow', 'gl-rounded-base', 'gl-bg-white']);
});
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js
index 534c0baf35d..05c259de370 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js
@@ -110,7 +110,7 @@ describe('Merge request widget rebase component', () => {
expect(findRebaseMessageText()).toContain('Something went wrong!');
});
- describe('Rebase buttons with', () => {
+ describe('Rebase buttons', () => {
beforeEach(() => {
createWrapper(
{
@@ -148,6 +148,79 @@ describe('Merge request widget rebase component', () => {
expect(rebaseMock).toHaveBeenCalledWith({ skipCi: true });
});
});
+
+ describe('Rebase when pipelines must succeed is enabled', () => {
+ beforeEach(() => {
+ createWrapper(
+ {
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: true,
+ onlyAllowMergeIfPipelineSucceeds: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ },
+ mergeRequestWidgetGraphql,
+ );
+ });
+
+ it('renders only the rebase button', () => {
+ expect(findRebaseWithoutCiButton().exists()).toBe(false);
+ expect(findStandardRebaseButton().exists()).toBe(true);
+ });
+
+ it('starts the rebase when clicking', async () => {
+ findStandardRebaseButton().vm.$emit('click');
+
+ await nextTick();
+
+ expect(rebaseMock).toHaveBeenCalledWith({ skipCi: false });
+ });
+ });
+
+ describe('Rebase when pipelines must succeed and skipped pipelines are considered successful are enabled', () => {
+ beforeEach(() => {
+ createWrapper(
+ {
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: true,
+ onlyAllowMergeIfPipelineSucceeds: true,
+ allowMergeOnSkippedPipeline: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ },
+ mergeRequestWidgetGraphql,
+ );
+ });
+
+ it('renders both rebase buttons', () => {
+ expect(findRebaseWithoutCiButton().exists()).toBe(true);
+ expect(findStandardRebaseButton().exists()).toBe(true);
+ });
+
+ it('starts the rebase when clicking', async () => {
+ findStandardRebaseButton().vm.$emit('click');
+
+ await nextTick();
+
+ expect(rebaseMock).toHaveBeenCalledWith({ skipCi: false });
+ });
+
+ it('starts the CI-skipping rebase when clicking on "Rebase without CI"', async () => {
+ findRebaseWithoutCiButton().vm.$emit('click');
+
+ await nextTick();
+
+ expect(rebaseMock).toHaveBeenCalledWith({ skipCi: true });
+ });
+ });
});
describe('without permissions', () => {
diff --git a/spec/frontend/work_items/components/work_item_information_spec.js b/spec/frontend/work_items/components/work_item_information_spec.js
index d5f6921c2bc..887c5f615e9 100644
--- a/spec/frontend/work_items/components/work_item_information_spec.js
+++ b/spec/frontend/work_items/components/work_item_information_spec.js
@@ -8,7 +8,6 @@ const createComponent = () => mount(WorkItemInformation);
describe('Work item information alert', () => {
let wrapper;
const tasksHelpPath = helpPagePath('user/tasks');
- const workItemsHelpPath = helpPagePath('development/work_items');
const findAlert = () => wrapper.findComponent(GlAlert);
const findHelpLink = () => wrapper.findComponent(GlLink);
@@ -33,16 +32,12 @@ describe('Work item information alert', () => {
expect(findAlert().props('variant')).toBe('tip');
});
- it('should have the correct text for primary button and link', () => {
+ it('should have the correct text for title', () => {
expect(findAlert().props('title')).toBe(WorkItemInformation.i18n.tasksInformationTitle);
- expect(findAlert().props('primaryButtonText')).toBe(
- WorkItemInformation.i18n.learnTasksButtonText,
- );
- expect(findAlert().props('primaryButtonLink')).toBe(tasksHelpPath);
});
it('should have the correct link to work item link', () => {
expect(findHelpLink().exists()).toBe(true);
- expect(findHelpLink().attributes('href')).toBe(workItemsHelpPath);
+ expect(findHelpLink().attributes('href')).toBe(tasksHelpPath);
});
});
diff --git a/spec/lib/gitlab/alert_management/payload/base_spec.rb b/spec/lib/gitlab/alert_management/payload/base_spec.rb
index ad2a3c7b462..3e8d71ac673 100644
--- a/spec/lib/gitlab/alert_management/payload/base_spec.rb
+++ b/spec/lib/gitlab/alert_management/payload/base_spec.rb
@@ -347,4 +347,26 @@ RSpec.describe Gitlab::AlertManagement::Payload::Base do
it { is_expected.to be(true) }
end
+
+ describe '#source' do
+ subject { parsed_payload.source }
+
+ it { is_expected.to be_nil }
+
+ context 'with alerting integration provided' do
+ before do
+ parsed_payload.integration = instance_double('::AlertManagement::HttpIntegration', name: 'INTEGRATION')
+ end
+
+ it { is_expected.to eq('INTEGRATION') }
+ end
+
+ context 'with monitoring tool defined in the raw payload' do
+ before do
+ allow(parsed_payload).to receive(:monitoring_tool).and_return('TOOL')
+ end
+
+ it { is_expected.to eq('TOOL') }
+ end
+ end
end
diff --git a/spec/lib/gitlab/alert_management/payload/generic_spec.rb b/spec/lib/gitlab/alert_management/payload/generic_spec.rb
index 59933f7459d..bc3b6edc638 100644
--- a/spec/lib/gitlab/alert_management/payload/generic_spec.rb
+++ b/spec/lib/gitlab/alert_management/payload/generic_spec.rb
@@ -144,4 +144,40 @@ RSpec.describe Gitlab::AlertManagement::Payload::Generic do
it { is_expected.to eq(value) }
end
end
+
+ describe '#resolved?' do
+ subject { parsed_payload.resolved? }
+
+ context 'without end time' do
+ it { is_expected.to eq(false) }
+ end
+
+ context 'with end time' do
+ let(:raw_payload) { { 'end_time' => Time.current.to_s } }
+
+ it { is_expected.to eq(true) }
+ end
+ end
+
+ describe '#source' do
+ subject { parsed_payload.source }
+
+ it { is_expected.to eq('Generic Alert Endpoint') }
+
+ context 'with alerting integration provided' do
+ before do
+ parsed_payload.integration = instance_double('::AlertManagement::HttpIntegration', name: 'INTEGRATION')
+ end
+
+ it { is_expected.to eq('INTEGRATION') }
+ end
+
+ context 'with monitoring tool defined in the raw payload' do
+ before do
+ allow(parsed_payload).to receive(:monitoring_tool).and_return('TOOL')
+ end
+
+ it { is_expected.to eq('TOOL') }
+ end
+ end
end
diff --git a/spec/lib/gitlab/background_migration/rename_task_system_note_to_checklist_item_spec.rb b/spec/lib/gitlab/background_migration/rename_task_system_note_to_checklist_item_spec.rb
index 6996249cb40..45932defaf9 100644
--- a/spec/lib/gitlab/background_migration/rename_task_system_note_to_checklist_item_spec.rb
+++ b/spec/lib/gitlab/background_migration/rename_task_system_note_to_checklist_item_spec.rb
@@ -50,8 +50,8 @@ RSpec.describe Gitlab::BackgroundMigration::RenameTaskSystemNoteToChecklistItem
let(:migration) do
described_class.new(
- start_id: note1.id,
- end_id: note4.id,
+ start_id: metadata1.id,
+ end_id: metadata4.id,
batch_table: :system_note_metadata,
batch_column: :id,
sub_batch_size: 2,
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index cc696d76a02..2c0f6943243 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -586,13 +586,36 @@ RSpec.describe API::Branches do
let(:route) { "/projects/#{project_id}/repository/branches/#{branch_name}/unprotect" }
shared_examples_for 'repository unprotected branch' do
- it 'unprotects a single branch' do
- put api(route, current_user)
+ context 'when branch is protected' do
+ let!(:protected_branch) { create(:protected_branch, project: project, name: protected_branch_name) }
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('public_api/v4/branch')
- expect(json_response['name']).to eq(CGI.unescape(branch_name))
- expect(json_response['protected']).to eq(false)
+ it 'unprotects a single branch' do
+ expect_next_instance_of(::ProtectedBranches::DestroyService, project, current_user) do |instance|
+ expect(instance).to receive(:execute).with(protected_branch).and_call_original
+ end
+
+ put api(route, current_user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq(CGI.unescape(branch_name))
+ expect(json_response['protected']).to eq(false)
+
+ expect { protected_branch.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+
+ context 'when branch is not protected' do
+ it 'returns a single branch response' do
+ expect(::ProtectedBranches::DestroyService).not_to receive(:new)
+
+ put api(route, current_user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq(CGI.unescape(branch_name))
+ expect(json_response['protected']).to eq(false)
+ end
end
context 'when branch does not exist' do
@@ -637,40 +660,40 @@ RSpec.describe API::Branches do
context 'when authenticated', 'as a maintainer' do
let(:current_user) { user }
+ let(:protected_branch_name) { branch_name }
- context "when a protected branch doesn't already exist" do
- it_behaves_like 'repository unprotected branch'
+ it_behaves_like 'repository unprotected branch'
- context 'when branch contains a dot' do
- let(:branch_name) { branch_with_dot }
+ context 'when branch contains a dot' do
+ let(:branch_name) { branch_with_dot }
- it_behaves_like 'repository unprotected branch'
- end
+ it_behaves_like 'repository unprotected branch'
+ end
- context 'when branch contains a slash' do
- let(:branch_name) { branch_with_slash }
+ context 'when branch contains a slash' do
+ let(:branch_name) { branch_with_slash }
- it_behaves_like '404 response' do
- let(:request) { put api(route, current_user) }
- end
+ it_behaves_like '404 response' do
+ let(:request) { put api(route, current_user) }
end
+ end
- context 'when branch contains an escaped slash' do
- let(:branch_name) { CGI.escape(branch_with_slash) }
+ context 'when branch contains an escaped slash' do
+ let(:branch_name) { CGI.escape(branch_with_slash) }
+ let(:protected_branch_name) { branch_with_slash }
- it_behaves_like 'repository unprotected branch'
- end
+ it_behaves_like 'repository unprotected branch'
+ end
- context 'requesting with the escaped project full path' do
- let(:project_id) { CGI.escape(project.full_path) }
+ context 'requesting with the escaped project full path' do
+ let(:project_id) { CGI.escape(project.full_path) }
- it_behaves_like 'repository unprotected branch'
+ it_behaves_like 'repository unprotected branch'
- context 'when branch contains a dot' do
- let(:branch_name) { branch_with_dot }
+ context 'when branch contains a dot' do
+ let(:branch_name) { branch_with_dot }
- it_behaves_like 'repository unprotected branch'
- end
+ it_behaves_like 'repository unprotected branch'
end
end
end
diff --git a/spec/support/shared_examples/graphql/resolvers/issuable_resolvers_shared_examples.rb b/spec/support/shared_examples/graphql/resolvers/issuable_resolvers_shared_examples.rb
index feaa8070090..25008bca619 100644
--- a/spec/support/shared_examples/graphql/resolvers/issuable_resolvers_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/resolvers/issuable_resolvers_shared_examples.rb
@@ -73,6 +73,10 @@ RSpec.shared_examples 'graphql query for searching issuables' do
resolve_issuables(search: 'created')
end
end
+
+ it 'does not return error if search term is not present' do
+ expect(resolve_issuables).not_to be_instance_of(Gitlab::Graphql::Errors::ArgumentError)
+ end
end
context 'with disable_anonymous_search as `false`' do
diff --git a/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb b/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
index 9546b6cbea4..0db9519f760 100644
--- a/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
+++ b/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
@@ -23,12 +23,10 @@ RSpec.shared_examples 'creates an alert management alert or errors' do
end
context 'and fails to save' do
- let(:errors) { double(messages: { hosts: ['hosts array is over 255 chars'] }, '[]': [] ) }
-
before do
- allow(service).to receive(:alert).and_call_original
- allow(service).to receive_message_chain(:alert, :save).and_return(false)
- allow(service).to receive_message_chain(:alert, :errors).and_return(errors)
+ allow(AlertManagement::Alert).to receive(:new).and_wrap_original do |m, **args|
+ m.call(**args, hosts: ['a' * 256]) # hosts should be 255
+ end
end
it_behaves_like 'alerts service responds with an error', :bad_request