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/nav')
-rw-r--r--spec/frontend/nav/components/new_nav_toggle_spec.js214
-rw-r--r--spec/frontend/nav/components/responsive_app_spec.js122
-rw-r--r--spec/frontend/nav/components/responsive_header_spec.js63
-rw-r--r--spec/frontend/nav/components/responsive_home_spec.js133
-rw-r--r--spec/frontend/nav/components/top_nav_app_spec.js68
-rw-r--r--spec/frontend/nav/components/top_nav_container_view_spec.js120
-rw-r--r--spec/frontend/nav/components/top_nav_dropdown_menu_spec.js146
-rw-r--r--spec/frontend/nav/components/top_nav_menu_item_spec.js145
-rw-r--r--spec/frontend/nav/components/top_nav_menu_sections_spec.js138
-rw-r--r--spec/frontend/nav/components/top_nav_new_dropdown_spec.js142
-rw-r--r--spec/frontend/nav/mock_data.js39
11 files changed, 0 insertions, 1330 deletions
diff --git a/spec/frontend/nav/components/new_nav_toggle_spec.js b/spec/frontend/nav/components/new_nav_toggle_spec.js
deleted file mode 100644
index cf8e59d6522..00000000000
--- a/spec/frontend/nav/components/new_nav_toggle_spec.js
+++ /dev/null
@@ -1,214 +0,0 @@
-import { mount, createWrapper } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import { getByText as getByTextHelper } from '@testing-library/dom';
-import { GlDisclosureDropdownItem, GlToggle } from '@gitlab/ui';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
-import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/alert';
-import { s__ } from '~/locale';
-import { mockTracking } from 'helpers/tracking_helper';
-
-jest.mock('~/alert');
-
-const TEST_ENDPONT = 'https://example.com/toggle';
-
-describe('NewNavToggle', () => {
- useMockLocationHelper();
-
- let wrapper;
- let trackingSpy;
-
- const findToggle = () => wrapper.findComponent(GlToggle);
- const findDisclosureItem = () => wrapper.findComponent(GlDisclosureDropdownItem);
-
- const createComponent = (propsData = { enabled: false }) => {
- wrapper = mount(NewNavToggle, {
- propsData: {
- endpoint: TEST_ENDPONT,
- ...propsData,
- },
- });
-
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- };
-
- const getByText = (text, options) =>
- createWrapper(getByTextHelper(wrapper.element, text, options));
-
- describe('When rendered in scope of the new navigation', () => {
- it('renders the disclosure item', () => {
- createComponent({ newNavigation: true, enabled: true });
- expect(findDisclosureItem().exists()).toBe(true);
- });
-
- describe('when user preference is enabled', () => {
- beforeEach(() => {
- createComponent({ newNavigation: true, enabled: true });
- });
-
- it('renders the toggle as enabled', () => {
- expect(findToggle().props('value')).toBe(true);
- });
- });
-
- describe('when user preference is disabled', () => {
- beforeEach(() => {
- createComponent({ enabled: false });
- });
-
- it('renders the toggle as disabled', () => {
- expect(findToggle().props('value')).toBe(false);
- });
- });
-
- describe.each`
- desc | actFn | toggleValue | trackingLabel | trackingProperty
- ${'when toggle button is clicked'} | ${() => findToggle().trigger('click')} | ${false} | ${'enable_new_nav_beta'} | ${'navigation_top'}
- ${'when menu item text is clicked'} | ${() => getByText('New navigation').trigger('click')} | ${false} | ${'enable_new_nav_beta'} | ${'navigation_top'}
- ${'when toggle button is clicked'} | ${() => findToggle().trigger('click')} | ${true} | ${'disable_new_nav_beta'} | ${'nav_user_menu'}
- ${'when menu item text is clicked'} | ${() => getByText('New navigation').trigger('click')} | ${true} | ${'disable_new_nav_beta'} | ${'nav_user_menu'}
- `('$desc', ({ actFn, toggleValue, trackingLabel, trackingProperty }) => {
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- createComponent({ enabled: toggleValue });
- });
-
- it('reloads the page on success', async () => {
- mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_OK);
-
- actFn();
- await waitForPromises();
-
- expect(window.location.reload).toHaveBeenCalled();
- });
-
- it('shows an alert on error', async () => {
- mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
-
- actFn();
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith(
- expect.objectContaining({
- message: s__(
- 'NorthstarNavigation|Could not update the new navigation preference. Please try again later.',
- ),
- }),
- );
- expect(window.location.reload).not.toHaveBeenCalled();
- });
-
- it('changes the toggle', async () => {
- await actFn();
-
- expect(findToggle().props('value')).toBe(!toggleValue);
- });
-
- it('tracks the Snowplow event', async () => {
- mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_OK);
- await actFn();
- await waitForPromises();
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_toggle', {
- label: trackingLabel,
- property: trackingProperty,
- });
- });
-
- afterEach(() => {
- mock.restore();
- });
- });
- });
-
- describe('When rendered in scope of the current navigation', () => {
- it('renders its title', () => {
- createComponent();
- expect(getByText('Navigation redesign').exists()).toBe(true);
- });
-
- describe('when user preference is enabled', () => {
- beforeEach(() => {
- createComponent({ enabled: true });
- });
-
- it('renders the toggle as enabled', () => {
- expect(findToggle().props('value')).toBe(true);
- });
- });
-
- describe('when user preference is disabled', () => {
- beforeEach(() => {
- createComponent({ enabled: false });
- });
-
- it('renders the toggle as disabled', () => {
- expect(findToggle().props('value')).toBe(false);
- });
- });
-
- describe.each`
- desc | actFn | toggleValue | trackingLabel | trackingProperty
- ${'when toggle button is clicked'} | ${() => findToggle().trigger('click')} | ${false} | ${'enable_new_nav_beta'} | ${'navigation_top'}
- ${'when menu item text is clicked'} | ${() => getByText('New navigation').trigger('click')} | ${false} | ${'enable_new_nav_beta'} | ${'navigation_top'}
- ${'when toggle button is clicked'} | ${() => findToggle().trigger('click')} | ${true} | ${'disable_new_nav_beta'} | ${'nav_user_menu'}
- ${'when menu item text is clicked'} | ${() => getByText('New navigation').trigger('click')} | ${true} | ${'disable_new_nav_beta'} | ${'nav_user_menu'}
- `('$desc', ({ actFn, toggleValue, trackingLabel, trackingProperty }) => {
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- createComponent({ enabled: toggleValue });
- });
-
- it('reloads the page on success', async () => {
- mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_OK);
-
- actFn();
- await waitForPromises();
-
- expect(window.location.reload).toHaveBeenCalled();
- });
-
- it('shows an alert on error', async () => {
- mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
-
- actFn();
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith(
- expect.objectContaining({
- message: s__(
- 'NorthstarNavigation|Could not update the new navigation preference. Please try again later.',
- ),
- }),
- );
- expect(window.location.reload).not.toHaveBeenCalled();
- });
-
- it('changes the toggle', async () => {
- await actFn();
-
- expect(findToggle().props('value')).toBe(!toggleValue);
- });
-
- it('tracks the Snowplow event', async () => {
- mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_OK);
- await actFn();
- await waitForPromises();
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_toggle', {
- label: trackingLabel,
- property: trackingProperty,
- });
- });
-
- afterEach(() => {
- mock.restore();
- });
- });
- });
-});
diff --git a/spec/frontend/nav/components/responsive_app_spec.js b/spec/frontend/nav/components/responsive_app_spec.js
deleted file mode 100644
index 9d3b43520ec..00000000000
--- a/spec/frontend/nav/components/responsive_app_spec.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import ResponsiveApp from '~/nav/components/responsive_app.vue';
-import ResponsiveHeader from '~/nav/components/responsive_header.vue';
-import ResponsiveHome from '~/nav/components/responsive_home.vue';
-import TopNavContainerView from '~/nav/components/top_nav_container_view.vue';
-import { resetMenuItemsActive } from '~/nav/utils/reset_menu_items_active';
-import KeepAliveSlots from '~/vue_shared/components/keep_alive_slots.vue';
-import { TEST_NAV_DATA } from '../mock_data';
-
-describe('~/nav/components/responsive_app.vue', () => {
- let wrapper;
-
- const createComponent = () => {
- wrapper = shallowMount(ResponsiveApp, {
- propsData: {
- navData: TEST_NAV_DATA,
- },
- stubs: {
- KeepAliveSlots,
- },
- });
- };
- const findHome = () => wrapper.findComponent(ResponsiveHome);
- const findMobileOverlay = () => wrapper.find('[data-testid="mobile-overlay"]');
- const findSubviewHeader = () => wrapper.findComponent(ResponsiveHeader);
- const findSubviewContainer = () => wrapper.findComponent(TopNavContainerView);
- const hasMobileOverlayVisible = () => findMobileOverlay().classes('mobile-nav-open');
-
- beforeEach(() => {
- document.body.innerHTML = '';
- // Add test class to reset state + assert that we're adding classes correctly
- document.body.className = 'test-class';
- });
-
- describe('default', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('shows home by default', () => {
- expect(findHome().isVisible()).toBe(true);
- expect(findHome().props()).toEqual({
- navData: resetMenuItemsActive(TEST_NAV_DATA),
- });
- });
-
- it.each`
- events | expectation
- ${[]} | ${false}
- ${['bv::dropdown::show']} | ${true}
- ${['bv::dropdown::show', 'bv::dropdown::hide']} | ${false}
- `(
- 'with root events $events, movile overlay visible = $expectation',
- async ({ events, expectation }) => {
- // `await...reduce(async` is like doing an `forEach(async (...))` excpet it works
- await events.reduce(async (acc, evt) => {
- await acc;
-
- wrapper.vm.$root.$emit(evt);
-
- await nextTick();
- }, Promise.resolve());
-
- expect(hasMobileOverlayVisible()).toBe(expectation);
- },
- );
- });
-
- const projectsContainerProps = {
- containerClass: 'gl-px-3',
- frequentItemsDropdownType: ResponsiveApp.FREQUENT_ITEMS_PROJECTS.namespace,
- frequentItemsVuexModule: ResponsiveApp.FREQUENT_ITEMS_PROJECTS.vuexModule,
- currentItem: {},
- linksPrimary: TEST_NAV_DATA.views.projects.linksPrimary,
- linksSecondary: TEST_NAV_DATA.views.projects.linksSecondary,
- };
- const groupsContainerProps = {
- containerClass: 'gl-px-3',
- frequentItemsDropdownType: ResponsiveApp.FREQUENT_ITEMS_GROUPS.namespace,
- frequentItemsVuexModule: ResponsiveApp.FREQUENT_ITEMS_GROUPS.vuexModule,
- currentItem: {},
- linksPrimary: TEST_NAV_DATA.views.groups.linksPrimary,
- linksSecondary: TEST_NAV_DATA.views.groups.linksSecondary,
- };
-
- describe.each`
- view | header | containerProps
- ${'projects'} | ${'Projects'} | ${projectsContainerProps}
- ${'groups'} | ${'Groups'} | ${groupsContainerProps}
- `('when menu item with $view is clicked', ({ view, header, containerProps }) => {
- beforeEach(async () => {
- createComponent();
-
- findHome().vm.$emit('menu-item-click', { view });
-
- await nextTick();
- });
-
- it('shows header', () => {
- expect(findSubviewHeader().text()).toBe(header);
- });
-
- it('shows container subview', () => {
- expect(findSubviewContainer().props()).toEqual(containerProps);
- });
-
- it('hides home', () => {
- expect(findHome().isVisible()).toBe(false);
- });
-
- describe('when header back button is clicked', () => {
- beforeEach(() => {
- findSubviewHeader().vm.$emit('menu-item-click', { view: 'home' });
- });
-
- it('shows home', () => {
- expect(findHome().isVisible()).toBe(true);
- });
- });
- });
-});
diff --git a/spec/frontend/nav/components/responsive_header_spec.js b/spec/frontend/nav/components/responsive_header_spec.js
deleted file mode 100644
index 2514035270a..00000000000
--- a/spec/frontend/nav/components/responsive_header_spec.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import ResponsiveHeader from '~/nav/components/responsive_header.vue';
-import TopNavMenuItem from '~/nav/components/top_nav_menu_item.vue';
-
-const TEST_SLOT_CONTENT = 'Test slot content';
-
-describe('~/nav/components/top_nav_menu_sections.vue', () => {
- let wrapper;
-
- const createComponent = () => {
- wrapper = shallowMount(ResponsiveHeader, {
- slots: {
- default: TEST_SLOT_CONTENT,
- },
- directives: {
- GlTooltip: createMockDirective('gl-tooltip'),
- },
- });
- };
-
- const findMenuItem = () => wrapper.findComponent(TopNavMenuItem);
-
- beforeEach(() => {
- createComponent();
- });
-
- it('renders slot', () => {
- expect(wrapper.text()).toBe(TEST_SLOT_CONTENT);
- });
-
- it('renders back button', () => {
- const button = findMenuItem();
-
- const tooltip = getBinding(button.element, 'gl-tooltip').value.title;
-
- expect(tooltip).toBe('Go back');
- expect(button.props()).toEqual({
- menuItem: {
- id: 'home',
- view: 'home',
- icon: 'chevron-lg-left',
- },
- iconOnly: true,
- });
- });
-
- it('emits nothing', () => {
- expect(wrapper.emitted()).toEqual({});
- });
-
- describe('when back button is clicked', () => {
- beforeEach(() => {
- findMenuItem().vm.$emit('click');
- });
-
- it('emits menu-item-click', () => {
- expect(wrapper.emitted()).toEqual({
- 'menu-item-click': [[{ id: 'home', view: 'home', icon: 'chevron-lg-left' }]],
- });
- });
- });
-});
diff --git a/spec/frontend/nav/components/responsive_home_spec.js b/spec/frontend/nav/components/responsive_home_spec.js
deleted file mode 100644
index 5a5cfc93607..00000000000
--- a/spec/frontend/nav/components/responsive_home_spec.js
+++ /dev/null
@@ -1,133 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import ResponsiveHome from '~/nav/components/responsive_home.vue';
-import TopNavMenuItem from '~/nav/components/top_nav_menu_item.vue';
-import TopNavMenuSections from '~/nav/components/top_nav_menu_sections.vue';
-import TopNavNewDropdown from '~/nav/components/top_nav_new_dropdown.vue';
-import { TEST_NAV_DATA } from '../mock_data';
-
-const TEST_SEARCH_MENU_ITEM = {
- id: 'search',
- title: 'search',
- icon: 'search',
- href: '/search',
-};
-
-const TEST_NEW_DROPDOWN_VIEW_MODEL = {
- title: 'new',
- menu_sections: [],
-};
-
-describe('~/nav/components/responsive_home.vue', () => {
- let wrapper;
- let menuItemClickListener;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(ResponsiveHome, {
- propsData: {
- navData: TEST_NAV_DATA,
- ...props,
- },
- directives: {
- GlTooltip: createMockDirective('gl-tooltip'),
- },
- listeners: {
- 'menu-item-click': menuItemClickListener,
- },
- });
- };
-
- const findSearchMenuItem = () => wrapper.findComponent(TopNavMenuItem);
- const findNewDropdown = () => wrapper.findComponent(TopNavNewDropdown);
- const findMenuSections = () => wrapper.findComponent(TopNavMenuSections);
-
- beforeEach(() => {
- menuItemClickListener = jest.fn();
- });
-
- describe('default', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it.each`
- desc | fn
- ${'does not show search menu item'} | ${findSearchMenuItem}
- ${'does not show new dropdown'} | ${findNewDropdown}
- `('$desc', ({ fn }) => {
- expect(fn().exists()).toBe(false);
- });
-
- it('shows menu sections', () => {
- expect(findMenuSections().props('sections')).toEqual([
- { id: 'primary', menuItems: TEST_NAV_DATA.primary },
- { id: 'secondary', menuItems: TEST_NAV_DATA.secondary },
- ]);
- });
-
- it('emits when menu sections emits', () => {
- expect(menuItemClickListener).not.toHaveBeenCalled();
-
- findMenuSections().vm.$emit('menu-item-click', TEST_NAV_DATA.primary[0]);
-
- expect(menuItemClickListener).toHaveBeenCalledWith(TEST_NAV_DATA.primary[0]);
- });
- });
-
- describe('without secondary', () => {
- beforeEach(() => {
- createComponent({ navData: { ...TEST_NAV_DATA, secondary: null } });
- });
-
- it('shows menu sections', () => {
- expect(findMenuSections().props('sections')).toEqual([
- { id: 'primary', menuItems: TEST_NAV_DATA.primary },
- ]);
- });
- });
-
- describe('with search view', () => {
- beforeEach(() => {
- createComponent({
- navData: {
- ...TEST_NAV_DATA,
- views: { search: TEST_SEARCH_MENU_ITEM },
- },
- });
- });
-
- it('shows search menu item', () => {
- expect(findSearchMenuItem().props()).toEqual({
- menuItem: TEST_SEARCH_MENU_ITEM,
- iconOnly: true,
- });
- });
-
- it('shows tooltip for search', () => {
- const tooltip = getBinding(findSearchMenuItem().element, 'gl-tooltip');
- expect(tooltip.value).toEqual({ title: TEST_SEARCH_MENU_ITEM.title });
- });
- });
-
- describe('with new view', () => {
- beforeEach(() => {
- createComponent({
- navData: {
- ...TEST_NAV_DATA,
- views: { new: TEST_NEW_DROPDOWN_VIEW_MODEL },
- },
- });
- });
-
- it('shows new dropdown', () => {
- expect(findNewDropdown().props()).toEqual({
- viewModel: TEST_NEW_DROPDOWN_VIEW_MODEL,
- });
- });
-
- it('shows tooltip for new dropdown', () => {
- const tooltip = getBinding(findNewDropdown().element, 'gl-tooltip');
- expect(tooltip.value).toEqual({ title: TEST_NEW_DROPDOWN_VIEW_MODEL.title });
- });
- });
-});
diff --git a/spec/frontend/nav/components/top_nav_app_spec.js b/spec/frontend/nav/components/top_nav_app_spec.js
deleted file mode 100644
index 7f39552eb42..00000000000
--- a/spec/frontend/nav/components/top_nav_app_spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import { GlNavItemDropdown } from '@gitlab/ui';
-import { mount, shallowMount } from '@vue/test-utils';
-import { mockTracking } from 'helpers/tracking_helper';
-import TopNavApp from '~/nav/components/top_nav_app.vue';
-import TopNavDropdownMenu from '~/nav/components/top_nav_dropdown_menu.vue';
-import { TEST_NAV_DATA } from '../mock_data';
-
-describe('~/nav/components/top_nav_app.vue', () => {
- let wrapper;
-
- const createComponent = () => {
- wrapper = mount(TopNavApp, {
- propsData: {
- navData: TEST_NAV_DATA,
- },
- });
- };
-
- const createComponentShallow = () => {
- wrapper = shallowMount(TopNavApp, {
- propsData: {
- navData: TEST_NAV_DATA,
- },
- });
- };
-
- const findNavItemDropdown = () => wrapper.findComponent(GlNavItemDropdown);
- const findNavItemDropdowToggle = () => findNavItemDropdown().find('.js-top-nav-dropdown-toggle');
- const findMenu = () => wrapper.findComponent(TopNavDropdownMenu);
-
- describe('default', () => {
- beforeEach(() => {
- createComponentShallow();
- });
-
- it('renders nav item dropdown', () => {
- expect(findNavItemDropdown().attributes('href')).toBeUndefined();
- expect(findNavItemDropdown().attributes()).toMatchObject({
- icon: '',
- text: '',
- 'no-flip': '',
- 'no-caret': '',
- });
- });
-
- it('renders top nav dropdown menu', () => {
- expect(findMenu().props()).toStrictEqual({
- primary: TEST_NAV_DATA.primary,
- secondary: TEST_NAV_DATA.secondary,
- views: TEST_NAV_DATA.views,
- });
- });
- });
-
- describe('tracking', () => {
- it('emits a tracking event when the toggle is clicked', () => {
- const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- createComponent();
-
- findNavItemDropdowToggle().trigger('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_nav', {
- label: 'hamburger_menu',
- property: 'navigation_top',
- });
- });
- });
-});
diff --git a/spec/frontend/nav/components/top_nav_container_view_spec.js b/spec/frontend/nav/components/top_nav_container_view_spec.js
deleted file mode 100644
index 388ac243648..00000000000
--- a/spec/frontend/nav/components/top_nav_container_view_spec.js
+++ /dev/null
@@ -1,120 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { merge } from 'lodash';
-import { nextTick } from 'vue';
-import FrequentItemsApp from '~/frequent_items/components/app.vue';
-import { FREQUENT_ITEMS_PROJECTS } from '~/frequent_items/constants';
-import eventHub from '~/frequent_items/event_hub';
-import TopNavContainerView from '~/nav/components/top_nav_container_view.vue';
-import TopNavMenuSections from '~/nav/components/top_nav_menu_sections.vue';
-import VuexModuleProvider from '~/vue_shared/components/vuex_module_provider.vue';
-import { TEST_NAV_DATA } from '../mock_data';
-
-const DEFAULT_PROPS = {
- frequentItemsDropdownType: FREQUENT_ITEMS_PROJECTS.namespace,
- frequentItemsVuexModule: FREQUENT_ITEMS_PROJECTS.vuexModule,
- linksPrimary: TEST_NAV_DATA.primary,
- linksSecondary: TEST_NAV_DATA.secondary,
- containerClass: 'test-frequent-items-container-class',
-};
-const TEST_OTHER_PROPS = {
- namespace: 'projects',
- currentUserName: 'test-user',
- currentItem: { id: 'test' },
-};
-
-describe('~/nav/components/top_nav_container_view.vue', () => {
- let wrapper;
-
- const createComponent = (props = {}, options = {}) => {
- wrapper = shallowMount(TopNavContainerView, {
- propsData: {
- ...DEFAULT_PROPS,
- ...TEST_OTHER_PROPS,
- ...props,
- },
- ...options,
- });
- };
-
- const findMenuSections = () => wrapper.findComponent(TopNavMenuSections);
- const findFrequentItemsApp = () => {
- const parent = wrapper.findComponent(VuexModuleProvider);
-
- return {
- vuexModule: parent.props('vuexModule'),
- props: parent.findComponent(FrequentItemsApp).props(),
- attributes: parent.findComponent(FrequentItemsApp).attributes(),
- };
- };
- const findFrequentItemsContainer = () => wrapper.find('[data-testid="frequent-items-container"]');
-
- it.each(['projects', 'groups'])(
- 'emits frequent items event to event hub (%s)',
- async (frequentItemsDropdownType) => {
- const listener = jest.fn();
- eventHub.$on(`${frequentItemsDropdownType}-dropdownOpen`, listener);
- createComponent({ frequentItemsDropdownType });
-
- expect(listener).not.toHaveBeenCalled();
-
- await nextTick();
-
- expect(listener).toHaveBeenCalled();
- },
- );
-
- describe('default', () => {
- const EXTRA_ATTRS = { 'data-test-attribute': 'foo' };
-
- beforeEach(() => {
- createComponent({}, { attrs: EXTRA_ATTRS });
- });
-
- it('does not inherit extra attrs', () => {
- expect(wrapper.attributes()).toEqual({
- class: expect.any(String),
- });
- });
-
- it('renders frequent items app', () => {
- expect(findFrequentItemsApp()).toEqual({
- vuexModule: DEFAULT_PROPS.frequentItemsVuexModule,
- props: expect.objectContaining(
- merge({ currentItem: { lastAccessedOn: Date.now() } }, TEST_OTHER_PROPS),
- ),
- attributes: expect.objectContaining(EXTRA_ATTRS),
- });
- });
-
- it('renders given container class', () => {
- expect(findFrequentItemsContainer().classes(DEFAULT_PROPS.containerClass)).toBe(true);
- });
-
- it('renders menu sections', () => {
- const sections = [
- { id: 'primary', menuItems: TEST_NAV_DATA.primary },
- { id: 'secondary', menuItems: TEST_NAV_DATA.secondary },
- ];
-
- expect(findMenuSections().props()).toEqual({
- sections,
- withTopBorder: true,
- isPrimarySection: false,
- });
- });
- });
-
- describe('without secondary links', () => {
- beforeEach(() => {
- createComponent({
- linksSecondary: [],
- });
- });
-
- it('renders one menu item group', () => {
- expect(findMenuSections().props('sections')).toEqual([
- { id: 'primary', menuItems: TEST_NAV_DATA.primary },
- ]);
- });
- });
-});
diff --git a/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js b/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
deleted file mode 100644
index 1d516240306..00000000000
--- a/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
+++ /dev/null
@@ -1,146 +0,0 @@
-import { shallowMount, mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import TopNavDropdownMenu from '~/nav/components/top_nav_dropdown_menu.vue';
-import TopNavMenuItem from '~/nav/components/top_nav_menu_item.vue';
-import TopNavMenuSections from '~/nav/components/top_nav_menu_sections.vue';
-import KeepAliveSlots from '~/vue_shared/components/keep_alive_slots.vue';
-import { TEST_NAV_DATA } from '../mock_data';
-import { stubComponent } from '../../__helpers__/stub_component';
-
-describe('~/nav/components/top_nav_dropdown_menu.vue', () => {
- let wrapper;
-
- const createComponent = (props = {}, mountFn = shallowMount) => {
- wrapper = mountFn(TopNavDropdownMenu, {
- propsData: {
- primary: TEST_NAV_DATA.primary,
- secondary: TEST_NAV_DATA.secondary,
- views: TEST_NAV_DATA.views,
- ...props,
- },
- stubs: {
- // Stub the keep-alive-slots so we don't render frequent items which uses a store
- KeepAliveSlots: stubComponent(KeepAliveSlots),
- },
- });
- };
-
- const findMenuItems = () => wrapper.findAllComponents(TopNavMenuItem);
- const findMenuSections = () => wrapper.findComponent(TopNavMenuSections);
- const findMenuSidebar = () => wrapper.find('[data-testid="menu-sidebar"]');
- const findMenuSubview = () => wrapper.findComponent(KeepAliveSlots);
- const hasFullWidthMenuSidebar = () => findMenuSidebar().classes('gl-w-full');
-
- const withActiveIndex = (menuItems, activeIndex) =>
- menuItems.map((x, idx) => ({
- ...x,
- active: idx === activeIndex,
- }));
-
- beforeEach(() => {
- jest.spyOn(console, 'error').mockImplementation();
- });
-
- describe('default', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders menu sections', () => {
- expect(findMenuSections().props()).toEqual({
- sections: [
- { id: 'primary', menuItems: TEST_NAV_DATA.primary },
- { id: 'secondary', menuItems: TEST_NAV_DATA.secondary },
- ],
- withTopBorder: false,
- isPrimarySection: true,
- });
- });
-
- it('has full width menu sidebar', () => {
- expect(hasFullWidthMenuSidebar()).toBe(true);
- });
-
- it('renders hidden subview with no slot key', () => {
- const subview = findMenuSubview();
-
- expect(subview.isVisible()).toBe(false);
- expect(subview.props()).toEqual({ slotKey: '' });
- });
- });
-
- describe('with pre-initialized active view', () => {
- beforeEach(() => {
- // We opt for a small integration test, to make sure the event is handled correctly
- // as it would in prod.
- createComponent(
- {
- primary: withActiveIndex(TEST_NAV_DATA.primary, 1),
- },
- mount,
- );
- });
-
- it('renders menu sections', () => {
- expect(findMenuSections().props('sections')).toStrictEqual([
- { id: 'primary', menuItems: withActiveIndex(TEST_NAV_DATA.primary, 1) },
- { id: 'secondary', menuItems: TEST_NAV_DATA.secondary },
- ]);
- });
-
- it('does not have full width menu sidebar', () => {
- expect(hasFullWidthMenuSidebar()).toBe(false);
- });
-
- it('renders visible subview with slot key', () => {
- const subview = findMenuSubview();
-
- expect(subview.isVisible()).toBe(true);
- expect(subview.props('slotKey')).toBe(TEST_NAV_DATA.primary[1].view);
- });
-
- it('does not change view if non-view menu item is clicked', async () => {
- const secondaryLink = findMenuItems().at(TEST_NAV_DATA.primary.length);
-
- // Ensure this doesn't have a view
- expect(secondaryLink.props('menuItem').view).toBeUndefined();
-
- secondaryLink.vm.$emit('click');
-
- await nextTick();
-
- expect(findMenuSubview().props('slotKey')).toBe(TEST_NAV_DATA.primary[1].view);
- });
-
- describe('when menu item is clicked', () => {
- let primaryLink;
-
- beforeEach(async () => {
- primaryLink = findMenuItems().at(0);
- primaryLink.vm.$emit('click');
- await nextTick();
- });
-
- it('clicked on link with view', () => {
- expect(primaryLink.props('menuItem').view).toBe(TEST_NAV_DATA.views.projects.namespace);
- });
-
- it('changes active view', () => {
- expect(findMenuSubview().props('slotKey')).toBe(TEST_NAV_DATA.primary[0].view);
- });
-
- it('changes active status on menu item', () => {
- expect(findMenuSections().props('sections')).toStrictEqual([
- {
- id: 'primary',
- menuItems: withActiveIndex(TEST_NAV_DATA.primary, 0),
- },
- {
- id: 'secondary',
- menuItems: withActiveIndex(TEST_NAV_DATA.secondary, -1),
- },
- ]);
- });
- });
- });
-});
diff --git a/spec/frontend/nav/components/top_nav_menu_item_spec.js b/spec/frontend/nav/components/top_nav_menu_item_spec.js
deleted file mode 100644
index b9cf39b8c1d..00000000000
--- a/spec/frontend/nav/components/top_nav_menu_item_spec.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import { GlButton, GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import TopNavMenuItem from '~/nav/components/top_nav_menu_item.vue';
-
-const TEST_MENU_ITEM = {
- title: 'Cheeseburger',
- icon: 'search',
- href: '/pretty/good/burger',
- view: 'burger-view',
- data: { qa_selector: 'not-a-real-selector', method: 'post', testFoo: 'test' },
-};
-
-describe('~/nav/components/top_nav_menu_item.vue', () => {
- let listener;
- let wrapper;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(TopNavMenuItem, {
- propsData: {
- menuItem: TEST_MENU_ITEM,
- ...props,
- },
- listeners: {
- click: listener,
- },
- });
- };
-
- const findButton = () => wrapper.findComponent(GlButton);
- const findButtonIcons = () =>
- findButton()
- .findAllComponents(GlIcon)
- .wrappers.map((x) => ({
- name: x.props('name'),
- classes: x.classes(),
- }));
-
- beforeEach(() => {
- listener = jest.fn();
- });
-
- describe('default', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders button href and text', () => {
- const button = findButton();
-
- expect(button.attributes('href')).toBe(TEST_MENU_ITEM.href);
- expect(button.text()).toBe(TEST_MENU_ITEM.title);
- });
-
- it('renders button data attributes', () => {
- const button = findButton();
-
- expect(button.attributes()).toMatchObject({
- 'data-qa-selector': TEST_MENU_ITEM.data.qa_selector,
- 'data-method': TEST_MENU_ITEM.data.method,
- 'data-test-foo': TEST_MENU_ITEM.data.testFoo,
- });
- });
-
- it('passes listeners to button', () => {
- expect(listener).not.toHaveBeenCalled();
-
- findButton().vm.$emit('click', 'TEST');
-
- expect(listener).toHaveBeenCalledWith('TEST');
- });
-
- it('renders expected icons', () => {
- expect(findButtonIcons()).toEqual([
- {
- name: TEST_MENU_ITEM.icon,
- classes: ['gl-mr-3!'],
- },
- {
- name: 'chevron-right',
- classes: ['gl-ml-auto'],
- },
- ]);
- });
- });
-
- describe('with icon-only', () => {
- beforeEach(() => {
- createComponent({ iconOnly: true });
- });
-
- it('does not render title or view icon', () => {
- expect(wrapper.text()).toBe('');
- });
-
- it('only renders menuItem icon', () => {
- expect(findButtonIcons()).toEqual([
- {
- name: TEST_MENU_ITEM.icon,
- classes: [],
- },
- ]);
- });
- });
-
- describe.each`
- desc | menuItem | expectedIcons
- ${'with no icon'} | ${{ ...TEST_MENU_ITEM, icon: null }} | ${['chevron-right']}
- ${'with no view'} | ${{ ...TEST_MENU_ITEM, view: null }} | ${[TEST_MENU_ITEM.icon]}
- ${'with no icon or view'} | ${{ ...TEST_MENU_ITEM, view: null, icon: null }} | ${[]}
- `('$desc', ({ menuItem, expectedIcons }) => {
- beforeEach(() => {
- createComponent({ menuItem });
- });
-
- it(`renders expected icons ${JSON.stringify(expectedIcons)}`, () => {
- expect(findButtonIcons().map((x) => x.name)).toEqual(expectedIcons);
- });
- });
-
- describe.each`
- desc | active | cssClass | expectedClasses
- ${'default'} | ${false} | ${''} | ${[]}
- ${'with css class'} | ${false} | ${'test-css-class testing-123'} | ${['test-css-class', 'testing-123']}
- ${'with css class & active'} | ${true} | ${'test-css-class'} | ${['test-css-class', ...TopNavMenuItem.ACTIVE_CLASS.split(' ')]}
- `('$desc', ({ active, cssClass, expectedClasses }) => {
- beforeEach(() => {
- createComponent({
- menuItem: {
- ...TEST_MENU_ITEM,
- active,
- css_class: cssClass,
- },
- });
- });
-
- it('renders expected classes', () => {
- expect(wrapper.classes()).toStrictEqual([
- 'top-nav-menu-item',
- 'gl-display-block',
- 'gl-pr-3!',
- ...expectedClasses,
- ]);
- });
- });
-});
diff --git a/spec/frontend/nav/components/top_nav_menu_sections_spec.js b/spec/frontend/nav/components/top_nav_menu_sections_spec.js
deleted file mode 100644
index 7a3e58fd964..00000000000
--- a/spec/frontend/nav/components/top_nav_menu_sections_spec.js
+++ /dev/null
@@ -1,138 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import TopNavMenuSections from '~/nav/components/top_nav_menu_sections.vue';
-
-const TEST_SECTIONS = [
- {
- id: 'primary',
- menuItems: [
- { type: 'header', title: 'Heading' },
- { type: 'item', id: 'test', href: '/test/href' },
- { type: 'header', title: 'Another Heading' },
- { type: 'item', id: 'foo' },
- { type: 'item', id: 'bar' },
- ],
- },
- {
- id: 'secondary',
- menuItems: [
- { type: 'item', id: 'lorem' },
- { type: 'item', id: 'ipsum' },
- ],
- },
-];
-
-describe('~/nav/components/top_nav_menu_sections.vue', () => {
- let wrapper;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(TopNavMenuSections, {
- propsData: {
- sections: TEST_SECTIONS,
- ...props,
- },
- });
- };
-
- const findMenuItemModels = (parent) =>
- parent.findAll('[data-testid="menu-header"],[data-testid="menu-item"]').wrappers.map((x) => {
- return {
- menuItem: x.vm
- ? {
- type: 'item',
- ...x.props('menuItem'),
- }
- : {
- type: 'header',
- title: x.text(),
- },
- classes: x.classes(),
- };
- });
- const findSectionModels = () =>
- wrapper.findAll('[data-testid="menu-section"]').wrappers.map((x) => ({
- classes: x.classes(),
- menuItems: findMenuItemModels(x),
- }));
-
- describe('default', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders sections with menu items', () => {
- const headerClasses = ['gl-px-4', 'gl-py-2', 'gl-text-gray-900', 'gl-display-block'];
- const itemClasses = ['gl-w-full'];
-
- expect(findSectionModels()).toEqual([
- {
- classes: [],
- menuItems: TEST_SECTIONS[0].menuItems.map((menuItem, index) => {
- const classes = menuItem.type === 'header' ? [...headerClasses] : [...itemClasses];
- if (index > 0) classes.push(menuItem.type === 'header' ? 'gl-pt-3!' : 'gl-mt-1');
- return {
- menuItem,
- classes,
- };
- }),
- },
- {
- classes: [
- ...TopNavMenuSections.BORDER_CLASSES.split(' '),
- 'gl-border-gray-50',
- 'gl-mt-3',
- ],
- menuItems: TEST_SECTIONS[1].menuItems.map((menuItem, index) => {
- const classes = menuItem.type === 'header' ? [...headerClasses] : [...itemClasses];
- if (index > 0) classes.push(menuItem.type === 'header' ? 'gl-pt-3!' : 'gl-mt-1');
- return {
- menuItem,
- classes,
- };
- }),
- },
- ]);
- });
-
- it('when clicked menu item with href, does nothing', () => {
- const menuItem = wrapper.findAll('[data-testid="menu-item"]').at(0);
-
- menuItem.vm.$emit('click');
-
- expect(wrapper.emitted()).toEqual({});
- });
-
- it('when clicked menu item without href, emits "menu-item-click"', () => {
- const menuItem = wrapper.findAll('[data-testid="menu-item"]').at(1);
-
- menuItem.vm.$emit('click');
-
- expect(wrapper.emitted('menu-item-click')).toEqual([[TEST_SECTIONS[0].menuItems[3]]]);
- });
- });
-
- describe('with withTopBorder=true', () => {
- beforeEach(() => {
- createComponent({ withTopBorder: true });
- });
-
- it('renders border classes for top section', () => {
- expect(findSectionModels().map((x) => x.classes)).toEqual([
- [...TopNavMenuSections.BORDER_CLASSES.split(' '), 'gl-border-gray-50'],
- [...TopNavMenuSections.BORDER_CLASSES.split(' '), 'gl-border-gray-50', 'gl-mt-3'],
- ]);
- });
- });
-
- describe('with isPrimarySection=true', () => {
- beforeEach(() => {
- createComponent({ isPrimarySection: true });
- });
-
- it('renders border classes for top section', () => {
- expect(findSectionModels().map((x) => x.classes)).toEqual([
- [],
- [...TopNavMenuSections.BORDER_CLASSES.split(' '), 'gl-border-gray-100', 'gl-mt-3'],
- ]);
- });
- });
-});
diff --git a/spec/frontend/nav/components/top_nav_new_dropdown_spec.js b/spec/frontend/nav/components/top_nav_new_dropdown_spec.js
deleted file mode 100644
index 432ee5e9ecd..00000000000
--- a/spec/frontend/nav/components/top_nav_new_dropdown_spec.js
+++ /dev/null
@@ -1,142 +0,0 @@
-import { GlDropdown } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import TopNavNewDropdown from '~/nav/components/top_nav_new_dropdown.vue';
-import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
-import { TOP_NAV_INVITE_MEMBERS_COMPONENT } from '~/invite_members/constants';
-
-const TEST_VIEW_MODEL = {
- title: 'Dropdown',
- menu_sections: [
- {
- title: 'Section 1',
- menu_items: [
- { id: 'foo-1', title: 'Foo 1', href: '/foo/1' },
- { id: 'foo-2', title: 'Foo 2', href: '/foo/2' },
- { id: 'foo-3', title: 'Foo 3', href: '/foo/3' },
- ],
- },
- {
- title: 'Section 2',
- menu_items: [
- { id: 'bar-1', title: 'Bar 1', href: '/bar/1' },
- { id: 'bar-2', title: 'Bar 2', href: '/bar/2' },
- {
- id: 'invite',
- title: '_invite members title_',
- component: TOP_NAV_INVITE_MEMBERS_COMPONENT,
- icon: '_icon_',
- data: {
- trigger_element: '_trigger_element_',
- trigger_source: '_trigger_source_',
- },
- },
- ],
- },
- ],
-};
-
-describe('~/nav/components/top_nav_menu_sections.vue', () => {
- let wrapper;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(TopNavNewDropdown, {
- propsData: {
- viewModel: TEST_VIEW_MODEL,
- ...props,
- },
- });
- };
-
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findInviteMembersTrigger = () => wrapper.findComponent(InviteMembersTrigger);
- const findDropdownContents = () =>
- findDropdown()
- .findAll('[data-testid]')
- .wrappers.map((child) => {
- const type = child.attributes('data-testid');
-
- if (type === 'divider') {
- return { type };
- }
- if (type === 'header') {
- return { type, text: child.text() };
- }
-
- return {
- type,
- text: child.text(),
- href: child.attributes('href'),
- };
- });
-
- describe('default', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders dropdown parent', () => {
- expect(findDropdown().props()).toMatchObject({
- text: TEST_VIEW_MODEL.title,
- textSrOnly: true,
- icon: 'plus',
- });
- });
-
- it('renders dropdown content', () => {
- const hrefItems = TEST_VIEW_MODEL.menu_sections[1].menu_items.filter((item) =>
- Boolean(item.href),
- );
-
- expect(findDropdownContents()).toEqual([
- {
- type: 'header',
- text: TEST_VIEW_MODEL.menu_sections[0].title,
- },
- ...TEST_VIEW_MODEL.menu_sections[0].menu_items.map(({ title, href }) => ({
- type: 'item',
- href,
- text: title,
- })),
- {
- type: 'divider',
- },
- {
- type: 'header',
- text: TEST_VIEW_MODEL.menu_sections[1].title,
- },
- ...hrefItems.map(({ title, href }) => ({
- type: 'item',
- href,
- text: title,
- })),
- ]);
- expect(findInviteMembersTrigger().props()).toMatchObject({
- displayText: '_invite members title_',
- icon: '_icon_',
- triggerElement: 'dropdown-_trigger_element_',
- triggerSource: '_trigger_source_',
- });
- });
- });
-
- describe('with only 1 section', () => {
- beforeEach(() => {
- createComponent({
- viewModel: {
- ...TEST_VIEW_MODEL,
- menu_sections: TEST_VIEW_MODEL.menu_sections.slice(0, 1),
- },
- });
- });
-
- it('renders dropdown content without headers and dividers', () => {
- expect(findDropdownContents()).toEqual(
- TEST_VIEW_MODEL.menu_sections[0].menu_items.map(({ title, href }) => ({
- type: 'item',
- href,
- text: title,
- })),
- );
- });
- });
-});
diff --git a/spec/frontend/nav/mock_data.js b/spec/frontend/nav/mock_data.js
deleted file mode 100644
index 2052acfe001..00000000000
--- a/spec/frontend/nav/mock_data.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { range } from 'lodash';
-
-export const TEST_NAV_DATA = {
- menuTitle: 'Test Menu Title',
- primary: [
- ...['projects', 'groups'].map((view) => ({
- id: view,
- href: null,
- title: view,
- view,
- })),
- ...range(0, 2).map((idx) => ({
- id: `primary-link-${idx}`,
- href: `/path/to/primary/${idx}`,
- title: `Title ${idx}`,
- })),
- ],
- secondary: range(0, 2).map((idx) => ({
- id: `secondary-link-${idx}`,
- href: `/path/to/secondary/${idx}`,
- title: `SecTitle ${idx}`,
- })),
- views: {
- projects: {
- namespace: 'projects',
- currentUserName: '',
- currentItem: {},
- linksPrimary: [{ id: 'project-link', href: '/path/to/projects', title: 'Project Link' }],
- linksSecondary: [],
- },
- groups: {
- namespace: 'groups',
- currentUserName: '',
- currentItem: {},
- linksPrimary: [],
- linksSecondary: [{ id: 'group-link', href: '/path/to/groups', title: 'Group Link' }],
- },
- },
-};