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-06-20 13:43:29 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-06-20 13:43:29 +0300
commit3b1af5cc7ed2666ff18b718ce5d30fa5a2756674 (patch)
tree3bc4a40e0ee51ec27eabf917c537033c0c5b14d4 /spec/frontend/super_sidebar
parent9bba14be3f2c211bf79e15769cd9b77bc73a13bc (diff)
Add latest changes from gitlab-org/gitlab@16-1-stable-eev16.1.0-rc42
Diffstat (limited to 'spec/frontend/super_sidebar')
-rw-r--r--spec/frontend/super_sidebar/components/brand_logo_spec.js42
-rw-r--r--spec/frontend/super_sidebar/components/context_switcher_spec.js6
-rw-r--r--spec/frontend/super_sidebar/components/create_menu_spec.js19
-rw-r--r--spec/frontend/super_sidebar/components/frequent_items_list_spec.js28
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/__snapshots__/search_item_spec.js.snap122
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js143
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/fake_search_input_spec.js44
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js133
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/search_item_spec.js33
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/utils_spec.js18
-rw-r--r--spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js62
-rw-r--r--spec/frontend/super_sidebar/components/help_center_spec.js49
-rw-r--r--spec/frontend/super_sidebar/components/items_list_spec.js44
-rw-r--r--spec/frontend/super_sidebar/components/sidebar_menu_spec.js204
-rw-r--r--spec/frontend/super_sidebar/components/user_bar_spec.js6
-rw-r--r--spec/frontend/super_sidebar/components/user_menu_spec.js33
-rw-r--r--spec/frontend/super_sidebar/super_sidebar_collapsed_state_manager_spec.js23
17 files changed, 761 insertions, 248 deletions
diff --git a/spec/frontend/super_sidebar/components/brand_logo_spec.js b/spec/frontend/super_sidebar/components/brand_logo_spec.js
new file mode 100644
index 00000000000..63c4bb9668b
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/brand_logo_spec.js
@@ -0,0 +1,42 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { createMockDirective } from 'helpers/vue_mock_directive';
+import BrandLogo from 'jh_else_ce/super_sidebar/components/brand_logo.vue';
+
+describe('Brand Logo component', () => {
+ let wrapper;
+
+ const defaultPropsData = {
+ logoUrl: 'path/to/logo',
+ };
+
+ const findBrandLogo = () => wrapper.findByTestId('brand-header-custom-logo');
+ const findDefaultLogo = () => wrapper.findByTestId('brand-header-default-logo');
+
+ const createWrapper = (props = {}) => {
+ wrapper = shallowMountExtended(BrandLogo, {
+ provide: {
+ rootPath: '/',
+ },
+ propsData: {
+ ...defaultPropsData,
+ ...props,
+ },
+ directives: {
+ GlTooltip: createMockDirective('gl-tooltip'),
+ },
+ });
+ };
+
+ it('renders it', () => {
+ createWrapper();
+ expect(findBrandLogo().exists()).toBe(true);
+ expect(findBrandLogo().attributes('src')).toBe(defaultPropsData.logoUrl);
+ });
+
+ it('when logoUrl given empty', () => {
+ createWrapper({ logoUrl: '' });
+
+ expect(findBrandLogo().exists()).toBe(false);
+ expect(findDefaultLogo().exists()).toBe(true);
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/context_switcher_spec.js b/spec/frontend/super_sidebar/components/context_switcher_spec.js
index 7928ee6400c..4317f451377 100644
--- a/spec/frontend/super_sidebar/components/context_switcher_spec.js
+++ b/spec/frontend/super_sidebar/components/context_switcher_spec.js
@@ -158,12 +158,6 @@ describe('ContextSwitcher component', () => {
expect(findContextSwitcherToggle().props('expanded')).toEqual(false);
});
- it("passes Popper.js' options to the disclosure dropdown", () => {
- expect(findDisclosureDropdown().props('popperOptions')).toMatchObject({
- modifiers: expect.any(Array),
- });
- });
-
it('does not emit the `toggle` event initially', () => {
expect(wrapper.emitted('toggle')).toBe(undefined);
});
diff --git a/spec/frontend/super_sidebar/components/create_menu_spec.js b/spec/frontend/super_sidebar/components/create_menu_spec.js
index 456085e23da..fe2fd17ae4d 100644
--- a/spec/frontend/super_sidebar/components/create_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/create_menu_spec.js
@@ -6,7 +6,6 @@ import {
GlDisclosureDropdownItem,
} from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { stubComponent } from 'helpers/stub_component';
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
import { __ } from '~/locale';
import CreateMenu from '~/super_sidebar/components/create_menu.vue';
@@ -21,8 +20,6 @@ describe('CreateMenu component', () => {
const findInviteMembersTrigger = () => wrapper.findComponent(InviteMembersTrigger);
const findGlTooltip = () => wrapper.findComponent(GlTooltip);
- const closeAndFocusMock = jest.fn();
-
const createWrapper = () => {
wrapper = shallowMountExtended(CreateMenu, {
propsData: {
@@ -30,9 +27,7 @@ describe('CreateMenu component', () => {
},
stubs: {
InviteMembersTrigger,
- GlDisclosureDropdown: stubComponent(GlDisclosureDropdown, {
- methods: { closeAndFocus: closeAndFocusMock },
- }),
+ GlDisclosureDropdown,
},
});
};
@@ -42,11 +37,12 @@ describe('CreateMenu component', () => {
createWrapper();
});
- it('passes popper options to the dropdown', () => {
+ it('passes custom offset to the dropdown', () => {
createWrapper();
- expect(findGlDisclosureDropdown().props('popperOptions')).toEqual({
- modifiers: [{ name: 'offset', options: { offset: [-147, 4] } }],
+ expect(findGlDisclosureDropdown().props('dropdownOffset')).toEqual({
+ crossAxis: -147,
+ mainAxis: 4,
});
});
@@ -93,10 +89,5 @@ describe('CreateMenu component', () => {
expect(findGlTooltip().exists()).toBe(true);
});
-
- it('closes the dropdown when invite members modal is opened', () => {
- findInviteMembersTrigger().vm.$emit('modal-opened');
- expect(closeAndFocusMock).toHaveBeenCalled();
- });
});
});
diff --git a/spec/frontend/super_sidebar/components/frequent_items_list_spec.js b/spec/frontend/super_sidebar/components/frequent_items_list_spec.js
index 5329a8f5da3..63dd941974a 100644
--- a/spec/frontend/super_sidebar/components/frequent_items_list_spec.js
+++ b/spec/frontend/super_sidebar/components/frequent_items_list_spec.js
@@ -1,4 +1,4 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
import { s__ } from '~/locale';
import FrequentItemsList from '~/super_sidebar/components//frequent_items_list.vue';
import ItemsList from '~/super_sidebar/components/items_list.vue';
@@ -18,18 +18,20 @@ describe('FrequentItemsList component', () => {
const findListTitle = () => wrapper.findByTestId('list-title');
const findItemsList = () => wrapper.findComponent(ItemsList);
const findEmptyText = () => wrapper.findByTestId('empty-text');
+ const findRemoveItemButton = () => wrapper.findByTestId('item-remove');
- const createWrapper = ({ props = {} } = {}) => {
- wrapper = shallowMountExtended(FrequentItemsList, {
+ const createWrapperFactory = (mountFn = shallowMountExtended) => () => {
+ wrapper = mountFn(FrequentItemsList, {
propsData: {
title,
pristineText,
storageKey,
maxItems,
- ...props,
},
});
};
+ const createWrapper = createWrapperFactory();
+ const createFullWrapper = createWrapperFactory(mountExtended);
describe('default', () => {
beforeEach(() => {
@@ -64,16 +66,20 @@ describe('FrequentItemsList component', () => {
it('does not render the empty text slot', () => {
expect(findEmptyText().exists()).toBe(false);
});
+ });
- describe('items editing', () => {
- it('remove-item event emission from items-list causes list item to be removed', async () => {
- const localStorageProjects = findItemsList().props('items');
+ describe('items editing', () => {
+ beforeEach(() => {
+ window.localStorage.setItem(storageKey, cachedFrequentProjects);
+ createFullWrapper();
+ });
- await findItemsList().vm.$emit('remove-item', localStorageProjects[0]);
+ it('remove-item event emission from items-list causes list item to be removed', async () => {
+ const localStorageProjects = findItemsList().props('items');
+ await findRemoveItemButton().trigger('click');
- expect(findItemsList().props('items')).toHaveLength(maxItems - 1);
- expect(findItemsList().props('items')).not.toContain(localStorageProjects[0]);
- });
+ expect(findItemsList().props('items')).toHaveLength(maxItems - 1);
+ expect(findItemsList().props('items')).not.toContain(localStorageProjects[0]);
});
});
});
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/__snapshots__/search_item_spec.js.snap b/spec/frontend/super_sidebar/components/global_search/command_palette/__snapshots__/search_item_spec.js.snap
new file mode 100644
index 00000000000..d16d137db2f
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/__snapshots__/search_item_spec.js.snap
@@ -0,0 +1,122 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`SearchItem should render the item 1`] = `
+<div
+ class="gl-display-flex gl-align-items-center"
+>
+ <gl-avatar-stub
+ alt="avatar"
+ aria-hidden="true"
+ class="gl-mr-3"
+ entityid="37"
+ entityname=""
+ shape="rect"
+ size="16"
+ src="https://www.gravatar.com/avatar/a9638f4ec70148d51e56bf05ad41e993?s=80&d=identicon"
+ />
+
+ <!---->
+
+ <span
+ class="gl-display-flex gl-flex-direction-column"
+ >
+ <span
+ class="gl-text-gray-900"
+ />
+
+ <!---->
+ </span>
+</div>
+`;
+
+exports[`SearchItem should render the item 2`] = `
+<div
+ class="gl-display-flex gl-align-items-center"
+>
+ <!---->
+
+ <gl-icon-stub
+ class="gl-mr-3"
+ name="users"
+ size="16"
+ />
+
+ <span
+ class="gl-display-flex gl-flex-direction-column"
+ >
+ <span
+ class="gl-text-gray-900"
+ >
+ Manage &gt; Activity
+ </span>
+
+ <!---->
+ </span>
+</div>
+`;
+
+exports[`SearchItem should render the item 3`] = `
+<div
+ class="gl-display-flex gl-align-items-center"
+>
+ <gl-avatar-stub
+ alt="avatar"
+ aria-hidden="true"
+ class="gl-mr-3"
+ entityid="1"
+ entityname="MockProject1"
+ shape="rect"
+ size="32"
+ src="/project/avatar/1/avatar.png"
+ />
+
+ <!---->
+
+ <span
+ class="gl-display-flex gl-flex-direction-column"
+ >
+ <span
+ class="gl-text-gray-900"
+ >
+ MockProject1
+ </span>
+
+ <span
+ class="gl-font-sm gl-text-gray-500"
+ >
+ Gitlab Org / MockProject1
+ </span>
+ </span>
+</div>
+`;
+
+exports[`SearchItem should render the item 4`] = `
+<div
+ class="gl-display-flex gl-align-items-center"
+>
+ <gl-avatar-stub
+ alt="avatar"
+ aria-hidden="true"
+ class="gl-mr-3"
+ entityid="7"
+ entityname="Flight"
+ shape="rect"
+ size="16"
+ src=""
+ />
+
+ <!---->
+
+ <span
+ class="gl-display-flex gl-flex-direction-column"
+ >
+ <span
+ class="gl-text-gray-900"
+ >
+ Dismiss Cipher with no integrity
+ </span>
+
+ <!---->
+ </span>
+</div>
+`;
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js b/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js
new file mode 100644
index 00000000000..21d085dc0fb
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js
@@ -0,0 +1,143 @@
+import fuzzaldrinPlus from 'fuzzaldrin-plus';
+import { GlDisclosureDropdownGroup, GlDisclosureDropdownItem, GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import CommandPaletteItems from '~/super_sidebar/components/global_search/command_palette/command_palette_items.vue';
+import {
+ COMMAND_HANDLE,
+ USERS_GROUP_TITLE,
+ USER_HANDLE,
+ SEARCH_SCOPE,
+} from '~/super_sidebar/components/global_search/command_palette/constants';
+import {
+ commandMapper,
+ linksReducer,
+} from '~/super_sidebar/components/global_search/command_palette/utils';
+import { getFormattedItem } from '~/super_sidebar/components/global_search/utils';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import waitForPromises from 'helpers/wait_for_promises';
+import { COMMANDS, LINKS, USERS } from './mock_data';
+
+const links = LINKS.reduce(linksReducer, []);
+
+describe('CommandPaletteItems', () => {
+ let wrapper;
+ const autocompletePath = '/autocomplete';
+ const searchContext = { project: { id: 1 }, group: { id: 2 } };
+
+ const createComponent = (props) => {
+ wrapper = shallowMount(CommandPaletteItems, {
+ propsData: {
+ handle: COMMAND_HANDLE,
+ searchQuery: '',
+ ...props,
+ },
+ stubs: {
+ GlDisclosureDropdownGroup,
+ GlDisclosureDropdownItem,
+ },
+ provide: {
+ commandPaletteCommands: COMMANDS,
+ commandPaletteLinks: LINKS,
+ autocompletePath,
+ searchContext,
+ },
+ });
+ };
+
+ const findItems = () => wrapper.findAllComponents(GlDisclosureDropdownItem);
+ const findGroups = () => wrapper.findAllComponents(GlDisclosureDropdownGroup);
+ const findLoader = () => wrapper.findComponent(GlLoadingIcon);
+
+ describe('COMMANDS & LINKS', () => {
+ it('renders all commands initially', () => {
+ createComponent();
+ const commandGroup = COMMANDS.map(commandMapper)[0];
+ expect(findItems()).toHaveLength(commandGroup.items.length);
+ expect(findGroups().at(0).props('group')).toEqual({
+ name: commandGroup.name,
+ items: commandGroup.items,
+ });
+ });
+
+ describe('with search query', () => {
+ it('should filter commands and links by the search query', async () => {
+ jest.spyOn(fuzzaldrinPlus, 'filter');
+ createComponent({ searchQuery: 'mr' });
+ const searchQuery = 'todo';
+ await wrapper.setProps({ searchQuery });
+ const commandGroup = COMMANDS.map(commandMapper)[0];
+ expect(fuzzaldrinPlus.filter).toHaveBeenCalledWith(
+ commandGroup.items,
+ searchQuery,
+ expect.objectContaining({ key: 'text' }),
+ );
+ expect(fuzzaldrinPlus.filter).toHaveBeenCalledWith(
+ links,
+ searchQuery,
+ expect.objectContaining({ key: 'keywords' }),
+ );
+ });
+
+ it('should display no results message when no command matched the search query', async () => {
+ jest.spyOn(fuzzaldrinPlus, 'filter').mockReturnValue([]);
+ createComponent({ searchQuery: 'mr' });
+ const searchQuery = 'todo';
+ await wrapper.setProps({ searchQuery });
+ expect(wrapper.text()).toBe('No results found');
+ });
+ });
+ });
+
+ describe('USERS, ISSUES, PROJECTS', () => {
+ let mockAxios;
+
+ beforeEach(() => {
+ mockAxios = new MockAdapter(axios);
+ });
+
+ it('should NOT start search by the search query which is less than 3 chars', () => {
+ jest.spyOn(axios, 'get');
+ const searchQuery = 'us';
+ createComponent({ handle: USER_HANDLE, searchQuery });
+
+ expect(axios.get).not.toHaveBeenCalled();
+
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('should start scoped search with 3+ chars and display a loader', () => {
+ jest.spyOn(axios, 'get');
+ const searchQuery = 'user';
+ createComponent({ handle: USER_HANDLE, searchQuery });
+
+ expect(axios.get).toHaveBeenCalledWith(
+ `${autocompletePath}?term=${searchQuery}&project_id=${searchContext.project.id}&filter=search&scope=${SEARCH_SCOPE[USER_HANDLE]}`,
+ );
+ expect(findLoader().exists()).toBe(true);
+ });
+
+ it('should render returned items', async () => {
+ mockAxios.onGet().replyOnce(HTTP_STATUS_OK, USERS);
+
+ const searchQuery = 'user';
+ createComponent({ handle: USER_HANDLE, searchQuery });
+
+ await waitForPromises();
+ expect(findItems()).toHaveLength(USERS.length);
+ expect(findGroups().at(0).props('group')).toMatchObject({
+ name: USERS_GROUP_TITLE,
+ items: USERS.map(getFormattedItem),
+ });
+ });
+
+ it('should display no results message when no users matched the search query', async () => {
+ mockAxios.onGet().replyOnce(HTTP_STATUS_OK, []);
+ const searchQuery = 'user';
+ createComponent({ handle: USER_HANDLE, searchQuery });
+ await waitForPromises();
+ expect(wrapper.text()).toBe('No results found');
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/fake_search_input_spec.js b/spec/frontend/super_sidebar/components/global_search/command_palette/fake_search_input_spec.js
new file mode 100644
index 00000000000..a8e91395303
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/fake_search_input_spec.js
@@ -0,0 +1,44 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import FakeSearchInput from '~/super_sidebar/components/global_search/command_palette/fake_search_input.vue';
+import {
+ SEARCH_SCOPE_PLACEHOLDER,
+ COMMON_HANDLES,
+ COMMAND_HANDLE,
+} from '~/super_sidebar/components/global_search/command_palette/constants';
+
+describe('FakeSearchInput', () => {
+ let wrapper;
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(FakeSearchInput, {
+ propsData: {
+ scope: COMMAND_HANDLE,
+ userInput: '',
+ ...props,
+ },
+ });
+ };
+
+ const findSearchScope = () => wrapper.findByTestId('search-scope');
+ const findSearchScopePlaceholder = () => wrapper.findByTestId('search-scope-placeholder');
+
+ it('should render the search scope', () => {
+ createComponent();
+ expect(findSearchScope().text()).toBe(COMMAND_HANDLE);
+ });
+
+ describe('placeholder', () => {
+ it.each(COMMON_HANDLES)(
+ 'should render the placeholder for the %s scope when there is no user input',
+ (scope) => {
+ createComponent({ scope });
+ expect(findSearchScopePlaceholder().text()).toBe(SEARCH_SCOPE_PLACEHOLDER[scope]);
+ },
+ );
+
+ it('should NOT render the placeholder when there is user input', () => {
+ createComponent({ userInput: 'todo' });
+ expect(findSearchScopePlaceholder().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js b/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js
new file mode 100644
index 00000000000..ec65a43d549
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js
@@ -0,0 +1,133 @@
+export const COMMANDS = [
+ {
+ name: 'Global',
+ items: [
+ {
+ text: 'New project/repository',
+ href: '/projects/new',
+ },
+ {
+ text: 'New group',
+ href: '/groups/new',
+ },
+ {
+ text: 'New snippet',
+ href: '/-/snippets/new',
+ },
+ {
+ text: 'Invite members',
+ href: '/-/snippets/new',
+ component: 'invite_members',
+ },
+ ],
+ },
+];
+
+export const LINKS = [
+ {
+ title: 'Manage',
+ icon: 'users',
+ link: '/flightjs/Flight/activity',
+ is_active: false,
+ pill_count: null,
+ items: [
+ {
+ id: 'activity',
+ title: 'Activity',
+ icon: null,
+ link: '/flightjs/Flight/activity',
+ pill_count: null,
+ link_classes: 'shortcuts-project-activity',
+ is_active: false,
+ },
+ {
+ id: 'members',
+ title: 'Members',
+ icon: null,
+ link: '/flightjs/Flight/-/project_members',
+ pill_count: null,
+ link_classes: null,
+ is_active: false,
+ },
+ {
+ id: 'labels',
+ title: 'Labels',
+ icon: null,
+ link: '/flightjs/Flight/-/labels',
+ pill_count: null,
+ link_classes: null,
+ is_active: false,
+ },
+ ],
+ separated: false,
+ },
+];
+
+export const TRANSFORMED_LINKS = [
+ {
+ href: '/flightjs/Flight/activity',
+ icon: 'users',
+ keywords: 'Manage',
+ text: 'Manage',
+ },
+ {
+ href: '/flightjs/Flight/activity',
+ icon: 'users',
+ keywords: 'Activity',
+ text: 'Manage > Activity',
+ },
+ {
+ href: '/flightjs/Flight/-/project_members',
+ icon: 'users',
+ keywords: 'Members',
+ text: 'Manage > Members',
+ },
+ {
+ href: '/flightjs/Flight/-/labels',
+ icon: 'users',
+ keywords: 'Labels',
+ text: 'Manage > Labels',
+ },
+];
+
+export const USERS = [
+ {
+ id: 37,
+ username: 'reported_user_14',
+ name: 'Cole Dickinson',
+ web_url: 'http://127.0.0.1:3000/reported_user_14',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/a9638f4ec70148d51e56bf05ad41e993?s=80\u0026d=identicon',
+ },
+ {
+ id: 47,
+ username: 'sharlatenok',
+ name: 'Olena Horal-Koretska',
+ web_url: 'http://127.0.0.1:3000/sharlatenok',
+ },
+ {
+ id: 30,
+ username: 'reported_user_7',
+ name: 'Violeta Feeney',
+ web_url: 'http://127.0.0.1:3000/reported_user_7',
+ },
+];
+
+export const PROJECT = {
+ category: 'Projects',
+ id: 1,
+ label: 'Gitlab Org / MockProject1',
+ value: 'MockProject1',
+ url: 'project/1',
+ avatar_url: '/project/avatar/1/avatar.png',
+};
+
+export const ISSUE = {
+ avatar_url: '',
+ category: 'Recent issues',
+ id: 516,
+ label: 'Dismiss Cipher with no integrity',
+ project_id: 7,
+ project_name: 'Flight',
+ url: '/flightjs/Flight/-/issues/37',
+};
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/search_item_spec.js b/spec/frontend/super_sidebar/components/global_search/command_palette/search_item_spec.js
new file mode 100644
index 00000000000..c7e49310588
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/search_item_spec.js
@@ -0,0 +1,33 @@
+import { shallowMount } from '@vue/test-utils';
+import SearchItem from '~/super_sidebar/components/global_search/command_palette/search_item.vue';
+import { getFormattedItem } from '~/super_sidebar/components/global_search/utils';
+import { linksReducer } from '~/super_sidebar/components/global_search/command_palette/utils';
+import { USERS, LINKS, PROJECT, ISSUE } from './mock_data';
+
+jest.mock('~/lib/utils/highlight', () => ({
+ __esModule: true,
+ default: (text) => text,
+}));
+const mockUser = getFormattedItem(USERS[0]);
+const mockCommand = LINKS.reduce(linksReducer, [])[1];
+const mockProject = getFormattedItem(PROJECT);
+const mockIssue = getFormattedItem(ISSUE);
+
+describe('SearchItem', () => {
+ let wrapper;
+
+ const createComponent = (item) => {
+ wrapper = shallowMount(SearchItem, {
+ propsData: {
+ item,
+ searchQuery: 'root',
+ },
+ });
+ };
+
+ it.each([mockUser, mockCommand, mockProject, mockIssue])('should render the item', (item) => {
+ createComponent(item);
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/utils_spec.js b/spec/frontend/super_sidebar/components/global_search/command_palette/utils_spec.js
new file mode 100644
index 00000000000..0b75787723e
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/utils_spec.js
@@ -0,0 +1,18 @@
+import {
+ commandMapper,
+ linksReducer,
+} from '~/super_sidebar/components/global_search/command_palette/utils';
+import { COMMANDS, LINKS, TRANSFORMED_LINKS } from './mock_data';
+
+describe('linksReducer', () => {
+ it('should transform links', () => {
+ expect(LINKS.reduce(linksReducer, [])).toEqual(TRANSFORMED_LINKS);
+ });
+});
+
+describe('commandMapper', () => {
+ it('should temporarily remove the `invite_members` item', () => {
+ const initialCommandsLength = COMMANDS[0].items.length;
+ expect(COMMANDS.map(commandMapper)[0].items).toHaveLength(initialCommandsLength - 1);
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js b/spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js
index f78e141afad..9b7b9e288df 100644
--- a/spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js
+++ b/spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js
@@ -7,6 +7,12 @@ import GlobalSearchModal from '~/super_sidebar/components/global_search/componen
import GlobalSearchAutocompleteItems from '~/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue';
import GlobalSearchDefaultItems from '~/super_sidebar/components/global_search/components/global_search_default_items.vue';
import GlobalSearchScopedItems from '~/super_sidebar/components/global_search/components/global_search_scoped_items.vue';
+import FakeSearchInput from '~/super_sidebar/components/global_search/command_palette/fake_search_input.vue';
+import CommandPaletteItems from '~/super_sidebar/components/global_search/command_palette/command_palette_items.vue';
+import {
+ SEARCH_OR_COMMAND_MODE_PLACEHOLDER,
+ COMMON_HANDLES,
+} from '~/super_sidebar/components/global_search/command_palette/constants';
import {
SEARCH_INPUT_DESCRIPTION,
SEARCH_RESULTS_DESCRIPTION,
@@ -17,6 +23,7 @@ import {
IS_SEARCHING,
SEARCH_SHORTCUTS_MIN_CHARACTERS,
} from '~/super_sidebar/components/global_search/constants';
+import { SEARCH_GITLAB } from '~/vue_shared/global_search/constants';
import { truncate } from '~/lib/utils/text_utility';
import { visitUrl } from '~/lib/utils/url_utility';
import { ENTER_KEY } from '~/lib/utils/keys';
@@ -53,7 +60,18 @@ describe('GlobalSearchModal', () => {
},
};
- const createComponent = (initialState, mockGetters, stubs) => {
+ const defaultMockGetters = {
+ searchQuery: () => MOCK_SEARCH_QUERY,
+ searchOptions: () => MOCK_DEFAULT_SEARCH_OPTIONS,
+ scopedSearchOptions: () => MOCK_SCOPED_SEARCH_OPTIONS,
+ };
+
+ const createComponent = (
+ initialState = deafaultMockState,
+ mockGetters = defaultMockGetters,
+ stubs,
+ glFeatures = { commandPalette: false },
+ ) => {
const store = new Vuex.Store({
state: {
...deafaultMockState,
@@ -71,6 +89,7 @@ describe('GlobalSearchModal', () => {
wrapper = shallowMountExtended(GlobalSearchModal, {
store,
stubs,
+ provide: { glFeatures },
});
};
@@ -98,6 +117,8 @@ describe('GlobalSearchModal', () => {
wrapper.findComponent(GlobalSearchAutocompleteItems);
const findSearchInputDescription = () => wrapper.find(`#${SEARCH_INPUT_DESCRIPTION}`);
const findSearchResultsDescription = () => wrapper.findByTestId(SEARCH_RESULTS_DESCRIPTION);
+ const findCommandPaletteItems = () => wrapper.findComponent(CommandPaletteItems);
+ const findFakeSearchInput = () => wrapper.findComponent(FakeSearchInput);
describe('template', () => {
describe('always renders', () => {
@@ -281,6 +302,45 @@ describe('GlobalSearchModal', () => {
).toBe(iconName);
});
});
+
+ describe('Command palette', () => {
+ describe('when FF `command_palette` is disabled', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should not render command mode components', () => {
+ expect(findCommandPaletteItems().exists()).toBe(false);
+ expect(findFakeSearchInput().exists()).toBe(false);
+ });
+
+ it('should provide default placeholder to the search input', () => {
+ expect(findGlobalSearchInput().attributes('placeholder')).toBe(SEARCH_GITLAB);
+ });
+ });
+
+ describe.each(COMMON_HANDLES)(
+ 'when FF `command_palette` is enabled and search handle is %s',
+ (handle) => {
+ beforeEach(() => {
+ createComponent({ search: handle }, undefined, undefined, {
+ commandPalette: true,
+ });
+ });
+
+ it('should render command mode components', () => {
+ expect(findCommandPaletteItems().exists()).toBe(true);
+ expect(findFakeSearchInput().exists()).toBe(true);
+ });
+
+ it('should provide an alternative placeholder to the search input', () => {
+ expect(findGlobalSearchInput().attributes('placeholder')).toBe(
+ SEARCH_OR_COMMAND_MODE_PLACEHOLDER,
+ );
+ });
+ },
+ );
+ });
});
describe('events', () => {
diff --git a/spec/frontend/super_sidebar/components/help_center_spec.js b/spec/frontend/super_sidebar/components/help_center_spec.js
index 808c30436a3..6af1172e4d8 100644
--- a/spec/frontend/super_sidebar/components/help_center_spec.js
+++ b/spec/frontend/super_sidebar/components/help_center_spec.js
@@ -4,7 +4,7 @@ import toggleWhatsNewDrawer from '~/whats_new';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import HelpCenter from '~/super_sidebar/components/help_center.vue';
import { helpPagePath } from '~/helpers/help_page_helper';
-import { DOMAIN, PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
+import { DOCS_URL, FORUM_URL, PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { STORAGE_KEY } from '~/whats_new/utils/notification';
import { helpCenterState } from '~/super_sidebar/constants';
@@ -25,6 +25,7 @@ describe('HelpCenter component', () => {
};
const withinComponent = () => within(wrapper.element);
const findButton = (name) => withinComponent().getByRole('button', { name });
+ const findNotificationDot = () => wrapper.findByTestId('notification-dot');
// eslint-disable-next-line no-shadow
const createWrapper = (sidebarData) => {
@@ -52,7 +53,7 @@ describe('HelpCenter component', () => {
},
{
text: HelpCenter.i18n.docs,
- href: `https://docs.${DOMAIN}`,
+ href: DOCS_URL,
extraAttrs: trackingAttrs('gitlab_documentation'),
},
{
@@ -62,7 +63,7 @@ describe('HelpCenter component', () => {
},
{
text: HelpCenter.i18n.forum,
- href: `https://forum.${DOMAIN}/`,
+ href: FORUM_URL,
extraAttrs: trackingAttrs('community_forum'),
},
{
@@ -91,22 +92,22 @@ describe('HelpCenter component', () => {
]);
});
- it('passes popper options to the dropdown', () => {
- expect(findDropdown().props('popperOptions')).toEqual({
- modifiers: [{ name: 'offset', options: { offset: [-4, 4] } }],
+ it('passes custom offset to the dropdown', () => {
+ expect(findDropdown().props('dropdownOffset')).toEqual({
+ crossAxis: -4,
+ mainAxis: 4,
});
});
describe('with show_tanuki_bot true', () => {
beforeEach(() => {
createWrapper({ ...sidebarData, show_tanuki_bot: true });
- jest.spyOn(wrapper.vm.$refs.dropdown, 'close');
});
it('shows Ask GitLab Chat with the help items', () => {
expect(findDropdownGroup(0).props('group').items).toEqual([
expect.objectContaining({
- icon: 'tanuki',
+ icon: 'tanuki-ai',
text: HelpCenter.i18n.chat,
extraAttrs: trackingAttrs('tanuki_bot_help_dropdown'),
}),
@@ -119,10 +120,6 @@ describe('HelpCenter component', () => {
findButton('Ask GitLab Chat').click();
});
- it('closes the dropdown', () => {
- expect(wrapper.vm.$refs.dropdown.close).toHaveBeenCalled();
- });
-
it('sets helpCenterState.showTanukiBotChatDrawer to true', () => {
expect(helpCenterState.showTanukiBotChatDrawer).toBe(true);
});
@@ -150,16 +147,9 @@ describe('HelpCenter component', () => {
let button;
beforeEach(() => {
- jest.spyOn(wrapper.vm.$refs.dropdown, 'close');
-
button = findButton('Keyboard shortcuts ?');
});
- it('closes the dropdown', () => {
- button.click();
- expect(wrapper.vm.$refs.dropdown.close).toHaveBeenCalled();
- });
-
it('shows the keyboard shortcuts modal', () => {
// This relies on the event delegation set up by the Shortcuts class in
// ~/behaviors/shortcuts/shortcuts.js.
@@ -179,17 +169,12 @@ describe('HelpCenter component', () => {
describe('showWhatsNew', () => {
beforeEach(() => {
- jest.spyOn(wrapper.vm.$refs.dropdown, 'close');
beforeEach(() => {
createWrapper({ ...sidebarData, show_version_check: true });
});
findButton("What's new 5").click();
});
- it('closes the dropdown', () => {
- expect(wrapper.vm.$refs.dropdown.close).toHaveBeenCalled();
- });
-
it('shows the "What\'s new" slideout', () => {
expect(toggleWhatsNewDrawer).toHaveBeenCalledWith(expect.any(Object));
});
@@ -219,8 +204,8 @@ describe('HelpCenter component', () => {
createWrapper({ ...sidebarData, display_whats_new: false });
});
- it('is false', () => {
- expect(wrapper.vm.showWhatsNewNotification).toBe(false);
+ it('does not render notification dot', () => {
+ expect(findNotificationDot().exists()).toBe(false);
});
});
@@ -231,8 +216,8 @@ describe('HelpCenter component', () => {
createWrapper({ ...sidebarData, display_whats_new: true });
});
- it('is true', () => {
- expect(wrapper.vm.showWhatsNewNotification).toBe(true);
+ it('renders notification dot', () => {
+ expect(findNotificationDot().exists()).toBe(true);
});
describe('when "What\'s new" drawer got opened', () => {
@@ -240,8 +225,8 @@ describe('HelpCenter component', () => {
findButton("What's new 5").click();
});
- it('is false', () => {
- expect(wrapper.vm.showWhatsNewNotification).toBe(false);
+ it('does not render notification dot', () => {
+ expect(findNotificationDot().exists()).toBe(false);
});
});
@@ -251,8 +236,8 @@ describe('HelpCenter component', () => {
createWrapper({ ...sidebarData, display_whats_new: true });
});
- it('is false', () => {
- expect(wrapper.vm.showWhatsNewNotification).toBe(false);
+ it('does not render notification dot', () => {
+ expect(findNotificationDot().exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/super_sidebar/components/items_list_spec.js b/spec/frontend/super_sidebar/components/items_list_spec.js
index d5e8043cce9..8e00984f500 100644
--- a/spec/frontend/super_sidebar/components/items_list_spec.js
+++ b/spec/frontend/super_sidebar/components/items_list_spec.js
@@ -1,5 +1,4 @@
-import { GlIcon } from '@gitlab/ui';
-import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ItemsList from '~/super_sidebar/components/items_list.vue';
import NavItem from '~/super_sidebar/components/nav_item.vue';
import { cachedFrequentProjects } from '../mock_data';
@@ -12,8 +11,8 @@ describe('ItemsList component', () => {
const findNavItems = () => wrapper.findAllComponents(NavItem);
- const createWrapper = ({ props = {}, slots = {}, mountFn = shallowMountExtended } = {}) => {
- wrapper = mountFn(ItemsList, {
+ const createWrapper = ({ props = {}, slots = {} } = {}) => {
+ wrapper = shallowMountExtended(ItemsList, {
propsData: {
...props,
},
@@ -61,41 +60,4 @@ describe('ItemsList component', () => {
expect(wrapper.findByTestId(testId).exists()).toBe(true);
});
-
- describe('item removal', () => {
- const findRemoveButton = () => wrapper.findByTestId('item-remove');
- const mockProject = {
- ...firstMockedProject,
- title: firstMockedProject.name,
- };
-
- beforeEach(() => {
- createWrapper({
- props: {
- items: [mockProject],
- },
- mountFn: mountExtended,
- });
- });
-
- it('renders the remove button', () => {
- const itemRemoveButton = findRemoveButton();
-
- expect(itemRemoveButton.exists()).toBe(true);
- expect(itemRemoveButton.attributes('title')).toBe('Remove');
- expect(itemRemoveButton.findComponent(GlIcon).props('name')).toBe('dash');
- });
-
- it('emits `remove-item` event with item param when remove button is clicked', () => {
- const itemRemoveButton = findRemoveButton();
-
- itemRemoveButton.vm.$emit(
- 'click',
- { stopPropagation: jest.fn(), preventDefault: jest.fn() },
- mockProject,
- );
-
- expect(wrapper.emitted('remove-item')).toEqual([[mockProject]]);
- });
- });
});
diff --git a/spec/frontend/super_sidebar/components/sidebar_menu_spec.js b/spec/frontend/super_sidebar/components/sidebar_menu_spec.js
index 9b726b620dd..21e5220edd9 100644
--- a/spec/frontend/super_sidebar/components/sidebar_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/sidebar_menu_spec.js
@@ -1,6 +1,8 @@
-import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import SidebarMenu from '~/super_sidebar/components/sidebar_menu.vue';
import PinnedSection from '~/super_sidebar/components/pinned_section.vue';
+import NavItem from '~/super_sidebar/components/nav_item.vue';
+import MenuSection from '~/super_sidebar/components/menu_section.vue';
import { PANELS_WITH_PINS } from '~/super_sidebar/constants';
import { sidebarData } from '../mock_data';
@@ -11,174 +13,142 @@ const menuItems = [
{ id: 4, title: 'Also with subitems', items: [{ id: 41, title: 'Subitem' }] },
];
-describe('SidebarMenu component', () => {
+describe('Sidebar Menu', () => {
let wrapper;
- const createWrapper = (mockData) => {
- wrapper = mountExtended(SidebarMenu, {
+ const createWrapper = (extraProps = {}) => {
+ wrapper = shallowMountExtended(SidebarMenu, {
propsData: {
- items: mockData.current_menu_items,
- pinnedItemIds: mockData.pinned_items,
- panelType: mockData.panel_type,
- updatePinsUrl: mockData.update_pins_url,
+ items: sidebarData.current_menu_items,
+ pinnedItemIds: sidebarData.pinned_items,
+ panelType: sidebarData.panel_type,
+ updatePinsUrl: sidebarData.update_pins_url,
+ ...extraProps,
},
});
};
+ const findStaticItemsSection = () => wrapper.findByTestId('static-items-section');
+ const findStaticItems = () => findStaticItemsSection().findAllComponents(NavItem);
const findPinnedSection = () => wrapper.findComponent(PinnedSection);
const findMainMenuSeparator = () => wrapper.findByTestId('main-menu-separator');
-
- describe('computed', () => {
- describe('supportsPins', () => {
- it('is true for the project sidebar', () => {
- createWrapper({ ...sidebarData, panel_type: 'project' });
- expect(wrapper.vm.supportsPins).toBe(true);
- });
-
- it('is true for the group sidebar', () => {
- createWrapper({ ...sidebarData, panel_type: 'group' });
- expect(wrapper.vm.supportsPins).toBe(true);
- });
-
- it('is false for any other sidebar', () => {
- createWrapper({ ...sidebarData, panel_type: 'your_work' });
- expect(wrapper.vm.supportsPins).toEqual(false);
+ const findNonStaticItemsSection = () => wrapper.findByTestId('non-static-items-section');
+ const findNonStaticItems = () => findNonStaticItemsSection().findAllComponents(NavItem);
+ const findNonStaticSectionItems = () =>
+ findNonStaticItemsSection().findAllComponents(MenuSection);
+
+ describe('Static section', () => {
+ describe('when the sidebar supports pins', () => {
+ beforeEach(() => {
+ createWrapper({
+ items: menuItems,
+ panelType: PANELS_WITH_PINS[0],
+ });
});
- });
- describe('flatPinnableItems', () => {
- it('returns all subitems in a flat array', () => {
- createWrapper({ ...sidebarData, current_menu_items: menuItems });
- expect(wrapper.vm.flatPinnableItems).toEqual([
- { id: 21, title: 'Pinned subitem' },
- { id: 41, title: 'Subitem' },
+ it('renders static items section', () => {
+ expect(findStaticItemsSection().exists()).toBe(true);
+ expect(findStaticItems().wrappers.map((w) => w.props('item').title)).toEqual([
+ 'No subitems',
+ 'Empty subitems array',
]);
});
});
- describe('staticItems', () => {
- describe('when the sidebar supports pins', () => {
- beforeEach(() => {
- createWrapper({
- ...sidebarData,
- current_menu_items: menuItems,
- panel_type: PANELS_WITH_PINS[0],
- });
+ describe('when the sidebar does not support pins', () => {
+ beforeEach(() => {
+ createWrapper({
+ items: menuItems,
+ panelType: 'explore',
});
+ });
- it('makes everything that has no subitems a static item', () => {
- expect(wrapper.vm.staticItems.map((i) => i.title)).toEqual([
- 'No subitems',
- 'Empty subitems array',
- ]);
- });
+ it('does not render static items section', () => {
+ expect(findStaticItemsSection().exists()).toBe(false);
});
+ });
+ });
- describe('when the sidebar does not support pins', () => {
- beforeEach(() => {
- createWrapper({
- ...sidebarData,
- current_menu_items: menuItems,
- panel_type: 'explore',
- });
- });
+ describe('Pinned section', () => {
+ it('is rendered in a project sidebar', () => {
+ createWrapper({ panelType: 'project' });
+ expect(findPinnedSection().exists()).toBe(true);
+ });
- it('returns an empty array', () => {
- expect(wrapper.vm.staticItems.map((i) => i.title)).toEqual([]);
- });
- });
+ it('is rendered in a group sidebar', () => {
+ createWrapper({ panelType: 'group' });
+ expect(findPinnedSection().exists()).toBe(true);
});
- describe('nonStaticItems', () => {
- describe('when the sidebar supports pins', () => {
- beforeEach(() => {
- createWrapper({
- ...sidebarData,
- current_menu_items: menuItems,
- panel_type: PANELS_WITH_PINS[0],
- });
- });
+ it('is not rendered in other sidebars', () => {
+ createWrapper({ panelType: 'your_work' });
+ expect(findPinnedSection().exists()).toBe(false);
+ });
+ });
- it('keeps items that have subitems (aka "sections") as non-static', () => {
- expect(wrapper.vm.nonStaticItems.map((i) => i.title)).toEqual([
- 'With subitems',
- 'Also with subitems',
- ]);
+ describe('Non static items section', () => {
+ describe('when the sidebar supports pins', () => {
+ beforeEach(() => {
+ createWrapper({
+ items: menuItems,
+ panelType: PANELS_WITH_PINS[0],
});
});
- describe('when the sidebar does not support pins', () => {
- beforeEach(() => {
- createWrapper({
- ...sidebarData,
- current_menu_items: menuItems,
- panel_type: 'explore',
- });
- });
-
- it('keeps all items as non-static', () => {
- expect(wrapper.vm.nonStaticItems).toEqual(menuItems);
- });
+ it('keeps items that have subitems (aka "sections") as non-static', () => {
+ expect(findNonStaticSectionItems().wrappers.map((w) => w.props('item').title)).toEqual([
+ 'With subitems',
+ 'Also with subitems',
+ ]);
});
});
- describe('pinnedItems', () => {
- describe('when user has no pinned item ids stored', () => {
- beforeEach(() => {
- createWrapper({
- ...sidebarData,
- current_menu_items: menuItems,
- pinned_items: [],
- });
- });
-
- it('returns an empty array', () => {
- expect(wrapper.vm.pinnedItems).toEqual([]);
+ describe('when the sidebar does not support pins', () => {
+ beforeEach(() => {
+ createWrapper({
+ items: menuItems,
+ panelType: 'explore',
});
});
- describe('when user has some pinned item ids stored', () => {
- beforeEach(() => {
- createWrapper({
- ...sidebarData,
- current_menu_items: menuItems,
- pinned_items: [21],
- });
- });
-
- it('returns the items matching the pinned ids', () => {
- expect(wrapper.vm.pinnedItems).toEqual([{ id: 21, title: 'Pinned subitem' }]);
- });
+ it('keeps all items as non-static', () => {
+ expect(findNonStaticSectionItems().length + findNonStaticItems().length).toBe(
+ menuItems.length,
+ );
});
});
});
- describe('Menu separators', () => {
+ describe('Separators', () => {
it('should add the separator above pinned section', () => {
createWrapper({
- ...sidebarData,
- current_menu_items: menuItems,
- panel_type: 'project',
+ items: menuItems,
+ panelType: 'project',
});
expect(findPinnedSection().props('separated')).toBe(true);
});
it('should add the separator above main menu items when there is a pinned section', () => {
createWrapper({
- ...sidebarData,
- current_menu_items: menuItems,
- panel_type: PANELS_WITH_PINS[0],
+ items: menuItems,
+ panelType: PANELS_WITH_PINS[0],
});
expect(findMainMenuSeparator().exists()).toBe(true);
});
it('should NOT add the separator above main menu items when there is no pinned section', () => {
createWrapper({
- ...sidebarData,
- current_menu_items: menuItems,
- panel_type: 'explore',
+ items: menuItems,
+ panelType: 'explore',
});
expect(findMainMenuSeparator().exists()).toBe(false);
});
});
+
+ describe('ARIA attributes', () => {
+ it('adds aria-label attribute to nav element', () => {
+ createWrapper();
+ expect(wrapper.find('nav').attributes('aria-label')).toBe('Main navigation');
+ });
+ });
});
diff --git a/spec/frontend/super_sidebar/components/user_bar_spec.js b/spec/frontend/super_sidebar/components/user_bar_spec.js
index 6878e724c65..ae48c0f2a75 100644
--- a/spec/frontend/super_sidebar/components/user_bar_spec.js
+++ b/spec/frontend/super_sidebar/components/user_bar_spec.js
@@ -5,6 +5,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { __ } from '~/locale';
import CreateMenu from '~/super_sidebar/components/create_menu.vue';
import SearchModal from '~/super_sidebar/components/global_search/components/global_search.vue';
+import BrandLogo from 'jh_else_ce/super_sidebar/components/brand_logo.vue';
import MergeRequestMenu from '~/super_sidebar/components/merge_request_menu.vue';
import Counter from '~/super_sidebar/components/counter.vue';
import UserBar from '~/super_sidebar/components/user_bar.vue';
@@ -23,7 +24,7 @@ describe('UserBar component', () => {
const findMRsCounter = () => findCounter(1);
const findTodosCounter = () => findCounter(2);
const findMergeRequestMenu = () => wrapper.findComponent(MergeRequestMenu);
- const findBrandLogo = () => wrapper.findByTestId('brand-header-custom-logo');
+ const findBrandLogo = () => wrapper.findComponent(BrandLogo);
const findCollapseButton = () => wrapper.findByTestId('super-sidebar-collapse-button');
const findSearchButton = () => wrapper.findByTestId('super-sidebar-search-button');
const findSearchModal = () => wrapper.findComponent(SearchModal);
@@ -47,7 +48,6 @@ describe('UserBar component', () => {
sidebarData: { ...sidebarData, ...extraSidebarData },
},
provide: {
- rootPath: '/',
toggleNewNavEndpoint: '/-/profile/preferences',
isImpersonating: false,
...provideOverrides,
@@ -116,7 +116,7 @@ describe('UserBar component', () => {
it('renders branding logo', () => {
expect(findBrandLogo().exists()).toBe(true);
- expect(findBrandLogo().attributes('src')).toBe(sidebarData.logo_url);
+ expect(findBrandLogo().props('logoUrl')).toBe(sidebarData.logo_url);
});
it('does not render the "Stop impersonating" button', () => {
diff --git a/spec/frontend/super_sidebar/components/user_menu_spec.js b/spec/frontend/super_sidebar/components/user_menu_spec.js
index cf8f650ec8f..f0f18ca9185 100644
--- a/spec/frontend/super_sidebar/components/user_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/user_menu_spec.js
@@ -1,5 +1,6 @@
import { GlAvatar, GlDisclosureDropdown } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { stubComponent } from 'helpers/stub_component';
import UserMenu from '~/super_sidebar/components/user_menu.vue';
import UserNameGroup from '~/super_sidebar/components/user_name_group.vue';
import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
@@ -17,7 +18,9 @@ describe('UserMenu component', () => {
const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
const showDropdown = () => findDropdown().vm.$emit('shown');
- const createWrapper = (userDataChanges = {}) => {
+ const closeDropdownSpy = jest.fn();
+
+ const createWrapper = (userDataChanges = {}, stubs = {}) => {
wrapper = mountExtended(UserMenu, {
propsData: {
data: {
@@ -28,6 +31,7 @@ describe('UserMenu component', () => {
stubs: {
GlEmoji,
GlAvatar: true,
+ ...stubs,
},
provide: {
toggleNewNavEndpoint,
@@ -37,11 +41,12 @@ describe('UserMenu component', () => {
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
};
- it('passes popper options to the dropdown', () => {
+ it('passes custom offset to the dropdown', () => {
createWrapper();
- expect(findDropdown().props('popperOptions')).toEqual({
- modifiers: [{ name: 'offset', options: { offset: [-211, 4] } }],
+ expect(findDropdown().props('dropdownOffset')).toEqual({
+ crossAxis: -211,
+ mainAxis: 4,
});
});
@@ -79,8 +84,8 @@ describe('UserMenu component', () => {
describe('User status item', () => {
let item;
- const setItem = ({ can_update, busy, customized } = {}) => {
- createWrapper({ status: { ...userMenuMockStatus, can_update, busy, customized } });
+ const setItem = ({ can_update, busy, customized, stubs } = {}) => {
+ createWrapper({ status: { ...userMenuMockStatus, can_update, busy, customized } }, stubs);
item = wrapper.findByTestId('status-item');
};
@@ -103,11 +108,19 @@ describe('UserMenu component', () => {
});
it('should close the dropdown when status modal opened', () => {
- setItem({ can_update: true });
- wrapper.vm.$refs.userDropdown.close = jest.fn();
- expect(wrapper.vm.$refs.userDropdown.close).not.toHaveBeenCalled();
+ setItem({
+ can_update: true,
+ stubs: {
+ GlDisclosureDropdown: stubComponent(GlDisclosureDropdown, {
+ methods: {
+ close: closeDropdownSpy,
+ },
+ }),
+ },
+ });
+ expect(closeDropdownSpy).not.toHaveBeenCalled();
item.vm.$emit('action');
- expect(wrapper.vm.$refs.userDropdown.close).toHaveBeenCalled();
+ expect(closeDropdownSpy).toHaveBeenCalled();
});
describe('renders correct label', () => {
diff --git a/spec/frontend/super_sidebar/super_sidebar_collapsed_state_manager_spec.js b/spec/frontend/super_sidebar/super_sidebar_collapsed_state_manager_spec.js
index 909f4249e28..771d1f07fea 100644
--- a/spec/frontend/super_sidebar/super_sidebar_collapsed_state_manager_spec.js
+++ b/spec/frontend/super_sidebar/super_sidebar_collapsed_state_manager_spec.js
@@ -42,22 +42,19 @@ describe('Super Sidebar Collapsed State Manager', () => {
describe('toggleSuperSidebarCollapsed', () => {
it.each`
- collapsed | saveCookie | windowWidth | hasClass | superSidebarPeek | isPeekable
- ${true} | ${true} | ${xl} | ${true} | ${false} | ${false}
- ${true} | ${true} | ${xl} | ${true} | ${true} | ${true}
- ${true} | ${false} | ${xl} | ${true} | ${false} | ${false}
- ${true} | ${true} | ${sm} | ${true} | ${false} | ${false}
- ${true} | ${false} | ${sm} | ${true} | ${false} | ${false}
- ${false} | ${true} | ${xl} | ${false} | ${false} | ${false}
- ${false} | ${true} | ${xl} | ${false} | ${true} | ${false}
- ${false} | ${false} | ${xl} | ${false} | ${false} | ${false}
- ${false} | ${true} | ${sm} | ${false} | ${false} | ${false}
- ${false} | ${false} | ${sm} | ${false} | ${false} | ${false}
+ collapsed | saveCookie | windowWidth | hasClass | isPeekable
+ ${true} | ${true} | ${xl} | ${true} | ${true}
+ ${true} | ${false} | ${xl} | ${true} | ${true}
+ ${true} | ${true} | ${sm} | ${true} | ${true}
+ ${true} | ${false} | ${sm} | ${true} | ${true}
+ ${false} | ${true} | ${xl} | ${false} | ${false}
+ ${false} | ${false} | ${xl} | ${false} | ${false}
+ ${false} | ${true} | ${sm} | ${false} | ${false}
+ ${false} | ${false} | ${sm} | ${false} | ${false}
`(
'when collapsed is $collapsed, saveCookie is $saveCookie, and windowWidth is $windowWidth then page class contains `page-with-super-sidebar-collapsed` is $hasClass',
- ({ collapsed, saveCookie, windowWidth, hasClass, superSidebarPeek, isPeekable }) => {
+ ({ collapsed, saveCookie, windowWidth, hasClass, isPeekable }) => {
jest.spyOn(bp, 'windowWidth').mockReturnValue(windowWidth);
- gon.features = { superSidebarPeek };
toggleSuperSidebarCollapsed(collapsed, saveCookie);