diff options
Diffstat (limited to 'spec/frontend/super_sidebar')
4 files changed, 182 insertions, 11 deletions
diff --git a/spec/frontend/super_sidebar/components/nav_item_link_spec.js b/spec/frontend/super_sidebar/components/nav_item_link_spec.js new file mode 100644 index 00000000000..5cc1bd01d0f --- /dev/null +++ b/spec/frontend/super_sidebar/components/nav_item_link_spec.js @@ -0,0 +1,37 @@ +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import NavItemLink from '~/super_sidebar/components/nav_item_link.vue'; + +describe('NavItemLink component', () => { + let wrapper; + + const createWrapper = (item) => { + wrapper = shallowMountExtended(NavItemLink, { + propsData: { + item, + }, + }); + }; + + describe('when `item` has `is_active` set to `false`', () => { + it('renders an anchor tag without active CSS class and `aria-current` attribute', () => { + createWrapper({ title: 'foo', link: '/foo', is_active: false }); + + expect(wrapper.attributes()).toEqual({ + href: '/foo', + class: '', + }); + }); + }); + + describe('when `item` has `is_active` set to `true`', () => { + it('renders an anchor tag with active CSS class and `aria-current="page"`', () => { + createWrapper({ title: 'foo', link: '/foo', is_active: true }); + + expect(wrapper.attributes()).toEqual({ + href: '/foo', + class: 'gl-bg-t-gray-a-08', + 'aria-current': 'page', + }); + }); + }); +}); diff --git a/spec/frontend/super_sidebar/components/nav_item_router_link_spec.js b/spec/frontend/super_sidebar/components/nav_item_router_link_spec.js new file mode 100644 index 00000000000..a7ca56325fe --- /dev/null +++ b/spec/frontend/super_sidebar/components/nav_item_router_link_spec.js @@ -0,0 +1,56 @@ +import { RouterLinkStub } from '@vue/test-utils'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import NavItemRouterLink from '~/super_sidebar/components/nav_item_router_link.vue'; + +describe('NavItemRouterLink component', () => { + let wrapper; + + const createWrapper = ({ item, routerLinkSlotProps = {} }) => { + wrapper = mountExtended(NavItemRouterLink, { + propsData: { + item, + }, + stubs: { + RouterLink: { + ...RouterLinkStub, + render() { + const children = this.$scopedSlots.default({ + href: '/foo', + isActive: false, + navigate: jest.fn(), + ...routerLinkSlotProps, + }); + return children; + }, + }, + }, + }); + }; + + describe('when `RouterLink` is not active', () => { + it('renders an anchor tag without active CSS class and `aria-current` attribute', () => { + createWrapper({ item: { title: 'foo', to: { name: 'foo' } } }); + + expect(wrapper.attributes()).toEqual({ + href: '/foo', + custom: '', + }); + }); + }); + + describe('when `RouterLink` is active', () => { + it('renders an anchor tag with active CSS class and `aria-current="page"`', () => { + createWrapper({ + item: { title: 'foo', to: { name: 'foo' } }, + routerLinkSlotProps: { isActive: true }, + }); + + expect(wrapper.findComponent(RouterLinkStub).props('activeClass')).toBe('gl-bg-t-gray-a-08'); + expect(wrapper.attributes()).toEqual({ + href: '/foo', + 'aria-current': 'page', + custom: '', + }); + }); + }); +}); diff --git a/spec/frontend/super_sidebar/components/nav_item_spec.js b/spec/frontend/super_sidebar/components/nav_item_spec.js index 1714a4c3a4e..43b3f14f2f5 100644 --- a/spec/frontend/super_sidebar/components/nav_item_spec.js +++ b/spec/frontend/super_sidebar/components/nav_item_spec.js @@ -1,6 +1,9 @@ import { GlBadge } from '@gitlab/ui'; -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { RouterLinkStub } from '@vue/test-utils'; +import { mountExtended, extendedWrapper } from 'helpers/vue_test_utils_helper'; import NavItem from '~/super_sidebar/components/nav_item.vue'; +import NavItemRouterLink from '~/super_sidebar/components/nav_item_router_link.vue'; +import NavItemLink from '~/super_sidebar/components/nav_item_link.vue'; import { CLICK_MENU_ITEM_ACTION, TRACKING_UNKNOWN_ID, @@ -12,19 +15,36 @@ describe('NavItem component', () => { const findLink = () => wrapper.findByTestId('nav-item-link'); const findPill = () => wrapper.findComponent(GlBadge); - const createWrapper = (item, props = {}, provide = {}) => { - wrapper = shallowMountExtended(NavItem, { + const findNavItemRouterLink = () => extendedWrapper(wrapper.findComponent(NavItemRouterLink)); + const findNavItemLink = () => extendedWrapper(wrapper.findComponent(NavItemLink)); + + const createWrapper = ({ item, props = {}, provide = {}, routerLinkSlotProps = {} }) => { + wrapper = mountExtended(NavItem, { propsData: { item, ...props, }, provide, + stubs: { + RouterLink: { + ...RouterLinkStub, + render() { + const children = this.$scopedSlots.default({ + href: '/foo', + isActive: false, + navigate: jest.fn(), + ...routerLinkSlotProps, + }); + return children; + }, + }, + }, }); }; describe('pills', () => { it.each([0, 5, 3.4, 'foo', '10%'])('item with pill_data `%p` renders a pill', (pillCount) => { - createWrapper({ title: 'Foo', pill_count: pillCount }); + createWrapper({ item: { title: 'Foo', pill_count: pillCount } }); expect(findPill().text()).toEqual(pillCount.toString()); }); @@ -32,7 +52,7 @@ describe('NavItem component', () => { it.each([null, undefined, false, true, '', NaN, Number.POSITIVE_INFINITY])( 'item with pill_data `%p` renders no pill', (pillCount) => { - createWrapper({ title: 'Foo', pill_count: pillCount }); + createWrapper({ item: { title: 'Foo', pill_count: pillCount } }); expect(findPill().exists()).toEqual(false); }, @@ -41,21 +61,21 @@ describe('NavItem component', () => { it('applies custom link classes', () => { const customClass = 'customClass'; - createWrapper( - { title: 'Foo' }, - { + createWrapper({ + item: { title: 'Foo' }, + props: { linkClasses: { [customClass]: true, }, }, - ); + }); expect(findLink().attributes('class')).toContain(customClass); }); it('applies custom classes set in the backend', () => { const customClass = 'customBackendClass'; - createWrapper({ title: 'Foo', link_classes: customClass }); + createWrapper({ item: { title: 'Foo', link_classes: customClass } }); expect(findLink().attributes('class')).toContain(customClass); }); @@ -70,7 +90,7 @@ describe('NavItem component', () => { `( 'adds appropriate data tracking labels for id=$id and panelType=$panelType', ({ id, eventLabel, panelType, eventProperty, eventExtra }) => { - createWrapper({ title: 'Foo', id }, {}, { panelType }); + createWrapper({ item: { title: 'Foo', id }, props: {}, provide: { panelType } }); expect(findLink().attributes('data-track-action')).toBe(CLICK_MENU_ITEM_ACTION); expect(findLink().attributes('data-track-label')).toBe(eventLabel); @@ -79,4 +99,51 @@ describe('NavItem component', () => { }, ); }); + + describe('when `item` prop has `to` attribute', () => { + describe('when `RouterLink` is not active', () => { + it('renders `NavItemRouterLink` with active indicator hidden', () => { + createWrapper({ item: { title: 'Foo', to: { name: 'foo' } } }); + + expect(findNavItemRouterLink().findByTestId('active-indicator').classes()).toContain( + 'gl-bg-transparent', + ); + }); + }); + + describe('when `RouterLink` is active', () => { + it('renders `NavItemRouterLink` with active indicator shown', () => { + createWrapper({ + item: { title: 'Foo', to: { name: 'foo' } }, + routerLinkSlotProps: { isActive: true }, + }); + + expect(findNavItemRouterLink().findByTestId('active-indicator').classes()).toContain( + 'gl-bg-blue-500', + ); + }); + }); + }); + + describe('when `item` prop has `link` attribute', () => { + describe('when `item` has `is_active` set to `false`', () => { + it('renders `NavItemLink` with active indicator hidden', () => { + createWrapper({ item: { title: 'Foo', link: '/foo', is_active: false } }); + + expect(findNavItemLink().findByTestId('active-indicator').classes()).toContain( + 'gl-bg-transparent', + ); + }); + }); + + describe('when `item` has `is_active` set to `true`', () => { + it('renders `NavItemLink` with active indicator shown', () => { + createWrapper({ item: { title: 'Foo', link: '/foo', is_active: true } }); + + expect(findNavItemLink().findByTestId('active-indicator').classes()).toContain( + 'gl-bg-blue-500', + ); + }); + }); + }); }); diff --git a/spec/frontend/super_sidebar/utils_spec.js b/spec/frontend/super_sidebar/utils_spec.js index d2984254dee..8c8673ddbc4 100644 --- a/spec/frontend/super_sidebar/utils_spec.js +++ b/spec/frontend/super_sidebar/utils_spec.js @@ -2,6 +2,7 @@ import { getTopFrequentItems, trackContextAccess, formatContextSwitcherItems, + ariaCurrent, } from '~/super_sidebar/utils'; import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import AccessorUtilities from '~/lib/utils/accessor'; @@ -157,4 +158,14 @@ describe('Super sidebar utils spec', () => { ]); }); }); + + describe('ariaCurrent', () => { + it.each` + isActive | expected + ${true} | ${'page'} + ${false} | ${null} + `('returns `$expected` when `isActive` is `$isActive`', ({ isActive, expected }) => { + expect(ariaCurrent(isActive)).toBe(expected); + }); + }); }); |