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:
Diffstat (limited to 'spec/frontend/vue_shared')
-rw-r--r--spec/frontend/vue_shared/alert_details/alert_status_spec.js25
-rw-r--r--spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap21
-rw-r--r--spec/frontend/vue_shared/components/badges/__snapshots__/experiment_badge_spec.js.snap41
-rw-r--r--spec/frontend/vue_shared/components/badges/beta_badge_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/badges/experiment_badge_spec.js32
-rw-r--r--spec/frontend/vue_shared/components/badges/hover_badge_spec.js50
-rw-r--r--spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js1
-rw-r--r--spec/frontend/vue_shared/components/ci_badge_link_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/clone_dropdown/clone_dropdown_item_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js17
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/user_token_spec.js40
-rw-r--r--spec/frontend/vue_shared/components/form/input_copy_toggle_visibility_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/markdown/editor_mode_switcher_spec.js80
-rw-r--r--spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js95
-rw-r--r--spec/frontend/vue_shared/components/markdown/toolbar_spec.js24
-rw-r--r--spec/frontend/vue_shared/components/runner_instructions/instructions/runner_cli_instructions_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/segmented_control_button_group_spec.js31
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/__snapshots__/utils_spec.js.snap88
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/components/blame_info_spec.js63
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/mock_data.js21
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/utils_spec.js35
-rw-r--r--spec/frontend/vue_shared/components/time_ago_tooltip_spec.js9
-rw-r--r--spec/frontend/vue_shared/components/toggle_labels_spec.js56
-rw-r--r--spec/frontend/vue_shared/components/vuex_module_provider_spec.js10
-rw-r--r--spec/frontend/vue_shared/issuable/create/components/issuable_create_root_spec.js3
-rw-r--r--spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js32
-rw-r--r--spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js18
-rw-r--r--spec/frontend/vue_shared/issuable/list/mock_data.js2
-rw-r--r--spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js36
30 files changed, 635 insertions, 229 deletions
diff --git a/spec/frontend/vue_shared/alert_details/alert_status_spec.js b/spec/frontend/vue_shared/alert_details/alert_status_spec.js
index 90d29f0bfd4..478df81a966 100644
--- a/spec/frontend/vue_shared/alert_details/alert_status_spec.js
+++ b/spec/frontend/vue_shared/alert_details/alert_status_spec.js
@@ -1,7 +1,7 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'helpers/mock_apollo_helper';
import updateAlertStatusMutation from '~/graphql_shared//mutations/alert_status_update.mutation.graphql';
@@ -34,13 +34,13 @@ describe('AlertManagementStatus', () => {
},
});
- const findStatusDropdown = () => wrapper.findComponent(GlDropdown);
- const findFirstStatusOption = () => findStatusDropdown().findComponent(GlDropdownItem);
- const findAllStatusOptions = () => findStatusDropdown().findAllComponents(GlDropdownItem);
- const findStatusDropdownHeader = () => wrapper.findByTestId('dropdown-header');
+ const findStatusDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
+ const findFirstStatusOption = () => findStatusDropdown().findComponent(GlListboxItem);
+ const findAllStatusOptions = () => findStatusDropdown().findAllComponents(GlListboxItem);
+ const findStatusDropdownHeader = () => wrapper.findByTestId('listbox-header-text');
const selectFirstStatusOption = () => {
- findFirstStatusOption().vm.$emit('click');
+ findFirstStatusOption().vm.$emit('select', new Event('click'));
return waitForPromises();
};
@@ -57,7 +57,7 @@ describe('AlertManagementStatus', () => {
provide = {},
handler = mockUpdatedMutationResult(),
} = {}) {
- wrapper = shallowMountExtended(AlertManagementStatus, {
+ wrapper = mountExtended(AlertManagementStatus, {
apolloProvider: createMockApolloProvider(handler),
propsData: {
alert: { ...mockAlert },
@@ -82,7 +82,7 @@ describe('AlertManagementStatus', () => {
it('shows the dropdown', () => {
mountComponent({ props: { isSidebar: true, isDropdownShowing: true } });
- expect(wrapper.classes()).toContain('show');
+ expect(wrapper.classes()).not.toContain('gl-display-none');
});
});
@@ -92,8 +92,7 @@ describe('AlertManagementStatus', () => {
});
it('calls `$apollo.mutate` with `updateAlertStatus` mutation and variables containing `iid`, `status`, & `projectPath`', async () => {
- findFirstStatusOption().vm.$emit('click');
- await waitForPromises();
+ await selectFirstStatusOption();
expect(requestHandler).toHaveBeenCalledWith({
iid,
@@ -194,9 +193,7 @@ describe('AlertManagementStatus', () => {
handler: mockUpdatedMutationResult({ nodes: mockAlerts }),
});
Tracking.event.mockClear();
- findFirstStatusOption().vm.$emit('click');
-
- await waitForPromises();
+ await selectFirstStatusOption();
const status = findFirstStatusOption().text();
const { category, action, label } = trackAlertStatusUpdateOptions;
diff --git a/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap b/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap
index 359aaacde0b..499a971d791 100644
--- a/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap
+++ b/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap
@@ -2,22 +2,15 @@
exports[`Beta badge component renders the badge 1`] = `
<div>
- <gl-badge-stub
- class="gl-cursor-pointer"
+ <a
+ class="badge badge-neutral badge-pill gl-badge gl-cursor-pointer md"
href="#"
- iconsize="md"
- size="md"
- variant="neutral"
+ target="_self"
>
Beta
- </gl-badge-stub>
- <gl-popover-stub
- cssclasses=""
- data-testid="beta-badge"
- showclosebutton="true"
- target="[Function]"
- title="What's Beta?"
- triggers="hover focus click"
+ </a>
+ <div
+ class="gl-popover"
>
<p>
A Beta feature is not production-ready, but is unlikely to change drastically before it's released. We encourage users to try Beta features and provide feedback.
@@ -43,6 +36,6 @@ exports[`Beta badge component renders the badge 1`] = `
Is complete or near completion.
</li>
</ul>
- </gl-popover-stub>
+ </div>
</div>
`;
diff --git a/spec/frontend/vue_shared/components/badges/__snapshots__/experiment_badge_spec.js.snap b/spec/frontend/vue_shared/components/badges/__snapshots__/experiment_badge_spec.js.snap
new file mode 100644
index 00000000000..4ad70338f3c
--- /dev/null
+++ b/spec/frontend/vue_shared/components/badges/__snapshots__/experiment_badge_spec.js.snap
@@ -0,0 +1,41 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Experiment badge component renders the badge 1`] = `
+<div>
+ <a
+ class="badge badge-neutral badge-pill gl-badge gl-cursor-pointer md"
+ href="#"
+ target="_self"
+ >
+ Experiment
+ </a>
+ <div
+ class="gl-popover"
+ >
+ <p>
+ An Experiment is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback.
+ </p>
+ <p
+ class="gl-mb-0"
+ >
+ An Experiment:
+ </p>
+ <ul
+ class="gl-pl-4"
+ >
+ <li>
+ May be unstable.
+ </li>
+ <li>
+ Can cause data loss.
+ </li>
+ <li>
+ Has no support and might not be documented.
+ </li>
+ <li>
+ Can be removed at any time.
+ </li>
+ </ul>
+ </div>
+</div>
+`;
diff --git a/spec/frontend/vue_shared/components/badges/beta_badge_spec.js b/spec/frontend/vue_shared/components/badges/beta_badge_spec.js
index c930c6d5708..d826ca5c7c0 100644
--- a/spec/frontend/vue_shared/components/badges/beta_badge_spec.js
+++ b/spec/frontend/vue_shared/components/badges/beta_badge_spec.js
@@ -1,4 +1,4 @@
-import { shallowMount } from '@vue/test-utils';
+import { mount } from '@vue/test-utils';
import { GlBadge } from '@gitlab/ui';
import BetaBadge from '~/vue_shared/components/badges/beta_badge.vue';
@@ -7,7 +7,7 @@ describe('Beta badge component', () => {
const findBadge = () => wrapper.findComponent(GlBadge);
const createWrapper = (props = {}) => {
- wrapper = shallowMount(BetaBadge, {
+ wrapper = mount(BetaBadge, {
propsData: { ...props },
});
};
diff --git a/spec/frontend/vue_shared/components/badges/experiment_badge_spec.js b/spec/frontend/vue_shared/components/badges/experiment_badge_spec.js
new file mode 100644
index 00000000000..3239578a173
--- /dev/null
+++ b/spec/frontend/vue_shared/components/badges/experiment_badge_spec.js
@@ -0,0 +1,32 @@
+import { mount } from '@vue/test-utils';
+import { GlBadge } from '@gitlab/ui';
+import ExperimentBadge from '~/vue_shared/components/badges/experiment_badge.vue';
+
+describe('Experiment badge component', () => {
+ let wrapper;
+
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ const createWrapper = (props = {}) => {
+ wrapper = mount(ExperimentBadge, {
+ propsData: { ...props },
+ });
+ };
+
+ it('renders the badge', () => {
+ createWrapper();
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('passes default size to badge', () => {
+ createWrapper();
+
+ expect(findBadge().props('size')).toBe('md');
+ });
+
+ it('passes given size to badge', () => {
+ createWrapper({ size: 'sm' });
+
+ expect(findBadge().props('size')).toBe('sm');
+ });
+});
diff --git a/spec/frontend/vue_shared/components/badges/hover_badge_spec.js b/spec/frontend/vue_shared/components/badges/hover_badge_spec.js
new file mode 100644
index 00000000000..68f368215c0
--- /dev/null
+++ b/spec/frontend/vue_shared/components/badges/hover_badge_spec.js
@@ -0,0 +1,50 @@
+import { mount } from '@vue/test-utils';
+import { GlBadge, GlPopover } from '@gitlab/ui';
+import HoverBadge from '~/vue_shared/components/badges/hover_badge.vue';
+
+describe('Hover badge component', () => {
+ let wrapper;
+
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ const findPopover = () => wrapper.findComponent(GlPopover);
+ const createWrapper = ({ props = {}, slots } = {}) => {
+ wrapper = mount(HoverBadge, {
+ propsData: {
+ label: 'Label',
+ title: 'Title',
+ ...props,
+ },
+ slots,
+ });
+ };
+
+ it('passes label to popover', () => {
+ createWrapper();
+
+ expect(findBadge().text()).toBe('Label');
+ });
+
+ it('passes title to popover', () => {
+ createWrapper();
+
+ expect(findPopover().props('title')).toBe('Title');
+ });
+
+ it('renders the default slot', () => {
+ createWrapper({ slots: { default: '<p>This is an awesome content</p>' } });
+
+ expect(findPopover().text()).toContain('This is an awesome content');
+ });
+
+ it('passes default size to badge', () => {
+ createWrapper();
+
+ expect(findBadge().props('size')).toBe('md');
+ });
+
+ it('passes given size to badge', () => {
+ createWrapper({ props: { size: 'sm' } });
+
+ expect(findBadge().props('size')).toBe('sm');
+ });
+});
diff --git a/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js b/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js
index eadcd452929..c1109f21b47 100644
--- a/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js
+++ b/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js
@@ -60,6 +60,7 @@ describe('Blob Rich Viewer component', () => {
expect(wrapper.text()).toContain('Line: 10');
expect(wrapper.text()).toContain('Line: 50');
expect(wrapper.emitted(CONTENT_LOADED_EVENT)).toHaveLength(1);
+ expect(handleLocationHash).toHaveBeenCalled();
expect(findMarkdownFieldView().props('isLoading')).toBe(false);
});
diff --git a/spec/frontend/vue_shared/components/ci_badge_link_spec.js b/spec/frontend/vue_shared/components/ci_badge_link_spec.js
index c74964c13f5..e1660225a5c 100644
--- a/spec/frontend/vue_shared/components/ci_badge_link_spec.js
+++ b/spec/frontend/vue_shared/components/ci_badge_link_spec.js
@@ -149,4 +149,10 @@ describe('CI Badge Link Component', () => {
expect(findBadge().props('size')).toBe('lg');
});
+
+ it('should have class `gl-px-2` when `showText` is false', () => {
+ createComponent({ status: statuses.success, size: 'md', showText: false });
+
+ expect(findBadge().classes()).toContain('gl-px-2');
+ });
});
diff --git a/spec/frontend/vue_shared/components/clone_dropdown/clone_dropdown_item_spec.js b/spec/frontend/vue_shared/components/clone_dropdown/clone_dropdown_item_spec.js
index e0dfa084f3e..341afa03f80 100644
--- a/spec/frontend/vue_shared/components/clone_dropdown/clone_dropdown_item_spec.js
+++ b/spec/frontend/vue_shared/components/clone_dropdown/clone_dropdown_item_spec.js
@@ -6,11 +6,11 @@ describe('Clone Dropdown Button', () => {
let wrapper;
const link = 'ssh://foo.bar';
const label = 'SSH';
- const qaSelector = 'some-selector';
+ const testId = 'some-selector';
const defaultPropsData = {
link,
label,
- qaSelector,
+ testId,
};
const findCopyButton = () => wrapper.findComponent(GlButton);
@@ -46,7 +46,7 @@ describe('Clone Dropdown Button', () => {
});
it('sets the qa selector', () => {
- expect(findCopyButton().attributes('data-qa-selector')).toBe(qaSelector);
+ expect(findCopyButton().attributes('data-testid')).toBe(testId);
});
});
});
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
index a22ad4c450e..7c9f3a3546a 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
@@ -97,6 +97,19 @@ export const projectMilestonesResponse = {
},
};
+export const projectUsersResponse = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/1',
+ attributes: {
+ nodes: mockUsers,
+ __typename: 'UserConnection',
+ },
+ __typename: 'Project',
+ },
+ },
+};
+
export const mockCrmContacts = [
{
__typename: 'CustomerRelationsContact',
@@ -247,8 +260,8 @@ export const mockAuthorToken = {
symbol: '@',
token: UserToken,
operators: OPERATORS_IS,
- fetchPath: 'gitlab-org/gitlab-test',
- fetchUsers: Api.projectUsers.bind(Api),
+ fullPath: 'gitlab-org/gitlab-test',
+ isProject: true,
};
export const mockLabelToken = {
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
index 63eacaabd0c..72e3475df75 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
@@ -420,6 +420,12 @@ describe('BaseToken', () => {
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
+ it('renders `footer` slot when present', () => {
+ wrapper = createComponent({ slots: { footer: "<div class='custom-footer' />" } });
+
+ expect(wrapper.find('.custom-footer').exists()).toBe(true);
+ });
+
describe('events', () => {
describe('when activeToken has been selected', () => {
beforeEach(() => {
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/user_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/user_token_spec.js
index e4ca7dcb19a..0229d00eb91 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/user_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/user_token_spec.js
@@ -6,16 +6,21 @@ import {
} from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
+import usersAutocompleteQuery from '~/graphql_shared/queries/users_autocomplete.query.graphql';
import { OPTIONS_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
import UserToken from '~/vue_shared/components/filtered_search_bar/tokens/user_token.vue';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
-import { mockAuthorToken, mockUsers } from '../mock_data';
+import { mockAuthorToken, mockUsers, projectUsersResponse } from '../mock_data';
+
+Vue.use(VueApollo);
jest.mock('~/alert');
const defaultStubs = {
@@ -37,6 +42,9 @@ const mockPreloadedUsers = [
},
];
+const usersQueryHandler = jest.fn().mockResolvedValue(projectUsersResponse);
+const mockApollo = createMockApollo([[usersAutocompleteQuery, usersQueryHandler]]);
+
function createComponent(options = {}) {
const {
config = mockAuthorToken,
@@ -47,6 +55,7 @@ function createComponent(options = {}) {
listeners = {},
} = options;
return mount(UserToken, {
+ apolloProvider: mockApollo,
propsData: {
config,
value,
@@ -145,6 +154,33 @@ describe('UserToken', () => {
expect(findBaseToken().props('suggestionsLoading')).toBe(false);
});
});
+
+ describe('default - when fetchMilestones function is not provided in config', () => {
+ beforeEach(() => {
+ wrapper = createComponent({});
+ return triggerFetchUsers();
+ });
+
+ it('calls searchMilestonesQuery to fetch milestones', () => {
+ expect(usersQueryHandler).toHaveBeenCalledWith({
+ fullPath: mockAuthorToken.fullPath,
+ isProject: mockAuthorToken.isProject,
+ search: null,
+ });
+ });
+
+ it('calls searchMilestonesQuery with search parameter when provided', async () => {
+ const searchTerm = 'foo';
+
+ await triggerFetchUsers(searchTerm);
+
+ expect(usersQueryHandler).toHaveBeenCalledWith({
+ fullPath: mockAuthorToken.fullPath,
+ isProject: mockAuthorToken.isProject,
+ search: searchTerm,
+ });
+ });
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/form/input_copy_toggle_visibility_spec.js b/spec/frontend/vue_shared/components/form/input_copy_toggle_visibility_spec.js
index eee85ce4fd3..72a0eb98a07 100644
--- a/spec/frontend/vue_shared/components/form/input_copy_toggle_visibility_spec.js
+++ b/spec/frontend/vue_shared/components/form/input_copy_toggle_visibility_spec.js
@@ -363,13 +363,13 @@ describe('InputCopyToggleVisibility', () => {
it('passes no `size` prop', () => {
createComponent();
- expect(findFormInput().props('size')).toBe(null);
+ expect(findFormInput().props('width')).toBe(null);
});
it('passes `size` prop to the input', () => {
createComponent({ props: { size: 'md' } });
- expect(findFormInput().props('size')).toBe('md');
+ expect(findFormInput().props('width')).toBe('md');
});
});
diff --git a/spec/frontend/vue_shared/components/markdown/editor_mode_switcher_spec.js b/spec/frontend/vue_shared/components/markdown/editor_mode_switcher_spec.js
index 712e78458c6..57f54f7e7d3 100644
--- a/spec/frontend/vue_shared/components/markdown/editor_mode_switcher_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/editor_mode_switcher_spec.js
@@ -1,41 +1,22 @@
import { nextTick } from 'vue';
-import { GlButton, GlLink, GlPopover } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import EditorModeSwitcher from '~/vue_shared/components/markdown/editor_mode_switcher.vue';
-import { counter } from '~/vue_shared/components/markdown/utils';
-import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
-import { stubComponent } from 'helpers/stub_component';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
-jest.mock('~/vue_shared/components/markdown/utils', () => ({
- counter: jest.fn().mockReturnValue(0),
-}));
-
describe('vue_shared/component/markdown/editor_mode_switcher', () => {
let wrapper;
useLocalStorageSpy();
- const createComponent = ({
- value,
- userCalloutDismisserSlotProps = { dismiss: jest.fn() },
- } = {}) => {
+ const createComponent = ({ value } = {}) => {
wrapper = mount(EditorModeSwitcher, {
propsData: {
value,
},
- stubs: {
- UserCalloutDismisser: stubComponent(UserCalloutDismisser, {
- render() {
- return this.$scopedSlots.default(userCalloutDismisserSlotProps);
- },
- }),
- },
});
};
const findSwitcherButton = () => wrapper.findComponent(GlButton);
- const findUserCalloutDismisser = () => wrapper.findComponent(UserCalloutDismisser);
- const findCalloutPopover = () => wrapper.findComponent(GlPopover);
describe.each`
value | buttonText
@@ -54,62 +35,7 @@ describe('vue_shared/component/markdown/editor_mode_switcher', () => {
await nextTick();
findSwitcherButton().vm.$emit('click');
- expect(wrapper.emitted().switch).toEqual([[false]]);
- });
- });
-
- describe('rich text editor callout', () => {
- let dismiss;
-
- beforeEach(() => {
- dismiss = jest.fn();
- createComponent({ value: 'markdown', userCalloutDismisserSlotProps: { dismiss } });
- });
-
- it('does not skip the user_callout_dismisser query', () => {
- expect(findUserCalloutDismisser().props()).toMatchObject({
- skipQuery: false,
- featureName: 'rich_text_editor',
- });
- });
-
- it('mounts new rich text editor popover', () => {
- expect(findCalloutPopover().props()).toMatchObject({
- showCloseButton: '',
- triggers: 'manual',
- target: 'switch-to-rich-text-editor',
- });
- });
-
- it('dismisses the callout and emits "switch" event when popover close button is clicked', async () => {
- await findCalloutPopover().findComponent(GlLink).vm.$emit('click');
-
- expect(wrapper.emitted().switch).toEqual([[true]]);
- expect(dismiss).toHaveBeenCalled();
- });
-
- it('dismisses the callout when action button is clicked', () => {
- findSwitcherButton().vm.$emit('click');
-
- expect(dismiss).toHaveBeenCalled();
- });
-
- it('does not show the callout if rich text is already enabled', async () => {
- await wrapper.setProps({ value: 'richText' });
-
- expect(findCalloutPopover().props()).toMatchObject({
- show: false,
- });
- });
-
- it('does not show the callout if already displayed once on the page', () => {
- counter.mockReturnValue(1);
-
- createComponent({ value: 'markdown' });
-
- expect(findCalloutPopover().props()).toMatchObject({
- show: false,
- });
+ expect(wrapper.emitted().switch).toEqual([[]]);
});
});
});
diff --git a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
index c69b18bca88..b4c90fe49d1 100644
--- a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
@@ -7,6 +7,8 @@ import {
EDITING_MODE_MARKDOWN_FIELD,
EDITING_MODE_CONTENT_EDITOR,
CLEAR_AUTOSAVE_ENTRY_EVENT,
+ CONTENT_EDITOR_READY_EVENT,
+ MARKDOWN_EDITOR_READY_EVENT,
} from '~/vue_shared/constants';
import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
@@ -83,22 +85,23 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
const findContentEditor = () => {
const result = wrapper.findComponent(ContentEditor);
-
// In Vue.js 3 there are nuances stubbing component with custom stub on mount
// So we try to search for stub also
return result.exists() ? result : wrapper.findComponent(ContentEditorStub);
};
- const enableContentEditor = async () => {
- findMarkdownField().vm.$emit('enableContentEditor');
- await nextTick();
- await waitForPromises();
+ const enableContentEditor = () => {
+ return new Promise((resolve) => {
+ markdownEditorEventHub.$once(CONTENT_EDITOR_READY_EVENT, resolve);
+ findMarkdownField().vm.$emit('enableContentEditor');
+ });
};
- const enableMarkdownEditor = async () => {
- findContentEditor().vm.$emit('enableMarkdownEditor');
- await nextTick();
- await waitForPromises();
+ const enableMarkdownEditor = () => {
+ return new Promise((resolve) => {
+ markdownEditorEventHub.$once(MARKDOWN_EDITOR_READY_EVENT, resolve);
+ findContentEditor().vm.$emit('enableMarkdownEditor');
+ });
};
beforeEach(() => {
@@ -128,9 +131,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
});
});
- // quarantine: https://gitlab.com/gitlab-org/gitlab/-/issues/412618
- // eslint-disable-next-line jest/no-disabled-tests
- it.skip('passes render_quick_actions param to renderMarkdownPath if quick actions are enabled', async () => {
+ it('passes render_quick_actions param to renderMarkdownPath if quick actions are enabled', async () => {
buildWrapper({ propsData: { supportsQuickActions: true } });
await enableContentEditor();
@@ -139,9 +140,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(mock.history.post[0].url).toContain(`render_quick_actions=true`);
});
- // quarantine: https://gitlab.com/gitlab-org/gitlab/-/issues/411565
- // eslint-disable-next-line jest/no-disabled-tests
- it.skip('does not pass render_quick_actions param to renderMarkdownPath if quick actions are disabled', async () => {
+ it('does not pass render_quick_actions param to renderMarkdownPath if quick actions are disabled', async () => {
buildWrapper({ propsData: { supportsQuickActions: false } });
await enableContentEditor();
@@ -213,9 +212,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(findMarkdownField().find('textarea').attributes('disabled')).toBe(undefined);
});
- // quarantine: https://gitlab.com/gitlab-org/gitlab/-/issues/404734
- // eslint-disable-next-line jest/no-disabled-tests
- it.skip('disables content editor when disabled prop is true', async () => {
+ it('disables content editor when disabled prop is true', async () => {
buildWrapper({ propsData: { disabled: true } });
await enableContentEditor();
@@ -358,9 +355,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
});
it(`emits ${EDITING_MODE_MARKDOWN_FIELD} event when enableMarkdownEditor emitted from content editor`, async () => {
- buildWrapper({
- stubs: { ContentEditor: ContentEditorStub },
- });
+ buildWrapper();
await enableContentEditor();
await enableMarkdownEditor();
@@ -494,12 +489,62 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(findContentEditor().props().autofocus).toBe(false);
});
- it('bubbles up keydown event', () => {
- const event = new Event('keydown');
+ describe('when keydown event is fired', () => {
+ let event;
+ beforeEach(() => {
+ event = new Event('keydown');
+ window.getSelection = jest.fn(() => ({
+ toString: jest.fn(() => 'test'),
+ removeAllRanges: jest.fn(),
+ }));
+ Object.assign(event, { preventDefault: jest.fn() });
+ });
+ it('bubbles up keydown event', () => {
+ findContentEditor().vm.$emit('keydown', event);
+
+ expect(wrapper.emitted('keydown')).toEqual([[event]]);
+ });
+
+ it('bubbles up keydown event for meta key with default behaviour intact', () => {
+ event.metaKey = true;
+ findContentEditor().vm.$emit('keydown', event);
- findContentEditor().vm.$emit('keydown', event);
+ expect(wrapper.emitted('keydown')).toEqual([[event]]);
+ expect(event.preventDefault).toHaveBeenCalledTimes(0);
+ });
+
+ it('bubbles up keydown event for meta + k key on selected text with default behaviour prevented', () => {
+ event.metaKey = true;
+ event.key = 'k';
+ findContentEditor().vm.$emit('keydown', event);
+
+ expect(wrapper.emitted('keydown')).toEqual([[event]]);
+ expect(event.preventDefault).toHaveBeenCalledTimes(1);
+ });
+
+ it('bubbles up keydown event for meta + k key without text selection with default behaviour prevented', () => {
+ event.metaKey = true;
+ event.key = 'k';
+ window.getSelection = jest.fn(() => ({
+ toString: jest.fn(() => ''),
+ removeAllRanges: jest.fn(),
+ }));
+
+ findContentEditor().vm.$emit('keydown', event);
- expect(wrapper.emitted('keydown')).toEqual([[event]]);
+ expect(wrapper.emitted('keydown')).toEqual([[event]]);
+ expect(event.preventDefault).toHaveBeenCalledTimes(1);
+ });
+
+ it('bubbles up keydown event for meta + non-k key with default behaviour intact', () => {
+ event.metaKey = true;
+ event.key = 'l';
+
+ findContentEditor().vm.$emit('keydown', event);
+
+ expect(wrapper.emitted('keydown')).toEqual([[event]]);
+ expect(event.preventDefault).toHaveBeenCalledTimes(0);
+ });
});
describe(`when richText editor triggers enableMarkdownEditor event`, () => {
diff --git a/spec/frontend/vue_shared/components/markdown/toolbar_spec.js b/spec/frontend/vue_shared/components/markdown/toolbar_spec.js
index 90d8ce3b500..59f01b7ff7f 100644
--- a/spec/frontend/vue_shared/components/markdown/toolbar_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/toolbar_spec.js
@@ -3,7 +3,6 @@ import Toolbar from '~/vue_shared/components/markdown/toolbar.vue';
import EditorModeSwitcher from '~/vue_shared/components/markdown/editor_mode_switcher.vue';
import { updateText } from '~/lib/utils/text_markdown';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
jest.mock('~/lib/utils/text_markdown');
@@ -83,28 +82,5 @@ describe('toolbar', () => {
expect(wrapper.emitted('enableContentEditor')).toEqual([[]]);
expect(updateText).not.toHaveBeenCalled();
});
-
- it('does not insert a template text if textarea has some value', () => {
- wrapper.findComponent(EditorModeSwitcher).vm.$emit('switch', true);
-
- expect(updateText).not.toHaveBeenCalled();
- });
-
- it('inserts a "getting started with rich text" template when switched for the first time', () => {
- document.querySelector('textarea').value = '';
-
- wrapper.findComponent(EditorModeSwitcher).vm.$emit('switch', true);
-
- expect(updateText).toHaveBeenCalledWith(
- expect.objectContaining({
- tag: `### Rich text editor
-
-Try out **styling** _your_ content right here or read the [direction](${PROMO_URL}/direction/plan/knowledge/content_editor/).`,
- textArea: document.querySelector('textarea'),
- cursorOffset: 0,
- wrap: false,
- }),
- );
- });
});
});
diff --git a/spec/frontend/vue_shared/components/runner_instructions/instructions/runner_cli_instructions_spec.js b/spec/frontend/vue_shared/components/runner_instructions/instructions/runner_cli_instructions_spec.js
index c6cd963fc33..67aa57a019b 100644
--- a/spec/frontend/vue_shared/components/runner_instructions/instructions/runner_cli_instructions_spec.js
+++ b/spec/frontend/vue_shared/components/runner_instructions/instructions/runner_cli_instructions_spec.js
@@ -1,5 +1,5 @@
-import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { GlAlert, GlListboxItem, GlLoadingIcon } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
@@ -32,7 +32,7 @@ describe('RunnerCliInstructions component', () => {
const findGlLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findAlert = () => wrapper.findComponent(GlAlert);
- const findArchitectureDropdownItems = () => wrapper.findAllByTestId('architecture-dropdown-item');
+ const findArchitectureDropdownItems = () => wrapper.findAllComponents(GlListboxItem);
const findBinaryDownloadButton = () => wrapper.findByTestId('binary-download-button');
const findBinaryInstructions = () => wrapper.findByTestId('binary-instructions');
const findRegisterCommand = () => wrapper.findByTestId('register-command');
@@ -43,7 +43,7 @@ describe('RunnerCliInstructions component', () => {
fakeApollo = createMockApollo(requestHandlers);
wrapper = extendedWrapper(
- shallowMount(RunnerCliInstructions, {
+ mount(RunnerCliInstructions, {
propsData: {
platform: mockPlatform,
registrationToken: 'MY_TOKEN',
diff --git a/spec/frontend/vue_shared/components/segmented_control_button_group_spec.js b/spec/frontend/vue_shared/components/segmented_control_button_group_spec.js
index c1feb64dacb..623a8739907 100644
--- a/spec/frontend/vue_shared/components/segmented_control_button_group_spec.js
+++ b/spec/frontend/vue_shared/components/segmented_control_button_group_spec.js
@@ -10,6 +10,7 @@ const DEFAULT_OPTIONS = [
];
describe('~/vue_shared/components/segmented_control_button_group.vue', () => {
+ let consoleSpy;
let wrapper;
const createComponent = (props = {}, scopedSlots = {}) => {
@@ -97,4 +98,34 @@ describe('~/vue_shared/components/segmented_control_button_group.vue', () => {
);
});
});
+
+ describe('options prop validation', () => {
+ beforeEach(() => {
+ consoleSpy = jest.spyOn(console, 'error').mockImplementation();
+ });
+
+ it.each([
+ [[{ disabled: true }]],
+ [[{ value: '1', disabled: 'false' }]],
+ [[{ value: null, disabled: 'true' }]],
+ [[[{ value: true }, null]]],
+ ])('with options=%j, fails validation', (options) => {
+ createComponent({ options });
+
+ expect(consoleSpy).toHaveBeenCalledTimes(1);
+ expect(consoleSpy).toHaveBeenCalledWith(
+ expect.stringContaining('Invalid prop: custom validator check failed for prop "options"'),
+ );
+ });
+
+ it.each([
+ [[{ value: '1' }]],
+ [[{ value: 1, disabled: true }]],
+ [[{ value: true, disabled: false }]],
+ ])('with options=%j, passes validation', (options) => {
+ createComponent({ options });
+
+ expect(consoleSpy).not.toHaveBeenCalled();
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/source_viewer/__snapshots__/utils_spec.js.snap b/spec/frontend/vue_shared/components/source_viewer/__snapshots__/utils_spec.js.snap
new file mode 100644
index 00000000000..e75b07dcf71
--- /dev/null
+++ b/spec/frontend/vue_shared/components/source_viewer/__snapshots__/utils_spec.js.snap
@@ -0,0 +1,88 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`SourceViewer utils toggleBlameClasses adds classes 1`] = `
+<div
+ class="content"
+>
+ <div
+ class="gl-border-gray-500 gl-border-t gl-pt-3!"
+ >
+ <div
+ id="reference-0"
+ >
+ 1
+ </div>
+ <div
+ id="reference-1"
+ >
+ 2
+ </div>
+ <div
+ id="reference-2"
+ >
+ 3
+ </div>
+ </div>
+ <div>
+ <div
+ class="gl-border-gray-500 gl-border-t gl-pt-3!"
+ id="reference-3"
+ >
+ Content 1
+ </div>
+ <div
+ class="gl-border-gray-500 gl-border-t gl-pt-3!"
+ id="reference-4"
+ >
+ Content 2
+ </div>
+ <div
+ class="gl-border-gray-500 gl-border-t gl-pt-3!"
+ id="reference-5"
+ >
+ Content 3
+ </div>
+ </div>
+</div>
+`;
+
+exports[`SourceViewer utils toggleBlameClasses removes classes 1`] = `
+<div
+ class="content"
+>
+ <div>
+ <div
+ id="reference-0"
+ >
+ 1
+ </div>
+ <div
+ id="reference-1"
+ >
+ 2
+ </div>
+ <div
+ id="reference-2"
+ >
+ 3
+ </div>
+ </div>
+ <div>
+ <div
+ id="reference-3"
+ >
+ Content 1
+ </div>
+ <div
+ id="reference-4"
+ >
+ Content 2
+ </div>
+ <div
+ id="reference-5"
+ >
+ Content 3
+ </div>
+ </div>
+</div>
+`;
diff --git a/spec/frontend/vue_shared/components/source_viewer/components/blame_info_spec.js b/spec/frontend/vue_shared/components/source_viewer/components/blame_info_spec.js
new file mode 100644
index 00000000000..ff8b2be9634
--- /dev/null
+++ b/spec/frontend/vue_shared/components/source_viewer/components/blame_info_spec.js
@@ -0,0 +1,63 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { setHTMLFixture } from 'helpers/fixtures';
+import CommitInfo from '~/repository/components/commit_info.vue';
+import BlameInfo from '~/vue_shared/components/source_viewer/components/blame_info.vue';
+import * as utils from '~/vue_shared/components/source_viewer/utils';
+import { SOURCE_CODE_CONTENT_MOCK, BLAME_DATA_MOCK } from '../mock_data';
+
+describe('BlameInfo component', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(BlameInfo, {
+ propsData: { blameData: BLAME_DATA_MOCK },
+ });
+ };
+
+ beforeEach(() => {
+ setHTMLFixture(SOURCE_CODE_CONTENT_MOCK);
+ jest.spyOn(utils, 'toggleBlameClasses');
+ createComponent();
+ });
+
+ const findCommitInfoComponents = () => wrapper.findAllComponents(CommitInfo);
+
+ it('adds the necessary classes to the DOM', () => {
+ expect(utils.toggleBlameClasses).toHaveBeenCalledWith(BLAME_DATA_MOCK, true);
+ });
+
+ it('renders a CommitInfo component for each blame entry', () => {
+ expect(findCommitInfoComponents().length).toBe(BLAME_DATA_MOCK.length);
+ });
+
+ it.each(BLAME_DATA_MOCK)(
+ 'sets the correct data and positioning for the commitInfo',
+ ({ lineno, commit, index }) => {
+ const commitInfoComponent = findCommitInfoComponents().at(index);
+
+ expect(commitInfoComponent.props('commit')).toEqual(commit);
+ expect(commitInfoComponent.element.style.top).toBe(utils.calculateBlameOffset(lineno));
+ },
+ );
+
+ describe('commitInfo component styling', () => {
+ const borderTopClassName = 'gl-border-t';
+
+ it('does not add a top border for the first entry', () => {
+ expect(findCommitInfoComponents().at(0).element.classList).not.toContain(borderTopClassName);
+ });
+
+ it('add a top border for the rest of the entries', () => {
+ expect(findCommitInfoComponents().at(1).element.classList).toContain(borderTopClassName);
+ expect(findCommitInfoComponents().at(2).element.classList).toContain(borderTopClassName);
+ });
+ });
+
+ describe('when component is destroyed', () => {
+ beforeEach(() => wrapper.destroy());
+
+ it('resets the DOM to its original state', () => {
+ expect(utils.toggleBlameClasses).toHaveBeenCalledWith(BLAME_DATA_MOCK, false);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/source_viewer/mock_data.js b/spec/frontend/vue_shared/components/source_viewer/mock_data.js
index f35e9607d5c..b3516f7ed72 100644
--- a/spec/frontend/vue_shared/components/source_viewer/mock_data.js
+++ b/spec/frontend/vue_shared/components/source_viewer/mock_data.js
@@ -22,3 +22,24 @@ export const CHUNK_2 = {
startingFrom: 70,
blamePath,
};
+
+export const SOURCE_CODE_CONTENT_MOCK = `
+<div class="content">
+ <div>
+ <div id="L1">1</div>
+ <div id="L2">2</div>
+ <div id="L3">3</div>
+ </div>
+
+ <div>
+ <div id="LC1">Content 1</div>
+ <div id="LC2">Content 2</div>
+ <div id="LC3">Content 3</div>
+ </div>
+</div>`;
+
+export const BLAME_DATA_MOCK = [
+ { lineno: 1, commit: { author: 'Peter' }, index: 0 },
+ { lineno: 2, commit: { author: 'Sarah' }, index: 1 },
+ { lineno: 3, commit: { author: 'Peter' }, index: 2 },
+];
diff --git a/spec/frontend/vue_shared/components/source_viewer/utils_spec.js b/spec/frontend/vue_shared/components/source_viewer/utils_spec.js
new file mode 100644
index 00000000000..0ac72aa9afb
--- /dev/null
+++ b/spec/frontend/vue_shared/components/source_viewer/utils_spec.js
@@ -0,0 +1,35 @@
+import { setHTMLFixture } from 'helpers/fixtures';
+import {
+ calculateBlameOffset,
+ toggleBlameClasses,
+} from '~/vue_shared/components/source_viewer/utils';
+import { SOURCE_CODE_CONTENT_MOCK, BLAME_DATA_MOCK } from './mock_data';
+
+describe('SourceViewer utils', () => {
+ beforeEach(() => setHTMLFixture(SOURCE_CODE_CONTENT_MOCK));
+
+ const findContent = () => document.querySelector('.content');
+
+ describe('calculateBlameOffset', () => {
+ it('returns an offset of zero if line number === 1', () => {
+ expect(calculateBlameOffset(1)).toBe('0px');
+ });
+
+ it('calculates an offset for the blame component', () => {
+ const { offsetTop } = document.querySelector('#LC3');
+ expect(calculateBlameOffset(3)).toBe(`${offsetTop}px`);
+ });
+ });
+
+ describe('toggleBlameClasses', () => {
+ it('adds classes', () => {
+ toggleBlameClasses(BLAME_DATA_MOCK, true);
+ expect(findContent()).toMatchSnapshot();
+ });
+
+ it('removes classes', () => {
+ toggleBlameClasses(BLAME_DATA_MOCK, false);
+ expect(findContent()).toMatchSnapshot();
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js b/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js
index 17a363ad8b1..41cf1d2b2e8 100644
--- a/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js
+++ b/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import { GlTruncate } from '@gitlab/ui';
import timezoneMock from 'timezone-mock';
import { formatDate, getTimeago } from '~/lib/utils/datetime_utility';
@@ -36,6 +37,14 @@ describe('Time ago with tooltip component', () => {
expect(vm.text()).toEqual(timeAgoTimestamp);
});
+ it('should render truncated value with gl-truncate as true', () => {
+ buildVm({
+ enableTruncation: true,
+ });
+
+ expect(vm.findComponent(GlTruncate).exists()).toBe(true);
+ });
+
it('should render provided html class', () => {
buildVm({
cssClass: 'foo',
diff --git a/spec/frontend/vue_shared/components/toggle_labels_spec.js b/spec/frontend/vue_shared/components/toggle_labels_spec.js
new file mode 100644
index 00000000000..e4b4b7f9e0c
--- /dev/null
+++ b/spec/frontend/vue_shared/components/toggle_labels_spec.js
@@ -0,0 +1,56 @@
+import { GlToggle } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+
+import ToggleLabels from '~/vue_shared/components/toggle_labels.vue';
+import isShowingLabelsQuery from '~/graphql_shared/client/is_showing_labels.query.graphql';
+
+Vue.use(VueApollo);
+
+describe('ToggleLabels', () => {
+ let wrapper;
+
+ const findToggle = () => wrapper.findComponent(GlToggle);
+
+ const mockSetIsShowingLabelsResolver = jest.fn();
+ const mockApollo = createMockApollo([], {
+ Mutation: {
+ setIsShowingLabels: mockSetIsShowingLabelsResolver,
+ },
+ });
+
+ const createComponent = () => {
+ mockApollo.clients.defaultClient.cache.writeQuery({
+ query: isShowingLabelsQuery,
+ data: {
+ isShowingLabels: true,
+ },
+ });
+ wrapper = shallowMountExtended(ToggleLabels, {
+ apolloProvider: mockApollo,
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('calls setIsShowingLabelsMutation on toggle', async () => {
+ expect(findToggle().props('value')).toBe(true);
+ findToggle().vm.$emit('change', false);
+
+ await waitForPromises();
+
+ expect(mockSetIsShowingLabelsResolver).toHaveBeenCalledWith(
+ {},
+ {
+ isShowingLabels: false,
+ },
+ expect.anything(),
+ expect.anything(),
+ );
+ });
+});
diff --git a/spec/frontend/vue_shared/components/vuex_module_provider_spec.js b/spec/frontend/vue_shared/components/vuex_module_provider_spec.js
index e24c5a4609d..95f557b10c1 100644
--- a/spec/frontend/vue_shared/components/vuex_module_provider_spec.js
+++ b/spec/frontend/vue_shared/components/vuex_module_provider_spec.js
@@ -1,6 +1,4 @@
import { mount } from '@vue/test-utils';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
import VuexModuleProvider from '~/vue_shared/components/vuex_module_provider.vue';
const TestComponent = {
@@ -38,12 +36,4 @@ describe('~/vue_shared/components/vuex_module_provider', () => {
});
expect(findProvidedVuexModule()).toBe(TEST_VUEX_MODULE);
});
-
- it('does not blow up when used with vue-apollo', () => {
- // See https://github.com/vuejs/vue-apollo/pull/1153 for details
- Vue.use(VueApollo);
-
- createComponent();
- expect(findProvidedVuexModule()).toBe(TEST_VUEX_MODULE);
- });
});
diff --git a/spec/frontend/vue_shared/issuable/create/components/issuable_create_root_spec.js b/spec/frontend/vue_shared/issuable/create/components/issuable_create_root_spec.js
index 03f509a3fa3..35e3564c599 100644
--- a/spec/frontend/vue_shared/issuable/create/components/issuable_create_root_spec.js
+++ b/spec/frontend/vue_shared/issuable/create/components/issuable_create_root_spec.js
@@ -5,6 +5,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import IssuableCreateRoot from '~/vue_shared/issuable/create/components/issuable_create_root.vue';
import IssuableForm from '~/vue_shared/issuable/create/components/issuable_form.vue';
+import { TYPE_TEST_CASE } from '~/issues/constants';
Vue.use(VueApollo);
@@ -13,6 +14,7 @@ const createComponent = ({
descriptionHelpPath = '/help/user/markdown',
labelsFetchPath = '/gitlab-org/gitlab-shell/-/labels.json',
labelsManagePath = '/gitlab-org/gitlab-shell/-/labels',
+ issuableType = TYPE_TEST_CASE,
} = {}) => {
return mount(IssuableCreateRoot, {
propsData: {
@@ -20,6 +22,7 @@ const createComponent = ({
descriptionHelpPath,
labelsFetchPath,
labelsManagePath,
+ issuableType,
},
apolloProvider: createMockApollo(),
slots: {
diff --git a/spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js b/spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js
index 62361705843..61185f913d9 100644
--- a/spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js
+++ b/spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js
@@ -1,9 +1,10 @@
-import { GlFormInput } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { GlFormInput, GlFormGroup, GlFormCheckbox } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import IssuableForm from '~/vue_shared/issuable/create/components/issuable_form.vue';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import LabelsSelect from '~/sidebar/components/labels/labels_select_vue/labels_select_root.vue';
+import { TYPE_TEST_CASE } from '~/issues/constants';
import { __ } from '~/locale';
const createComponent = ({
@@ -11,13 +12,15 @@ const createComponent = ({
descriptionHelpPath = '/help/user/markdown',
labelsFetchPath = '/gitlab-org/gitlab-shell/-/labels.json',
labelsManagePath = '/gitlab-org/gitlab-shell/-/labels',
+ issuableType = TYPE_TEST_CASE,
} = {}) => {
- return shallowMount(IssuableForm, {
+ return shallowMountExtended(IssuableForm, {
propsData: {
descriptionPreviewPath,
descriptionHelpPath,
labelsFetchPath,
labelsManagePath,
+ issuableType,
},
slots: {
actions: `
@@ -58,7 +61,7 @@ describe('IssuableForm', () => {
describe('template', () => {
it('renders issuable title input field', () => {
- const titleFieldEl = wrapper.find('[data-testid="issuable-title"]');
+ const titleFieldEl = wrapper.findByTestId('issuable-title');
expect(titleFieldEl.exists()).toBe(true);
expect(titleFieldEl.find('label').text()).toBe('Title');
@@ -68,7 +71,7 @@ describe('IssuableForm', () => {
});
it('renders issuable description input field', () => {
- const descriptionFieldEl = wrapper.find('[data-testid="issuable-description"]');
+ const descriptionFieldEl = wrapper.findByTestId('issuable-description');
expect(descriptionFieldEl.exists()).toBe(true);
expect(descriptionFieldEl.find('label').text()).toBe('Description');
@@ -88,8 +91,23 @@ describe('IssuableForm', () => {
});
});
+ it('renders issuable confidential checkbox', () => {
+ const confidentialCheckboxEl = wrapper.findByTestId('issuable-confidential');
+ expect(confidentialCheckboxEl.exists()).toBe(true);
+
+ expect(confidentialCheckboxEl.findComponent(GlFormGroup).exists()).toBe(true);
+ expect(confidentialCheckboxEl.findComponent(GlFormGroup).attributes('label')).toBe(
+ 'Confidentiality',
+ );
+
+ expect(confidentialCheckboxEl.findComponent(GlFormCheckbox).exists()).toBe(true);
+ expect(confidentialCheckboxEl.findComponent(GlFormCheckbox).text()).toBe(
+ 'This test case is confidential and should only be visible to team members with at least Reporter access.',
+ );
+ });
+
it('renders labels select field', () => {
- const labelsSelectEl = wrapper.find('[data-testid="issuable-labels"]');
+ const labelsSelectEl = wrapper.findByTestId('issuable-labels');
expect(labelsSelectEl.exists()).toBe(true);
expect(labelsSelectEl.find('label').text()).toBe('Labels');
@@ -111,7 +129,7 @@ describe('IssuableForm', () => {
it('renders contents for slot "actions"', () => {
const buttonEl = wrapper
- .find('[data-testid="issuable-create-actions"]')
+ .findByTestId('issuable-create-actions')
.find('button.js-issuable-save');
expect(buttonEl.exists()).toBe(true);
diff --git a/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js b/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js
index 9f7254ba0e6..47da111b604 100644
--- a/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js
+++ b/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js
@@ -1,6 +1,5 @@
import { GlLink, GlLabel, GlIcon, GlFormCheckbox, GlSprintf } from '@gitlab/ui';
import { nextTick } from 'vue';
-import { escape } from 'lodash';
import { useFakeDate } from 'helpers/fake_date';
import { shallowMountExtended as shallowMount } from 'helpers/vue_test_utils_helper';
import IssuableItem from '~/vue_shared/issuable/list/components/issuable_item.vue';
@@ -288,23 +287,10 @@ describe('IssuableItem', () => {
expect(titleEl.exists()).toBe(true);
expect(titleEl.findComponent(GlLink).attributes('href')).toBe(expectedHref);
expect(titleEl.findComponent(GlLink).attributes('target')).toBe(expectedTarget);
- expect(titleEl.findComponent(GlLink).html()).toContain(mockIssuable.titleHtml);
+ expect(titleEl.findComponent(GlLink).text()).toBe(mockIssuable.title);
},
);
- it('renders issuable title with escaped markup when issue tracker is external', () => {
- const mockTitle = '<script>foobar</script>';
- wrapper = createComponent({
- issuable: {
- ...mockIssuable,
- title: mockTitle,
- externalTracker: 'jira',
- },
- });
-
- expect(wrapper.findByTestId('issuable-title').html()).toContain(escape(mockTitle));
- });
-
it('renders checkbox when `showCheckbox` prop is true', async () => {
wrapper = createComponent({
showCheckbox: true,
@@ -366,7 +352,7 @@ describe('IssuableItem', () => {
expect(hiddenIcon.props('name')).toBe('spam');
expect(hiddenIcon.attributes()).toMatchObject({
- title: 'This issue is hidden because its author has been banned',
+ title: 'This issue is hidden because its author has been banned.',
arialabel: 'Hidden',
});
});
diff --git a/spec/frontend/vue_shared/issuable/list/mock_data.js b/spec/frontend/vue_shared/issuable/list/mock_data.js
index b39d177f292..f8cf3ba5271 100644
--- a/spec/frontend/vue_shared/issuable/list/mock_data.js
+++ b/spec/frontend/vue_shared/issuable/list/mock_data.js
@@ -42,7 +42,7 @@ export const mockCurrentUserTodo = {
export const mockIssuable = {
iid: '30',
title: 'Dismiss Cipher with no integrity',
- titleHtml: '<gl-emoji title="party-parrot"></gl-emoji>Dismiss Cipher with no integrity',
+ titleHtml: 'Dismiss Cipher with no integrity',
description: 'fortitudinis _fomentis_ dolor mitigari solet.',
descriptionHtml: 'fortitudinis <i>fomentis</i> dolor mitigari solet.',
state: 'opened',
diff --git a/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js b/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js
index 3b6f06d835b..03395e5dfc0 100644
--- a/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js
+++ b/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js
@@ -2,6 +2,8 @@ import { GlBadge, GlButton, GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { resetHTMLFixture, setHTMLFixture } from 'helpers/fixtures';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import HiddenBadge from '~/issuable/components/hidden_badge.vue';
+import LockedBadge from '~/issuable/components/locked_badge.vue';
import { STATUS_CLOSED, STATUS_OPEN, STATUS_REOPENED, TYPE_ISSUE } from '~/issues/constants';
import { __ } from '~/locale';
import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
@@ -23,8 +25,8 @@ describe('IssuableHeader component', () => {
wrapper.findAllComponents(GlIcon).filter((component) => component.props('name') === name);
const findIcon = (name) =>
findGlIconWithName(name).exists() ? findGlIconWithName(name).at(0) : undefined;
- const findBlockedIcon = () => findIcon('lock');
- const findHiddenIcon = () => findIcon('spam');
+ const findBlockedBadge = () => wrapper.findComponent(LockedBadge);
+ const findHiddenBadge = () => wrapper.findComponent(HiddenBadge);
const findExternalLinkIcon = () => findIcon('external-link');
const findFirstContributionIcon = () => findIcon('first-contribution');
const findComponentTooltip = (component) => getBinding(component.element, 'gl-tooltip');
@@ -111,49 +113,31 @@ describe('IssuableHeader component', () => {
});
});
- describe('blocked icon', () => {
+ describe('blocked badge', () => {
it('renders when issuable is blocked', () => {
createComponent({ blocked: true });
- expect(findBlockedIcon().props('ariaLabel')).toBe('Blocked');
- });
-
- it('has tooltip', () => {
- createComponent({ blocked: true });
-
- expect(findComponentTooltip(findBlockedIcon())).toBeDefined();
- expect(findBlockedIcon().attributes('title')).toBe(
- 'This issue is locked. Only project members can comment.',
- );
+ expect(findBlockedBadge().props('issuableType')).toBe('issue');
});
it('does not render when issuable is not blocked', () => {
createComponent({ blocked: false });
- expect(findBlockedIcon()).toBeUndefined();
+ expect(findBlockedBadge().exists()).toBe(false);
});
});
- describe('hidden icon', () => {
+ describe('hidden badge', () => {
it('renders when issuable is hidden', () => {
createComponent({ isHidden: true });
- expect(findHiddenIcon().props('ariaLabel')).toBe('Hidden');
- });
-
- it('has tooltip', () => {
- createComponent({ isHidden: true });
-
- expect(findComponentTooltip(findHiddenIcon())).toBeDefined();
- expect(findHiddenIcon().attributes('title')).toBe(
- 'This issue is hidden because its author has been banned',
- );
+ expect(findHiddenBadge().props('issuableType')).toBe('issue');
});
it('does not render when issuable is not hidden', () => {
createComponent({ isHidden: false });
- expect(findHiddenIcon()).toBeUndefined();
+ expect(findHiddenBadge().exists()).toBe(false);
});
});