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
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-04-19 15:15:59 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-04-19 15:15:59 +0300
commit2017bc90a671eac669f0114b6ef508e151409c4f (patch)
tree79bbbedede417d3ce13ae2e13dd1ad3bb069c975 /spec/frontend
parent9450a63064cd1572f030628dbf155f5c047f28c7 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/__helpers__/wait_for_text.js2
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js2
-rw-r--r--spec/frontend/ci/runner/components/registration/registration_instructions_spec.js2
-rw-r--r--spec/frontend/design_management/components/design_notes/design_reply_form_spec.js8
-rw-r--r--spec/frontend/diffs/components/diff_view_spec.js19
-rw-r--r--spec/frontend/pipelines/pipeline_operations_spec.js26
-rw-r--r--spec/frontend/pipelines/pipelines_manual_actions_legacy_spec.js168
-rw-r--r--spec/frontend/repository/components/fork_info_spec.js2
-rw-r--r--spec/frontend/repository/components/table/row_spec.js22
-rw-r--r--spec/frontend/search/sidebar/components/scope_new_navigation_spec.js83
-rw-r--r--spec/frontend/super_sidebar/components/create_menu_spec.js24
-rw-r--r--spec/frontend/super_sidebar/components/help_center_spec.js6
-rw-r--r--spec/frontend/super_sidebar/components/user_menu_spec.js11
-rw-r--r--spec/frontend/tags/components/delete_tag_modal_spec.js2
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js343
15 files changed, 345 insertions, 375 deletions
diff --git a/spec/frontend/__helpers__/wait_for_text.js b/spec/frontend/__helpers__/wait_for_text.js
index 6bed8a90a98..991adc5d6c0 100644
--- a/spec/frontend/__helpers__/wait_for_text.js
+++ b/spec/frontend/__helpers__/wait_for_text.js
@@ -1,3 +1,3 @@
import { findByText } from '@testing-library/dom';
-export const waitForText = async (text, container = document) => findByText(container, text);
+export const waitForText = (text, container = document) => findByText(container, text);
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js
index 06b3ec4aab8..a25d325f7a1 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js
@@ -626,7 +626,7 @@ describe('Ci Variable Shared Component', () => {
}
});
- it('report custom validator error on wrong data', async () => {
+ it('report custom validator error on wrong data', () => {
expect(() =>
assertProps(
ciVariableShared,
diff --git a/spec/frontend/ci/runner/components/registration/registration_instructions_spec.js b/spec/frontend/ci/runner/components/registration/registration_instructions_spec.js
index 629272c0bf0..8c196d7b5e3 100644
--- a/spec/frontend/ci/runner/components/registration/registration_instructions_spec.js
+++ b/spec/frontend/ci/runner/components/registration/registration_instructions_spec.js
@@ -280,7 +280,7 @@ describe('RegistrationInstructions', () => {
});
describe('when the page is closing', () => {
- it('warns the user against closing', async () => {
+ it('warns the user against closing', () => {
const { event, preventDefault, returnValueSetter } = mockBeforeunload();
expect(preventDefault).not.toHaveBeenCalled();
diff --git a/spec/frontend/design_management/components/design_notes/design_reply_form_spec.js b/spec/frontend/design_management/components/design_notes/design_reply_form_spec.js
index c8fa02cb6aa..f08efc0c685 100644
--- a/spec/frontend/design_management/components/design_notes/design_reply_form_spec.js
+++ b/spec/frontend/design_management/components/design_notes/design_reply_form_spec.js
@@ -124,7 +124,7 @@ describe('Design reply form component', () => {
${'gid://gitlab/DiffDiscussion/123'} | ${123}
`(
'initializes autosave support on discussion with proper key',
- async ({ discussionId, shortDiscussionId }) => {
+ ({ discussionId, shortDiscussionId }) => {
createComponent({ props: { discussionId } });
expect(Autosave).toHaveBeenCalledWith(expect.any(Element), [
@@ -136,7 +136,7 @@ describe('Design reply form component', () => {
);
describe('when form has no text', () => {
- beforeEach(async () => {
+ beforeEach(() => {
createComponent();
});
@@ -148,7 +148,7 @@ describe('Design reply form component', () => {
key | keyData
${'ctrl'} | ${ctrlKey}
${'meta'} | ${metaKey}
- `('does not perform mutation on textarea $key+enter keydown', async ({ keyData }) => {
+ `('does not perform mutation on textarea $key+enter keydown', ({ keyData }) => {
findTextarea().trigger('keydown.enter', keyData);
expect(mockMutationHandler).not.toHaveBeenCalled();
@@ -266,7 +266,7 @@ describe('Design reply form component', () => {
expect(wrapper.emitted('cancel-form')).toHaveLength(1);
});
- it('opens confirmation modal on Escape key when text has changed', async () => {
+ it('opens confirmation modal on Escape key when text has changed', () => {
createComponent();
findTextarea().setValue(mockComment);
diff --git a/spec/frontend/diffs/components/diff_view_spec.js b/spec/frontend/diffs/components/diff_view_spec.js
index 9bff6bd14f1..cfc80e61b30 100644
--- a/spec/frontend/diffs/components/diff_view_spec.js
+++ b/spec/frontend/diffs/components/diff_view_spec.js
@@ -14,7 +14,7 @@ describe('DiffView', () => {
const setSelectedCommentPosition = jest.fn();
const getDiffRow = (wrapper) => wrapper.findComponent(DiffRow).vm;
- const createWrapper = (props, provide = {}) => {
+ const createWrapper = (props) => {
Vue.use(Vuex);
const batchComments = {
@@ -48,7 +48,7 @@ describe('DiffView', () => {
...props,
};
const stubs = { DiffExpansionCell, DiffRow, DiffCommentCell, DraftNote };
- return shallowMount(DiffView, { propsData, store, stubs, provide });
+ return shallowMount(DiffView, { propsData, store, stubs });
};
it('does not render a diff-line component when there is no finding', () => {
@@ -56,24 +56,13 @@ describe('DiffView', () => {
expect(wrapper.findComponent(DiffLine).exists()).toBe(false);
});
- it('does render a diff-line component with the correct props when there is a finding & refactorCodeQualityInlineFindings flag is true', async () => {
- const wrapper = createWrapper(diffCodeQuality, {
- glFeatures: { refactorCodeQualityInlineFindings: true },
- });
+ it('does render a diff-line component with the correct props when there is a finding', async () => {
+ const wrapper = createWrapper(diffCodeQuality);
wrapper.findComponent(DiffRow).vm.$emit('toggleCodeQualityFindings', 2);
await nextTick();
expect(wrapper.findComponent(DiffLine).props('line')).toBe(diffCodeQuality.diffLines[2]);
});
- it('does not render a diff-line component when there is a finding & refactorCodeQualityInlineFindings flag is false', async () => {
- const wrapper = createWrapper(diffCodeQuality, {
- glFeatures: { refactorCodeQualityInlineFindings: false },
- });
- wrapper.findComponent(DiffRow).vm.$emit('toggleCodeQualityFindings', 2);
- await nextTick();
- expect(wrapper.findComponent(DiffLine).exists()).toBe(false);
- });
-
it.each`
type | side | container | sides | total
${'parallel'} | ${'left'} | ${'.old'} | ${{ left: { lineDrafts: [], renderDiscussion: true }, right: { lineDrafts: [], renderDiscussion: true } }} | ${2}
diff --git a/spec/frontend/pipelines/pipeline_operations_spec.js b/spec/frontend/pipelines/pipeline_operations_spec.js
index 15fc23e8b54..b2191453824 100644
--- a/spec/frontend/pipelines/pipeline_operations_spec.js
+++ b/spec/frontend/pipelines/pipeline_operations_spec.js
@@ -1,6 +1,5 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import PipelinesManualActions from '~/pipelines/components/pipelines_list/pipelines_manual_actions.vue';
-import PipelinesManualActionsLegacy from '~/pipelines/components/pipelines_list/pipelines_manual_actions_legacy.vue';
import PipelineMultiActions from '~/pipelines/components/pipelines_list/pipeline_multi_actions.vue';
import PipelineOperations from '~/pipelines/components/pipelines_list/pipeline_operations.vue';
import eventHub from '~/pipelines/event_hub';
@@ -15,15 +14,6 @@ describe('Pipeline operations', () => {
details: {
has_manual_actions: true,
has_scheduled_actions: false,
- manual_actions: [
- {
- name: 'dont-interrupt-me',
- path: '/root/ci-project/-/jobs/3974323562/play',
- playable: true,
- scheduled: false,
- },
- ],
- scheduled_actions: [],
},
flags: {
retryable: true,
@@ -34,20 +24,14 @@ describe('Pipeline operations', () => {
},
};
- const createComponent = (props = defaultProps, flagState = true) => {
+ const createComponent = (props = defaultProps) => {
wrapper = shallowMountExtended(PipelineOperations, {
- provide: {
- glFeatures: {
- lazyLoadPipelineDropdownActions: flagState,
- },
- },
propsData: {
...props,
},
});
};
- const findLegacyManualActions = () => wrapper.findComponent(PipelinesManualActionsLegacy);
const findManualActions = () => wrapper.findComponent(PipelinesManualActions);
const findMultiActions = () => wrapper.findComponent(PipelineMultiActions);
const findRetryBtn = () => wrapper.findByTestId('pipelines-retry-button');
@@ -57,14 +41,6 @@ describe('Pipeline operations', () => {
createComponent();
expect(findManualActions().exists()).toBe(true);
- expect(findLegacyManualActions().exists()).toBe(false);
- });
-
- it('should display legacy pipeline manual actions', () => {
- createComponent(defaultProps, false);
-
- expect(findLegacyManualActions().exists()).toBe(true);
- expect(findManualActions().exists()).toBe(false);
});
it('should display pipeline multi actions', () => {
diff --git a/spec/frontend/pipelines/pipelines_manual_actions_legacy_spec.js b/spec/frontend/pipelines/pipelines_manual_actions_legacy_spec.js
deleted file mode 100644
index 50ff301060b..00000000000
--- a/spec/frontend/pipelines/pipelines_manual_actions_legacy_spec.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { TEST_HOST } from 'spec/test_constants';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
-import PipelinesManualActionsLegacy from '~/pipelines/components/pipelines_list/pipelines_manual_actions_legacy.vue';
-import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
-import { TRACKING_CATEGORIES } from '~/pipelines/constants';
-
-jest.mock('~/alert');
-jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
-
-describe('Pipelines Actions dropdown', () => {
- let wrapper;
- let mock;
-
- const createComponent = (props, mountFn = shallowMount) => {
- wrapper = mountFn(PipelinesManualActionsLegacy, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findAllCountdowns = () => wrapper.findAllComponents(GlCountdown);
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- confirmAction.mockReset();
- });
-
- describe('manual actions', () => {
- const mockActions = [
- {
- name: 'stop_review',
- path: `${TEST_HOST}/root/review-app/builds/1893/play`,
- },
- {
- name: 'foo',
- path: `${TEST_HOST}/disabled/pipeline/action`,
- playable: false,
- },
- ];
-
- beforeEach(() => {
- createComponent({ actions: mockActions });
- });
-
- it('renders a dropdown with the provided actions', () => {
- expect(findAllDropdownItems()).toHaveLength(mockActions.length);
- });
-
- it("renders a disabled action when it's not playable", () => {
- expect(findAllDropdownItems().at(1).attributes('disabled')).toBe('true');
- });
-
- describe('on click', () => {
- it('makes a request and toggles the loading state', async () => {
- mock.onPost(mockActions.path).reply(HTTP_STATUS_OK);
-
- findAllDropdownItems().at(0).vm.$emit('click');
-
- await nextTick();
- expect(findDropdown().props('loading')).toBe(true);
-
- await waitForPromises();
- expect(findDropdown().props('loading')).toBe(false);
- });
-
- it('makes a failed request and toggles the loading state', async () => {
- mock.onPost(mockActions.path).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
-
- findAllDropdownItems().at(0).vm.$emit('click');
-
- await nextTick();
- expect(findDropdown().props('loading')).toBe(true);
-
- await waitForPromises();
- expect(findDropdown().props('loading')).toBe(false);
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('tracking', () => {
- afterEach(() => {
- unmockTracking();
- });
-
- it('tracks manual actions click', () => {
- const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
-
- findDropdown().vm.$emit('shown');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_manual_actions', {
- label: TRACKING_CATEGORIES.table,
- });
- });
- });
- });
-
- describe('scheduled jobs', () => {
- const scheduledJobAction = {
- name: 'scheduled action',
- path: `${TEST_HOST}/scheduled/job/action`,
- playable: true,
- scheduled_at: '2063-04-05T00:42:00Z',
- };
- const expiredJobAction = {
- name: 'expired action',
- path: `${TEST_HOST}/expired/job/action`,
- playable: true,
- scheduled_at: '2018-10-05T08:23:00Z',
- };
-
- beforeEach(() => {
- jest.spyOn(Date, 'now').mockImplementation(() => new Date('2063-04-04T00:42:00Z').getTime());
- createComponent({ actions: [scheduledJobAction, expiredJobAction] });
- });
-
- it('makes post request after confirming', async () => {
- mock.onPost(scheduledJobAction.path).reply(HTTP_STATUS_OK);
- confirmAction.mockResolvedValueOnce(true);
-
- findAllDropdownItems().at(0).vm.$emit('click');
-
- expect(confirmAction).toHaveBeenCalled();
-
- await waitForPromises();
-
- expect(mock.history.post).toHaveLength(1);
- });
-
- it('does not make post request if confirmation is cancelled', async () => {
- mock.onPost(scheduledJobAction.path).reply(HTTP_STATUS_OK);
- confirmAction.mockResolvedValueOnce(false);
-
- findAllDropdownItems().at(0).vm.$emit('click');
-
- expect(confirmAction).toHaveBeenCalled();
-
- await waitForPromises();
-
- expect(mock.history.post).toHaveLength(0);
- });
-
- it('displays the remaining time in the dropdown', () => {
- expect(findAllCountdowns().at(0).props('endDateString')).toBe(
- scheduledJobAction.scheduled_at,
- );
- });
-
- it('displays 00:00:00 for expired jobs in the dropdown', () => {
- expect(findAllCountdowns().at(1).props('endDateString')).toBe(expiredJobAction.scheduled_at);
- });
- });
-});
diff --git a/spec/frontend/repository/components/fork_info_spec.js b/spec/frontend/repository/components/fork_info_spec.js
index 6b3d7552bb3..8521f91a6c7 100644
--- a/spec/frontend/repository/components/fork_info_spec.js
+++ b/spec/frontend/repository/components/fork_info_spec.js
@@ -224,7 +224,7 @@ describe('ForkInfo component', () => {
);
});
- it('does not render Update Fork button', async () => {
+ it('does not render Update Fork button', () => {
expect(findUpdateForkButton().exists()).toBe(false);
});
});
diff --git a/spec/frontend/repository/components/table/row_spec.js b/spec/frontend/repository/components/table/row_spec.js
index 38260c5b1cd..02b505c828c 100644
--- a/spec/frontend/repository/components/table/row_spec.js
+++ b/spec/frontend/repository/components/table/row_spec.js
@@ -63,7 +63,7 @@ describe('Repository table row component', () => {
const findRouterLink = () => wrapper.findComponent(RouterLinkStub);
const findIntersectionObserver = () => wrapper.findComponent(GlIntersectionObserver);
- it('renders table row', async () => {
+ it('renders table row', () => {
factory({
propsData: {
id: '1',
@@ -77,7 +77,7 @@ describe('Repository table row component', () => {
expect(wrapper.element).toMatchSnapshot();
});
- it('renders a symlink table row', async () => {
+ it('renders a symlink table row', () => {
factory({
propsData: {
id: '1',
@@ -92,7 +92,7 @@ describe('Repository table row component', () => {
expect(wrapper.element).toMatchSnapshot();
});
- it('renders table row for path with special character', async () => {
+ it('renders table row for path with special character', () => {
factory({
propsData: {
id: '1',
@@ -128,7 +128,7 @@ describe('Repository table row component', () => {
${'tree'} | ${RouterLinkStub} | ${'RouterLink'}
${'blob'} | ${RouterLinkStub} | ${'RouterLink'}
${'commit'} | ${'a'} | ${'hyperlink'}
- `('renders a $componentName for type $type', async ({ type, component }) => {
+ `('renders a $componentName for type $type', ({ type, component }) => {
factory({
propsData: {
id: '1',
@@ -146,7 +146,7 @@ describe('Repository table row component', () => {
path
${'test#'}
${'Ă„nderungen'}
- `('renders link for $path', async ({ path }) => {
+ `('renders link for $path', ({ path }) => {
factory({
propsData: {
id: '1',
@@ -162,7 +162,7 @@ describe('Repository table row component', () => {
});
});
- it('renders link for directory with hash', async () => {
+ it('renders link for directory with hash', () => {
factory({
propsData: {
id: '1',
@@ -176,7 +176,7 @@ describe('Repository table row component', () => {
expect(wrapper.find('.tree-item-link').props('to')).toEqual({ path: '/-/tree/main/test%23' });
});
- it('renders commit ID for submodule', async () => {
+ it('renders commit ID for submodule', () => {
factory({
propsData: {
id: '1',
@@ -190,7 +190,7 @@ describe('Repository table row component', () => {
expect(wrapper.find('.commit-sha').text()).toContain('1');
});
- it('renders link with href', async () => {
+ it('renders link with href', () => {
factory({
propsData: {
id: '1',
@@ -205,7 +205,7 @@ describe('Repository table row component', () => {
expect(wrapper.find('a').attributes('href')).toEqual('https://test.com');
});
- it('renders LFS badge', async () => {
+ it('renders LFS badge', () => {
factory({
propsData: {
id: '1',
@@ -220,7 +220,7 @@ describe('Repository table row component', () => {
expect(findBadge().exists()).toBe(true);
});
- it('renders commit and web links with href for submodule', async () => {
+ it('renders commit and web links with href for submodule', () => {
factory({
propsData: {
id: '1',
@@ -237,7 +237,7 @@ describe('Repository table row component', () => {
expect(wrapper.findComponent(GlLink).attributes('href')).toEqual('https://test.com/commit');
});
- it('renders lock icon', async () => {
+ it('renders lock icon', () => {
factory({
propsData: {
id: '1',
diff --git a/spec/frontend/search/sidebar/components/scope_new_navigation_spec.js b/spec/frontend/search/sidebar/components/scope_new_navigation_spec.js
new file mode 100644
index 00000000000..105beae8638
--- /dev/null
+++ b/spec/frontend/search/sidebar/components/scope_new_navigation_spec.js
@@ -0,0 +1,83 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import Vuex from 'vuex';
+import ScopeNewNavigation from '~/search/sidebar/components/scope_new_navigation.vue';
+import NavItem from '~/super_sidebar/components/nav_item.vue';
+import { MOCK_QUERY, MOCK_NAVIGATION, MOCK_NAVIGATION_ITEMS } from '../../mock_data';
+
+Vue.use(Vuex);
+
+describe('ScopeNewNavigation', () => {
+ let wrapper;
+
+ const actionSpies = {
+ fetchSidebarCount: jest.fn(),
+ };
+
+ const getterSpies = {
+ currentScope: jest.fn(() => 'issues'),
+ navigationItems: jest.fn(() => MOCK_NAVIGATION_ITEMS),
+ };
+
+ const createComponent = (initialState) => {
+ const store = new Vuex.Store({
+ state: {
+ urlQuery: MOCK_QUERY,
+ navigation: MOCK_NAVIGATION,
+ ...initialState,
+ },
+ actions: actionSpies,
+ getters: getterSpies,
+ });
+
+ wrapper = shallowMount(ScopeNewNavigation, {
+ store,
+ stubs: {
+ NavItem,
+ },
+ });
+ };
+
+ const findNavElement = () => wrapper.findComponent('nav');
+ const findNavItems = () => wrapper.findAllComponents(NavItem);
+ const findNavItemActive = () => wrapper.find('[aria-current=page]');
+ const findNavItemActiveLabel = () =>
+ findNavItemActive().find('[class="gl-pr-3 gl-text-gray-900 gl-truncate-end"]');
+
+ describe('scope navigation', () => {
+ beforeEach(() => {
+ createComponent({ urlQuery: { ...MOCK_QUERY, search: 'test' } });
+ });
+
+ it('renders section', () => {
+ expect(findNavElement().exists()).toBe(true);
+ });
+
+ it('calls proper action when rendered', async () => {
+ await nextTick();
+ expect(actionSpies.fetchSidebarCount).toHaveBeenCalled();
+ });
+
+ it('renders all nav item components', () => {
+ expect(findNavItems()).toHaveLength(9);
+ });
+
+ it('has all proper links', () => {
+ const linkAtPosition = 3;
+ const { link } = MOCK_NAVIGATION[Object.keys(MOCK_NAVIGATION)[linkAtPosition]];
+
+ expect(findNavItems().at(linkAtPosition).findComponent('a').attributes('href')).toBe(link);
+ });
+ });
+
+ describe('scope navigation sets proper state with url scope set', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('has correct active item', () => {
+ expect(findNavItemActive().exists()).toBe(true);
+ expect(findNavItemActiveLabel().text()).toBe('Issues');
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/create_menu_spec.js b/spec/frontend/super_sidebar/components/create_menu_spec.js
index b24c6b8de7f..e05b5d30e69 100644
--- a/spec/frontend/super_sidebar/components/create_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/create_menu_spec.js
@@ -1,3 +1,4 @@
+import { nextTick } from 'vue';
import { GlDisclosureDropdown, GlTooltip } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { __ } from '~/locale';
@@ -23,6 +24,14 @@ describe('CreateMenu component', () => {
createWrapper();
});
+ it('passes popper options to the dropdown', () => {
+ createWrapper();
+
+ expect(findGlDisclosureDropdown().props('popperOptions')).toEqual({
+ modifiers: [{ name: 'offset', options: { offset: [-147, 4] } }],
+ });
+ });
+
it("sets the toggle's label", () => {
expect(findGlDisclosureDropdown().props('toggleText')).toBe(__('Create new...'));
});
@@ -35,5 +44,20 @@ describe('CreateMenu component', () => {
expect(findGlDisclosureDropdown().props('toggleId')).toBe(wrapper.vm.$options.toggleId);
expect(findGlTooltip().props('target')).toBe(`#${wrapper.vm.$options.toggleId}`);
});
+
+ it('hides the tooltip when the dropdown is opened', async () => {
+ findGlDisclosureDropdown().vm.$emit('shown');
+ await nextTick();
+
+ expect(findGlTooltip().exists()).toBe(false);
+ });
+
+ it('shows the tooltip when the dropdown is closed', async () => {
+ findGlDisclosureDropdown().vm.$emit('shown');
+ findGlDisclosureDropdown().vm.$emit('hidden');
+ await nextTick();
+
+ expect(findGlTooltip().exists()).toBe(true);
+ });
});
});
diff --git a/spec/frontend/super_sidebar/components/help_center_spec.js b/spec/frontend/super_sidebar/components/help_center_spec.js
index 839677f29d5..4c0e7a89a43 100644
--- a/spec/frontend/super_sidebar/components/help_center_spec.js
+++ b/spec/frontend/super_sidebar/components/help_center_spec.js
@@ -88,6 +88,12 @@ describe('HelpCenter component', () => {
]);
});
+ it('passes popper options to the dropdown', () => {
+ expect(findDropdown().props('popperOptions')).toEqual({
+ modifiers: [{ name: 'offset', options: { offset: [-4, 4] } }],
+ });
+ });
+
describe('with Gitlab version check feature enabled', () => {
beforeEach(() => {
createWrapper({ ...sidebarData, show_version_check: true });
diff --git a/spec/frontend/super_sidebar/components/user_menu_spec.js b/spec/frontend/super_sidebar/components/user_menu_spec.js
index 25bcd322d32..995095d0e35 100644
--- a/spec/frontend/super_sidebar/components/user_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/user_menu_spec.js
@@ -14,7 +14,8 @@ describe('UserMenu component', () => {
const GlEmoji = { template: '<img/>' };
const toggleNewNavEndpoint = invalidUrl;
- const showDropdown = () => wrapper.findComponent(GlDisclosureDropdown).vm.$emit('shown');
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
+ const showDropdown = () => findDropdown().vm.$emit('shown');
const createWrapper = (userDataChanges = {}) => {
wrapper = mountExtended(UserMenu, {
@@ -36,6 +37,14 @@ describe('UserMenu component', () => {
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
};
+ it('passes popper options to the dropdown', () => {
+ createWrapper();
+
+ expect(findDropdown().props('popperOptions')).toEqual({
+ modifiers: [{ name: 'offset', options: { offset: [-211, 4] } }],
+ });
+ });
+
describe('Toggle button', () => {
let toggle;
diff --git a/spec/frontend/tags/components/delete_tag_modal_spec.js b/spec/frontend/tags/components/delete_tag_modal_spec.js
index 8438bdb7db0..8ec9925563a 100644
--- a/spec/frontend/tags/components/delete_tag_modal_spec.js
+++ b/spec/frontend/tags/components/delete_tag_modal_spec.js
@@ -69,7 +69,7 @@ describe('Delete tag modal', () => {
expect(submitFormSpy).toHaveBeenCalled();
});
- it('calls show on the modal when a `openModal` event is received through the event hub', async () => {
+ it('calls show on the modal when a `openModal` event is received through the event hub', () => {
const showSpy = jest.spyOn(wrapper.vm.$refs.modal, 'show');
eventHub.$emit('openModal', {
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 f284ec98a73..9bd46267daa 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
@@ -1,56 +1,101 @@
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
import { GlModal } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+import BoldText from '~/vue_merge_request_widget/components/bold_text.vue';
import WidgetRebase from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue';
+import rebaseQuery from '~/vue_merge_request_widget/queries/states/rebase.query.graphql';
import eventHub from '~/vue_merge_request_widget/event_hub';
+import StateContainer from '~/vue_merge_request_widget/components/state_container.vue';
import toast from '~/vue_shared/plugins/global_toast';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { stubComponent } from 'helpers/stub_component';
jest.mock('~/vue_shared/plugins/global_toast');
let wrapper;
-
-function createWrapper(propsData, provideData) {
- wrapper = mount(WidgetRebase, {
- provide: {
- ...provideData,
+const showMock = jest.fn();
+
+const mockPipelineNodes = [
+ {
+ id: '1',
+ project: {
+ id: '2',
+ fullPath: 'user/forked',
},
- propsData,
- data() {
- return {
- state: {
- rebaseInProgress: propsData.mr.rebaseInProgress,
- targetBranch: propsData.mr.targetBranch,
+ },
+];
+
+const mockQueryHandler = ({
+ rebaseInProgress = false,
+ targetBranch = '',
+ pushToSourceBranch = false,
+ nodes = mockPipelineNodes,
+} = {}) =>
+ jest.fn().mockResolvedValue({
+ data: {
+ project: {
+ id: '1',
+ mergeRequest: {
+ id: '2',
+ rebaseInProgress,
+ targetBranch,
userPermissions: {
- pushToSourceBranch: propsData.mr.canPushToSourceBranch,
+ pushToSourceBranch,
+ },
+ pipelines: {
+ nodes,
},
- pipelines: propsData.mr.pipelines,
},
- };
+ },
+ },
+ });
+
+const createMockApolloProvider = (handler) => {
+ Vue.use(VueApollo);
+
+ return createMockApollo([[rebaseQuery, handler]]);
+};
+
+function createWrapper({ propsData = {}, provideData = {}, handler = mockQueryHandler() } = {}) {
+ wrapper = shallowMountExtended(WidgetRebase, {
+ apolloProvider: createMockApolloProvider(handler),
+ provide: {
+ ...provideData,
},
- mocks: {
- $apollo: {
- queries: {
- state: { loading: false },
+ propsData: {
+ mr: {},
+ service: {},
+ ...propsData,
+ },
+ stubs: {
+ StateContainer,
+ GlModal: stubComponent(GlModal, {
+ methods: {
+ show: showMock,
},
- },
+ }),
},
});
}
describe('Merge request widget rebase component', () => {
- const findRebaseMessage = () => wrapper.find('[data-testid="rebase-message"]');
+ const findRebaseMessage = () => wrapper.findByTestId('rebase-message');
+ const findBoldText = () => wrapper.findComponent(BoldText);
const findRebaseMessageText = () => findRebaseMessage().text();
- const findStandardRebaseButton = () => wrapper.find('[data-testid="standard-rebase-button"]');
- const findRebaseWithoutCiButton = () => wrapper.find('[data-testid="rebase-without-ci-button"]');
+ const findStandardRebaseButton = () => wrapper.findByTestId('standard-rebase-button');
+ const findRebaseWithoutCiButton = () => wrapper.findByTestId('rebase-without-ci-button');
const findModal = () => wrapper.findComponent(GlModal);
describe('while rebasing', () => {
- it('should show progress message', () => {
+ it('should show progress message', async () => {
createWrapper({
- mr: { rebaseInProgress: true },
- service: {},
+ handler: mockQueryHandler({ rebaseInProgress: true }),
});
+ await waitForPromises();
+
expect(findRebaseMessageText()).toContain('Rebase in progress');
});
});
@@ -59,95 +104,110 @@ describe('Merge request widget rebase component', () => {
const rebaseMock = jest.fn().mockResolvedValue();
const pollMock = jest.fn().mockResolvedValue({});
- it('renders the warning message', () => {
+ it('renders the warning message', async () => {
createWrapper({
- mr: {
+ handler: mockQueryHandler({
rebaseInProgress: false,
- canPushToSourceBranch: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
- },
+ pushToSourceBranch: false,
+ }),
});
- const text = findRebaseMessageText();
+ await waitForPromises();
- expect(text).toContain('Merge blocked');
- expect(text.replace(/\s\s+/g, ' ')).toContain(
+ expect(findBoldText().props('message')).toContain('Merge blocked');
+ expect(findBoldText().props('message').replace(/\s\s+/g, ' ')).toContain(
'the source branch must be rebased onto the target branch',
);
});
it('renders an error message when rebasing has failed', async () => {
createWrapper({
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
+ propsData: {
+ service: {
+ rebase: jest.fn().mockRejectedValue({
+ response: {
+ data: {
+ merge_error: 'Something went wrong!',
+ },
+ },
+ }),
+ },
},
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
});
+ await waitForPromises();
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ rebasingError: 'Something went wrong!' });
+ findStandardRebaseButton().vm.$emit('click');
- await nextTick();
+ await waitForPromises();
expect(findRebaseMessageText()).toContain('Something went wrong!');
});
describe('Rebase buttons', () => {
- beforeEach(() => {
+ it('renders both buttons', async () => {
createWrapper({
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
- },
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
});
- });
- it('renders both buttons', () => {
+ await waitForPromises();
+
expect(findRebaseWithoutCiButton().exists()).toBe(true);
expect(findStandardRebaseButton().exists()).toBe(true);
});
it('starts the rebase when clicking', async () => {
- findStandardRebaseButton().vm.$emit('click');
+ createWrapper({
+ propsData: {
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ },
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
+ });
- await nextTick();
+ await waitForPromises();
+
+ findStandardRebaseButton().vm.$emit('click');
expect(rebaseMock).toHaveBeenCalledWith({ skipCi: false });
});
it('starts the CI-skipping rebase when clicking on "Rebase without CI"', async () => {
- findRebaseWithoutCiButton().vm.$emit('click');
+ createWrapper({
+ propsData: {
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ },
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
+ });
- await nextTick();
+ await waitForPromises();
+
+ findRebaseWithoutCiButton().vm.$emit('click');
expect(rebaseMock).toHaveBeenCalledWith({ skipCi: true });
});
});
describe('Rebase when pipelines must succeed is enabled', () => {
- beforeEach(() => {
+ beforeEach(async () => {
createWrapper({
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- onlyAllowMergeIfPipelineSucceeds: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
+ propsData: {
+ mr: {
+ onlyAllowMergeIfPipelineSucceeds: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
},
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
});
+
+ await waitForPromises();
});
it('renders only the rebase button', () => {
@@ -165,19 +225,22 @@ describe('Merge request widget rebase component', () => {
});
describe('Rebase when pipelines must succeed and skipped pipelines are considered successful are enabled', () => {
- beforeEach(() => {
+ beforeEach(async () => {
createWrapper({
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- onlyAllowMergeIfPipelineSucceeds: true,
- allowMergeOnSkippedPipeline: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
+ propsData: {
+ mr: {
+ onlyAllowMergeIfPipelineSucceeds: true,
+ allowMergeOnSkippedPipeline: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
},
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
});
+
+ await waitForPromises();
});
it('renders both rebase buttons', () => {
@@ -203,51 +266,36 @@ describe('Merge request widget rebase component', () => {
});
describe('security modal', () => {
- it('displays modal and rebases after confirming', () => {
- createWrapper(
- {
+ it('displays modal and rebases after confirming', async () => {
+ createWrapper({
+ propsData: {
mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
sourceProjectFullPath: 'user/forked',
targetProjectFullPath: 'root/original',
- pipelines: {
- nodes: [
- {
- id: '1',
- project: {
- id: '2',
- fullPath: 'user/forked',
- },
- },
- ],
- },
},
service: {
rebase: rebaseMock,
poll: pollMock,
},
},
- { canCreatePipelineInTargetProject: true },
- );
+ provideData: { canCreatePipelineInTargetProject: true },
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
+ });
- findModal().vm.show = jest.fn();
+ await waitForPromises();
findStandardRebaseButton().vm.$emit('click');
-
- expect(findModal().vm.show).toHaveBeenCalled();
+ expect(showMock).toHaveBeenCalled();
findModal().vm.$emit('primary');
expect(rebaseMock).toHaveBeenCalled();
});
- it('does not display modal', () => {
- createWrapper(
- {
+ it('does not display modal', async () => {
+ createWrapper({
+ propsData: {
mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
sourceProjectFullPath: 'user/forked',
targetProjectFullPath: 'root/original',
},
@@ -256,14 +304,15 @@ describe('Merge request widget rebase component', () => {
poll: pollMock,
},
},
- { canCreatePipelineInTargetProject: false },
- );
+ provideData: { canCreatePipelineInTargetProject: false },
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
+ });
- findModal().vm.show = jest.fn();
+ await waitForPromises();
findStandardRebaseButton().vm.$emit('click');
- expect(findModal().vm.show).not.toHaveBeenCalled();
+ expect(showMock).not.toHaveBeenCalled();
expect(rebaseMock).toHaveBeenCalled();
});
});
@@ -273,42 +322,41 @@ describe('Merge request widget rebase component', () => {
const exampleTargetBranch = 'fake-branch-to-test-with';
describe('UI text', () => {
- beforeEach(() => {
+ beforeEach(async () => {
createWrapper({
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: false,
+ handler: mockQueryHandler({
+ pushToSourceBranch: false,
targetBranch: exampleTargetBranch,
- },
- service: {},
+ }),
});
+
+ await waitForPromises();
});
it('renders a message explaining user does not have permissions', () => {
- const text = findRebaseMessageText();
-
- expect(text).toContain('Merge blocked:');
- expect(text).toContain('the source branch must be rebased');
+ expect(findBoldText().props('message')).toContain('Merge blocked');
+ expect(findBoldText().props('message')).toContain('the source branch must be rebased');
});
it('renders the correct target branch name', () => {
- const text = findRebaseMessageText();
-
- expect(text).toContain('Merge blocked:');
- expect(text).toContain('the source branch must be rebased onto the target branch.');
+ expect(findBoldText().props('message')).toContain('Merge blocked:');
+ expect(findBoldText().props('message')).toContain(
+ 'the source branch must be rebased onto the target branch.',
+ );
});
});
- it('does render the "Rebase without pipeline" button', () => {
+ it('does render the "Rebase without pipeline" button', async () => {
createWrapper({
- mr: {
+ handler: mockQueryHandler({
rebaseInProgress: false,
- canPushToSourceBranch: false,
+ pushToSourceBranch: false,
targetBranch: exampleTargetBranch,
- },
- service: {},
+ }),
});
+ await waitForPromises();
+
expect(findRebaseWithoutCiButton().exists()).toBe(true);
});
});
@@ -317,24 +365,27 @@ describe('Merge request widget rebase component', () => {
it('checkRebaseStatus', async () => {
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
createWrapper({
- mr: {},
- service: {
- rebase() {
- return Promise.resolve();
- },
- poll() {
- return Promise.resolve({
- data: {
- rebase_in_progress: false,
- should_be_rebased: false,
- merge_error: null,
- },
- });
+ propsData: {
+ service: {
+ rebase() {
+ return Promise.resolve();
+ },
+ poll() {
+ return Promise.resolve({
+ data: {
+ rebase_in_progress: false,
+ should_be_rebased: false,
+ merge_error: null,
+ },
+ });
+ },
},
},
});
- wrapper.vm.rebase();
+ await waitForPromises();
+
+ findRebaseWithoutCiButton().vm.$emit('click');
// Wait for the rebase request
await nextTick();