diff options
Diffstat (limited to 'spec/frontend/groups')
11 files changed, 223 insertions, 112 deletions
diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js index a6bbea648d2..a4a7530184d 100644 --- a/spec/frontend/groups/components/app_spec.js +++ b/spec/frontend/groups/components/app_spec.js @@ -40,7 +40,7 @@ describe('AppComponent', () => { const store = new GroupsStore({ hideProjects: false }); const service = new GroupsService(mockEndpoint); - const createShallowComponent = ({ propsData = {}, provide = {} } = {}) => { + const createShallowComponent = ({ propsData = {} } = {}) => { store.state.pageInfo = mockPageInfo; wrapper = shallowMount(appComponent, { propsData: { @@ -53,10 +53,6 @@ describe('AppComponent', () => { mocks: { $toast, }, - provide: { - renderEmptyState: false, - ...provide, - }, }); vm = wrapper.vm; }; @@ -402,8 +398,7 @@ describe('AppComponent', () => { ({ action, groups, fromSearch, renderEmptyState, expected }) => { it(expected ? 'renders empty state' : 'does not render empty state', async () => { createShallowComponent({ - propsData: { action }, - provide: { renderEmptyState }, + propsData: { action, renderEmptyState }, }); vm.updateGroups(groups, fromSearch); @@ -420,7 +415,6 @@ describe('AppComponent', () => { it('renders legacy empty state', async () => { createShallowComponent({ propsData: { action: 'subgroups_and_projects' }, - provide: { renderEmptyState: false }, }); vm.updateGroups([], false); @@ -481,7 +475,7 @@ describe('AppComponent', () => { it('should render loading icon', async () => { vm.isLoading = true; await nextTick(); - expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); + expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true); }); it('should render groups tree', async () => { @@ -494,7 +488,7 @@ describe('AppComponent', () => { it('renders modal confirmation dialog', () => { createShallowComponent(); - const findGlModal = wrapper.find(GlModal); + const findGlModal = wrapper.findComponent(GlModal); expect(findGlModal.exists()).toBe(true); expect(findGlModal.attributes('title')).toBe('Are you sure?'); diff --git a/spec/frontend/groups/components/empty_state_spec.js b/spec/frontend/groups/components/empty_state_spec.js index c0e71e814d0..fbeaa32b1ec 100644 --- a/spec/frontend/groups/components/empty_state_spec.js +++ b/spec/frontend/groups/components/empty_state_spec.js @@ -68,7 +68,7 @@ describe('EmptyState', () => { it('renders empty state', () => { createComponent({ provide: { canCreateSubgroups: false, canCreateProjects: false } }); - expect(wrapper.find(GlEmptyState).props()).toMatchObject({ + expect(wrapper.findComponent(GlEmptyState).props()).toMatchObject({ title: EmptyState.i18n.withoutLinks.title, description: EmptyState.i18n.withoutLinks.description, svgPath: defaultProvide.emptySubgroupIllustration, diff --git a/spec/frontend/groups/components/group_item_spec.js b/spec/frontend/groups/components/group_item_spec.js index 9906f62878f..3aa66644c19 100644 --- a/spec/frontend/groups/components/group_item_spec.js +++ b/spec/frontend/groups/components/group_item_spec.js @@ -8,9 +8,9 @@ import { getGroupItemMicrodata } from '~/groups/store/utils'; import * as urlUtilities from '~/lib/utils/url_utility'; import { ITEM_TYPE } from '~/groups/constants'; import { - VISIBILITY_LEVEL_PRIVATE, - VISIBILITY_LEVEL_INTERNAL, - VISIBILITY_LEVEL_PUBLIC, + VISIBILITY_LEVEL_PRIVATE_STRING, + VISIBILITY_LEVEL_INTERNAL_STRING, + VISIBILITY_LEVEL_PUBLIC_STRING, } from '~/visibility_level/constants'; import { helpPagePath } from '~/helpers/help_page_helper'; import { mountExtended, extendedWrapper } from 'helpers/vue_test_utils_helper'; @@ -19,7 +19,7 @@ import { mockParentGroupItem, mockChildren } from '../mock_data'; const createComponent = ( propsData = { group: mockParentGroupItem, parentGroup: mockChildren[0] }, provide = { - currentGroupVisibility: VISIBILITY_LEVEL_PRIVATE, + currentGroupVisibility: VISIBILITY_LEVEL_PRIVATE_STRING, }, ) => { return mountExtended(GroupItem, { @@ -274,7 +274,7 @@ describe('GroupItemComponent', () => { ${'itemscope'} | ${'itemscope'} ${'itemtype'} | ${'https://schema.org/Organization'} ${'itemprop'} | ${'subOrganization'} - `('it does set correct $attr', ({ attr, value } = {}) => { + `('does set correct $attr', ({ attr, value } = {}) => { expect(wrapper.attributes(attr)).toBe(value); }); @@ -283,7 +283,7 @@ describe('GroupItemComponent', () => { ${'img'} | ${'logo'} ${'[data-testid="group-name"]'} | ${'name'} ${'[data-testid="group-description"]'} | ${'description'} - `('it does set correct $selector', ({ selector, propValue } = {}) => { + `('does set correct $selector', ({ selector, propValue } = {}) => { expect(wrapper.find(selector).attributes('itemprop')).toBe(propValue); }); }); @@ -320,16 +320,16 @@ describe('GroupItemComponent', () => { describe('when showing projects', () => { describe.each` - itemVisibility | currentGroupVisibility | isPopoverShown - ${VISIBILITY_LEVEL_PRIVATE} | ${VISIBILITY_LEVEL_PUBLIC} | ${false} - ${VISIBILITY_LEVEL_INTERNAL} | ${VISIBILITY_LEVEL_PUBLIC} | ${false} - ${VISIBILITY_LEVEL_PUBLIC} | ${VISIBILITY_LEVEL_PUBLIC} | ${false} - ${VISIBILITY_LEVEL_PRIVATE} | ${VISIBILITY_LEVEL_PRIVATE} | ${false} - ${VISIBILITY_LEVEL_INTERNAL} | ${VISIBILITY_LEVEL_PRIVATE} | ${true} - ${VISIBILITY_LEVEL_PUBLIC} | ${VISIBILITY_LEVEL_PRIVATE} | ${true} - ${VISIBILITY_LEVEL_PRIVATE} | ${VISIBILITY_LEVEL_INTERNAL} | ${false} - ${VISIBILITY_LEVEL_INTERNAL} | ${VISIBILITY_LEVEL_INTERNAL} | ${false} - ${VISIBILITY_LEVEL_PUBLIC} | ${VISIBILITY_LEVEL_INTERNAL} | ${true} + itemVisibility | currentGroupVisibility | isPopoverShown + ${VISIBILITY_LEVEL_PRIVATE_STRING} | ${VISIBILITY_LEVEL_PUBLIC_STRING} | ${false} + ${VISIBILITY_LEVEL_INTERNAL_STRING} | ${VISIBILITY_LEVEL_PUBLIC_STRING} | ${false} + ${VISIBILITY_LEVEL_PUBLIC_STRING} | ${VISIBILITY_LEVEL_PUBLIC_STRING} | ${false} + ${VISIBILITY_LEVEL_PRIVATE_STRING} | ${VISIBILITY_LEVEL_PRIVATE_STRING} | ${false} + ${VISIBILITY_LEVEL_INTERNAL_STRING} | ${VISIBILITY_LEVEL_PRIVATE_STRING} | ${true} + ${VISIBILITY_LEVEL_PUBLIC_STRING} | ${VISIBILITY_LEVEL_PRIVATE_STRING} | ${true} + ${VISIBILITY_LEVEL_PRIVATE_STRING} | ${VISIBILITY_LEVEL_INTERNAL_STRING} | ${false} + ${VISIBILITY_LEVEL_INTERNAL_STRING} | ${VISIBILITY_LEVEL_INTERNAL_STRING} | ${false} + ${VISIBILITY_LEVEL_PUBLIC_STRING} | ${VISIBILITY_LEVEL_INTERNAL_STRING} | ${true} `( 'when item visibility is $itemVisibility and parent group visibility is $currentGroupVisibility', ({ itemVisibility, currentGroupVisibility, isPopoverShown }) => { @@ -374,7 +374,7 @@ describe('GroupItemComponent', () => { wrapper = createComponent({ group: { ...mockParentGroupItem, - visibility: VISIBILITY_LEVEL_PUBLIC, + visibility: VISIBILITY_LEVEL_PUBLIC_STRING, type: ITEM_TYPE.PROJECT, }, parentGroup: mockChildren[0], diff --git a/spec/frontend/groups/components/groups_spec.js b/spec/frontend/groups/components/groups_spec.js index 6c1eb373b7e..866868eff36 100644 --- a/spec/frontend/groups/components/groups_spec.js +++ b/spec/frontend/groups/components/groups_spec.js @@ -6,7 +6,7 @@ import GroupItemComponent from '~/groups/components/group_item.vue'; import PaginationLinks from '~/vue_shared/components/pagination_links.vue'; import GroupsComponent from '~/groups/components/groups.vue'; import eventHub from '~/groups/event_hub'; -import { VISIBILITY_LEVEL_PRIVATE } from '~/visibility_level/constants'; +import { VISIBILITY_LEVEL_PRIVATE_STRING } from '~/visibility_level/constants'; import { mockGroups, mockPageInfo } from '../mock_data'; describe('GroupsComponent', () => { @@ -26,7 +26,7 @@ describe('GroupsComponent', () => { ...propsData, }, provide: { - currentGroupVisibility: VISIBILITY_LEVEL_PRIVATE, + currentGroupVisibility: VISIBILITY_LEVEL_PRIVATE_STRING, }, }); }; diff --git a/spec/frontend/groups/components/invite_members_banner_spec.js b/spec/frontend/groups/components/invite_members_banner_spec.js index 1924f400861..d25b45bd662 100644 --- a/spec/frontend/groups/components/invite_members_banner_spec.js +++ b/spec/frontend/groups/components/invite_members_banner_spec.js @@ -71,7 +71,7 @@ describe('InviteMembersBanner', () => { describe('when the button is clicked', () => { beforeEach(() => { jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); - wrapper.find(GlBanner).vm.$emit('primary'); + wrapper.findComponent(GlBanner).vm.$emit('primary'); }); it('calls openModal through the eventHub', () => { @@ -92,7 +92,7 @@ describe('InviteMembersBanner', () => { mockAxios.onPost(provide.calloutsPath).replyOnce(200); const dismissEvent = 'invite_members_banner_dismissed'; - wrapper.find(GlBanner).vm.$emit('close'); + wrapper.findComponent(GlBanner).vm.$emit('close'); expect(trackingSpy).toHaveBeenCalledWith(trackCategory, dismissEvent, { label: provide.trackLabel, @@ -102,7 +102,7 @@ describe('InviteMembersBanner', () => { describe('rendering', () => { const findBanner = () => { - return wrapper.find(GlBanner); + return wrapper.findComponent(GlBanner); }; beforeEach(() => { @@ -132,16 +132,16 @@ describe('InviteMembersBanner', () => { }); it('should render the banner when not dismissed', () => { - expect(wrapper.find(GlBanner).exists()).toBe(true); + expect(wrapper.findComponent(GlBanner).exists()).toBe(true); }); it('should close the banner when dismiss is clicked', async () => { mockAxios.onPost(provide.calloutsPath).replyOnce(200); - expect(wrapper.find(GlBanner).exists()).toBe(true); - wrapper.find(GlBanner).vm.$emit('close'); + expect(wrapper.findComponent(GlBanner).exists()).toBe(true); + wrapper.findComponent(GlBanner).vm.$emit('close'); await nextTick(); - expect(wrapper.find(GlBanner).exists()).toBe(false); + expect(wrapper.findComponent(GlBanner).exists()).toBe(false); }); }); }); diff --git a/spec/frontend/groups/components/item_caret_spec.js b/spec/frontend/groups/components/item_caret_spec.js index 4bf92bb5642..2333f04bb2e 100644 --- a/spec/frontend/groups/components/item_caret_spec.js +++ b/spec/frontend/groups/components/item_caret_spec.js @@ -22,8 +22,8 @@ describe('ItemCaret', () => { } }); - const findAllGlIcons = () => wrapper.findAll(GlIcon); - const findGlIcon = () => wrapper.find(GlIcon); + const findAllGlIcons = () => wrapper.findAllComponents(GlIcon); + const findGlIcon = () => wrapper.findComponent(GlIcon); describe('template', () => { it('renders component template correctly', () => { diff --git a/spec/frontend/groups/components/item_stats_spec.js b/spec/frontend/groups/components/item_stats_spec.js index fdc267bc14a..0c2912adc66 100644 --- a/spec/frontend/groups/components/item_stats_spec.js +++ b/spec/frontend/groups/components/item_stats_spec.js @@ -24,7 +24,7 @@ describe('ItemStats', () => { } }); - const findItemStatsValue = () => wrapper.find(ItemStatsValue); + const findItemStatsValue = () => wrapper.findComponent(ItemStatsValue); describe('template', () => { it('renders component container element correctly', () => { diff --git a/spec/frontend/groups/components/item_stats_value_spec.js b/spec/frontend/groups/components/item_stats_value_spec.js index 98186120a81..b9db83c7dd7 100644 --- a/spec/frontend/groups/components/item_stats_value_spec.js +++ b/spec/frontend/groups/components/item_stats_value_spec.js @@ -25,7 +25,7 @@ describe('ItemStatsValue', () => { } }); - const findGlIcon = () => wrapper.find(GlIcon); + const findGlIcon = () => wrapper.findComponent(GlIcon); const findStatValue = () => wrapper.find('[data-testid="itemStatValue"]'); describe('template', () => { diff --git a/spec/frontend/groups/components/item_type_icon_spec.js b/spec/frontend/groups/components/item_type_icon_spec.js index f3652f1a410..aa00e82150b 100644 --- a/spec/frontend/groups/components/item_type_icon_spec.js +++ b/spec/frontend/groups/components/item_type_icon_spec.js @@ -23,7 +23,7 @@ describe('ItemTypeIcon', () => { } }); - const findGlIcon = () => wrapper.find(GlIcon); + const findGlIcon = () => wrapper.findComponent(GlIcon); describe('template', () => { it('renders component template correctly', () => { diff --git a/spec/frontend/groups/components/overview_tabs_spec.js b/spec/frontend/groups/components/overview_tabs_spec.js new file mode 100644 index 00000000000..352bf25b84f --- /dev/null +++ b/spec/frontend/groups/components/overview_tabs_spec.js @@ -0,0 +1,187 @@ +import { GlTab } from '@gitlab/ui'; +import { nextTick } from 'vue'; +import AxiosMockAdapter from 'axios-mock-adapter'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import OverviewTabs from '~/groups/components/overview_tabs.vue'; +import GroupsApp from '~/groups/components/app.vue'; +import GroupsStore from '~/groups/store/groups_store'; +import GroupsService from '~/groups/service/groups_service'; +import { createRouter } from '~/groups/init_overview_tabs'; +import { + ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, + ACTIVE_TAB_SHARED, + ACTIVE_TAB_ARCHIVED, +} from '~/groups/constants'; +import axios from '~/lib/utils/axios_utils'; + +const router = createRouter(); + +describe('OverviewTabs', () => { + let wrapper; + + const endpoints = { + subgroups_and_projects: '/groups/foobar/-/children.json', + shared: '/groups/foobar/-/shared_projects.json', + archived: '/groups/foobar/-/children.json?archived=only', + }; + + const routerMock = { + push: jest.fn(), + }; + + const createComponent = async ({ + route = { name: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, params: { group: 'foo/bar/baz' } }, + } = {}) => { + wrapper = mountExtended(OverviewTabs, { + router, + provide: { + endpoints, + }, + mocks: { $route: route, $router: routerMock }, + }); + + await nextTick(); + }; + + const findTabPanels = () => wrapper.findAllComponents(GlTab); + const findTab = (name) => wrapper.findByRole('tab', { name }); + const findSelectedTab = () => wrapper.findByRole('tab', { selected: true }); + + afterEach(() => { + wrapper.destroy(); + }); + + beforeEach(async () => { + // eslint-disable-next-line no-new + new AxiosMockAdapter(axios); + }); + + it('renders `Subgroups and projects` tab with `GroupsApp` component', async () => { + await createComponent(); + + const tabPanel = findTabPanels().at(0); + + expect(tabPanel.vm.$attrs).toMatchObject({ + title: OverviewTabs.i18n[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS], + lazy: false, + }); + expect(tabPanel.findComponent(GroupsApp).props()).toMatchObject({ + action: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, + store: new GroupsStore({ showSchemaMarkup: true }), + service: new GroupsService(endpoints[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS]), + hideProjects: false, + renderEmptyState: true, + }); + }); + + it('renders `Shared projects` tab and renders `GroupsApp` component after clicking tab', async () => { + await createComponent(); + + const tabPanel = findTabPanels().at(1); + + expect(tabPanel.vm.$attrs).toMatchObject({ + title: OverviewTabs.i18n[ACTIVE_TAB_SHARED], + lazy: true, + }); + + await findTab(OverviewTabs.i18n[ACTIVE_TAB_SHARED]).trigger('click'); + + expect(tabPanel.findComponent(GroupsApp).props()).toMatchObject({ + action: ACTIVE_TAB_SHARED, + store: new GroupsStore(), + service: new GroupsService(endpoints[ACTIVE_TAB_SHARED]), + hideProjects: false, + renderEmptyState: false, + }); + + expect(tabPanel.vm.$attrs.lazy).toBe(false); + }); + + it('renders `Archived projects` tab and renders `GroupsApp` component after clicking tab', async () => { + await createComponent(); + + const tabPanel = findTabPanels().at(2); + + expect(tabPanel.vm.$attrs).toMatchObject({ + title: OverviewTabs.i18n[ACTIVE_TAB_ARCHIVED], + lazy: true, + }); + + await findTab(OverviewTabs.i18n[ACTIVE_TAB_ARCHIVED]).trigger('click'); + + expect(tabPanel.findComponent(GroupsApp).props()).toMatchObject({ + action: ACTIVE_TAB_ARCHIVED, + store: new GroupsStore(), + service: new GroupsService(endpoints[ACTIVE_TAB_ARCHIVED]), + hideProjects: false, + renderEmptyState: false, + }); + + expect(tabPanel.vm.$attrs.lazy).toBe(false); + }); + + describe.each([ + [ + { name: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, params: { group: 'foo/bar/baz' } }, + OverviewTabs.i18n[ACTIVE_TAB_SHARED], + { + name: ACTIVE_TAB_SHARED, + params: { group: ['foo', 'bar', 'baz'] }, + }, + ], + [ + { name: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, params: { group: ['foo', 'bar', 'baz'] } }, + OverviewTabs.i18n[ACTIVE_TAB_SHARED], + { + name: ACTIVE_TAB_SHARED, + params: { group: ['foo', 'bar', 'baz'] }, + }, + ], + [ + { name: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, params: { group: 'foo' } }, + OverviewTabs.i18n[ACTIVE_TAB_SHARED], + { + name: ACTIVE_TAB_SHARED, + params: { group: ['foo'] }, + }, + ], + [ + { name: ACTIVE_TAB_SHARED, params: { group: 'foo/bar' } }, + OverviewTabs.i18n[ACTIVE_TAB_ARCHIVED], + { + name: ACTIVE_TAB_ARCHIVED, + params: { group: ['foo', 'bar'] }, + }, + ], + [ + { name: ACTIVE_TAB_SHARED, params: { group: 'foo/bar' } }, + OverviewTabs.i18n[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS], + { + name: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, + params: { group: ['foo', 'bar'] }, + }, + ], + [ + { name: ACTIVE_TAB_ARCHIVED, params: { group: ['foo'] } }, + OverviewTabs.i18n[ACTIVE_TAB_SHARED], + { + name: ACTIVE_TAB_SHARED, + params: { group: ['foo'] }, + }, + ], + ])('when current route is %j', (currentRoute, tabToClick, expectedRoute) => { + beforeEach(async () => { + await createComponent({ route: currentRoute }); + }); + + it(`sets ${OverviewTabs.i18n[currentRoute.name]} as active tab`, () => { + expect(findSelectedTab().text()).toBe(OverviewTabs.i18n[currentRoute.name]); + }); + + it(`pushes expected route when ${tabToClick} tab is clicked`, async () => { + await findTab(tabToClick).trigger('click'); + + expect(routerMock.push).toHaveBeenCalledWith(expectedRoute); + }); + }); +}); diff --git a/spec/frontend/groups/components/visibility_level_dropdown_spec.js b/spec/frontend/groups/components/visibility_level_dropdown_spec.js deleted file mode 100644 index 61b7bbb0833..00000000000 --- a/spec/frontend/groups/components/visibility_level_dropdown_spec.js +++ /dev/null @@ -1,70 +0,0 @@ -import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import Component from '~/groups/components/visibility_level_dropdown.vue'; - -describe('Visibility Level Dropdown', () => { - let wrapper; - - const options = [ - { level: 0, label: 'Private', description: 'Private description' }, - { level: 20, label: 'Public', description: 'Public description' }, - ]; - const defaultLevel = 0; - - const createComponent = (propsData) => { - wrapper = shallowMount(Component, { - propsData, - }); - }; - - beforeEach(() => { - createComponent({ - visibilityLevelOptions: options, - defaultLevel, - }); - }); - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - }); - - const hiddenInputValue = () => - wrapper.find("input[name='group[visibility_level]']").attributes('value'); - const dropdownText = () => wrapper.find(GlDropdown).props('text'); - const findDropdownItems = () => - wrapper.findAll(GlDropdownItem).wrappers.map((option) => ({ - text: option.text(), - secondaryText: option.props('secondaryText'), - })); - - describe('Default values', () => { - it('sets the value of the hidden input to the default value', () => { - expect(hiddenInputValue()).toBe(options[0].level.toString()); - }); - - it('sets the text of the dropdown to the default value', () => { - expect(dropdownText()).toBe(options[0].label); - }); - - it('shows all dropdown options', () => { - expect(findDropdownItems()).toEqual( - options.map(({ label, description }) => ({ text: label, secondaryText: description })), - ); - }); - }); - - describe('Selecting an option', () => { - beforeEach(() => { - wrapper.findAll(GlDropdownItem).at(1).vm.$emit('click'); - }); - - it('sets the value of the hidden input to the selected value', () => { - expect(hiddenInputValue()).toBe(options[1].level.toString()); - }); - - it('sets the text of the dropdown to the selected value', () => { - expect(dropdownText()).toBe(options[1].label); - }); - }); -}); |