diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-18 13:50:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-18 13:50:51 +0300 |
commit | db384e6b19af03b4c3c82a5760d83a3fd79f7982 (patch) | |
tree | 34beaef37df5f47ccbcf5729d7583aae093cffa0 /spec/frontend/import_entities | |
parent | 54fd7b1bad233e3944434da91d257fa7f63c3996 (diff) |
Add latest changes from gitlab-org/gitlab@16-3-stable-eev16.3.0-rc42
Diffstat (limited to 'spec/frontend/import_entities')
7 files changed, 191 insertions, 42 deletions
diff --git a/spec/frontend/import_entities/components/import_status_spec.js b/spec/frontend/import_entities/components/import_status_spec.js index 103a3e4ddd1..37c58b9cdf8 100644 --- a/spec/frontend/import_entities/components/import_status_spec.js +++ b/spec/frontend/import_entities/components/import_status_spec.js @@ -168,18 +168,14 @@ describe('Import entities status component', () => { }; describe.each` - detailsPath | importDetailsPage | partialImport | expectLink - ${undefined} | ${false} | ${false} | ${false} - ${undefined} | ${false} | ${true} | ${false} - ${undefined} | ${true} | ${false} | ${false} - ${undefined} | ${true} | ${true} | ${false} - ${mockDetailsPath} | ${false} | ${false} | ${false} - ${mockDetailsPath} | ${false} | ${true} | ${false} - ${mockDetailsPath} | ${true} | ${false} | ${false} - ${mockDetailsPath} | ${true} | ${true} | ${true} + detailsPath | partialImport | expectLink + ${undefined} | ${false} | ${false} + ${undefined} | ${true} | ${false} + ${mockDetailsPath} | ${false} | ${false} + ${mockDetailsPath} | ${true} | ${true} `( - 'when detailsPath is $detailsPath, feature flag importDetailsPage is $importDetailsPage, partial import is $partialImport', - ({ detailsPath, importDetailsPage, partialImport, expectLink }) => { + 'when detailsPath is $detailsPath, partial import is $partialImport', + ({ detailsPath, partialImport, expectLink }) => { beforeEach(() => { createComponent( { @@ -190,7 +186,6 @@ describe('Import entities status component', () => { { provide: { detailsPath, - glFeatures: { importDetailsPage }, }, }, ); diff --git a/spec/frontend/import_entities/components/import_target_dropdown_spec.js b/spec/frontend/import_entities/components/import_target_dropdown_spec.js new file mode 100644 index 00000000000..c12baed2374 --- /dev/null +++ b/spec/frontend/import_entities/components/import_target_dropdown_spec.js @@ -0,0 +1,99 @@ +import { GlCollapsibleListbox } from '@gitlab/ui'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import { shallowMount } from '@vue/test-utils'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; + +import ImportTargetDropdown from '~/import_entities/components/import_target_dropdown.vue'; +import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants'; +import searchNamespacesWhereUserCanImportProjectsQuery from '~/import_entities/import_projects/graphql/queries/search_namespaces_where_user_can_import_projects.query.graphql'; + +import { mockAvailableNamespaces, mockNamespacesResponse, mockUserNamespace } from '../mock_data'; + +Vue.use(VueApollo); + +describe('ImportTargetDropdown', () => { + let wrapper; + + const defaultProps = { + selected: mockUserNamespace, + userNamespace: mockUserNamespace, + }; + + const createComponent = ({ props = {} } = {}) => { + const apolloProvider = createMockApollo([ + [ + searchNamespacesWhereUserCanImportProjectsQuery, + jest.fn().mockResolvedValue(mockNamespacesResponse), + ], + ]); + + wrapper = shallowMount(ImportTargetDropdown, { + apolloProvider, + propsData: { + ...defaultProps, + ...props, + }, + }); + }; + + const findListbox = () => wrapper.findComponent(GlCollapsibleListbox); + const findListboxUsersItems = () => findListbox().props('items')[0].options; + const findListboxGroupsItems = () => findListbox().props('items')[1].options; + + const waitForQuery = async () => { + jest.advanceTimersByTime(DEBOUNCE_DELAY); + await waitForPromises(); + }; + + it('renders listbox', () => { + createComponent(); + + expect(findListbox().exists()).toBe(true); + }); + + it('truncates "toggle-text" when "selected" is too long', () => { + const mockSelected = 'a-group-path-that-is-longer-than-24-characters'; + + createComponent({ + props: { selected: mockSelected }, + }); + + expect(findListbox().props('toggleText')).toBe('a-group-path-that-is-lo…'); + }); + + it('passes userNamespace as "Users" group item', () => { + createComponent(); + + expect(findListboxUsersItems()).toEqual([ + { text: mockUserNamespace, value: mockUserNamespace }, + ]); + }); + + it('passes namespaces from GraphQL as "Groups" group item', async () => { + createComponent(); + + await waitForQuery(); + + expect(findListboxGroupsItems()).toEqual( + mockAvailableNamespaces.map((namespace) => ({ + text: namespace.fullPath, + value: namespace.fullPath, + })), + ); + }); + + it('filters namespaces based on user input', async () => { + createComponent(); + + findListbox().vm.$emit('search', 'match'); + + await waitForQuery(); + + expect(findListboxGroupsItems()).toEqual([ + { text: 'match1', value: 'match1' }, + { text: 'match2', value: 'match2' }, + ]); + }); +}); diff --git a/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js b/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js index 4c13ec555c2..87bee6afd62 100644 --- a/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js +++ b/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js @@ -1,4 +1,10 @@ -import { GlDropdown, GlIcon, GlDropdownItem } from '@gitlab/ui'; +import { + GlDisclosureDropdown, + GlDisclosureDropdownItem, + GlButtonGroup, + GlButton, + GlIcon, +} from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import ImportActionsCell from '~/import_entities/import_groups/components/import_actions_cell.vue'; @@ -13,6 +19,11 @@ describe('import actions cell', () => { isInvalid: false, ...props, }, + stubs: { + GlButtonGroup, + GlDisclosureDropdown, + GlDisclosureDropdownItem, + }, }); }; @@ -22,9 +33,9 @@ describe('import actions cell', () => { }); it('renders import dropdown', () => { - const dropdown = wrapper.findComponent(GlDropdown); - expect(dropdown.exists()).toBe(true); - expect(dropdown.props('text')).toBe('Import with projects'); + const button = wrapper.findComponent(GlButton); + expect(button.exists()).toBe(true); + expect(button.text()).toBe('Import with projects'); }); it('does not render icon with a hint', () => { @@ -38,9 +49,9 @@ describe('import actions cell', () => { }); it('renders re-import dropdown', () => { - const dropdown = wrapper.findComponent(GlDropdown); - expect(dropdown.exists()).toBe(true); - expect(dropdown.props('text')).toBe('Re-import with projects'); + const button = wrapper.findComponent(GlButton); + expect(button.exists()).toBe(true); + expect(button.text()).toBe('Re-import with projects'); }); it('renders icon with a hint', () => { @@ -55,22 +66,22 @@ describe('import actions cell', () => { it('does not render import dropdown when group is not available for import', () => { createComponent({ isAvailableForImport: false }); - const dropdown = wrapper.findComponent(GlDropdown); + const dropdown = wrapper.findComponent(GlDisclosureDropdown); expect(dropdown.exists()).toBe(false); }); it('renders import dropdown as disabled when group is invalid', () => { createComponent({ isInvalid: true, isAvailableForImport: true }); - const dropdown = wrapper.findComponent(GlDropdown); + const dropdown = wrapper.findComponent(GlDisclosureDropdown); expect(dropdown.props().disabled).toBe(true); }); it('emits import-group event when import button is clicked', () => { createComponent({ isAvailableForImport: true }); - const dropdown = wrapper.findComponent(GlDropdown); - dropdown.vm.$emit('click'); + const button = wrapper.findComponent(GlButton); + button.vm.$emit('click'); expect(wrapper.emitted('import-group')).toHaveLength(1); }); @@ -87,23 +98,24 @@ describe('import actions cell', () => { }); it('render import dropdown', () => { - const dropdown = wrapper.findComponent(GlDropdown); - expect(dropdown.props('text')).toBe(`${expectedAction} with projects`); - expect(dropdown.findComponent(GlDropdownItem).text()).toBe( + const button = wrapper.findComponent(GlButton); + const dropdown = wrapper.findComponent(GlDisclosureDropdown); + expect(button.element).toHaveText(`${expectedAction} with projects`); + expect(dropdown.findComponent(GlDisclosureDropdownItem).text()).toBe( `${expectedAction} without projects`, ); }); it('request migrate projects by default', () => { - const dropdown = wrapper.findComponent(GlDropdown); - dropdown.vm.$emit('click'); + const button = wrapper.findComponent(GlButton); + button.vm.$emit('click'); expect(wrapper.emitted('import-group')[0]).toStrictEqual([{ migrateProjects: true }]); }); it('request not to migrate projects via dropdown option', () => { - const dropdown = wrapper.findComponent(GlDropdown); - dropdown.findComponent(GlDropdownItem).vm.$emit('click'); + const dropdown = wrapper.findComponent(GlDisclosureDropdown); + dropdown.findComponent(GlDisclosureDropdownItem).vm.$emit('action'); expect(wrapper.emitted('import-group')[0]).toStrictEqual([{ migrateProjects: false }]); }); diff --git a/spec/frontend/import_entities/import_projects/components/github_status_table_spec.js b/spec/frontend/import_entities/import_projects/components/github_status_table_spec.js index 7eebff7364c..0b9e7a8cb73 100644 --- a/spec/frontend/import_entities/import_projects/components/github_status_table_spec.js +++ b/spec/frontend/import_entities/import_projects/components/github_status_table_spec.js @@ -1,6 +1,7 @@ import { GlTabs, GlSearchBoxByClick } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; +// eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; import { stubComponent } from 'helpers/stub_component'; diff --git a/spec/frontend/import_entities/import_projects/components/import_projects_table_spec.js b/spec/frontend/import_entities/import_projects/components/import_projects_table_spec.js index 351bbe5ea28..92d064846bd 100644 --- a/spec/frontend/import_entities/import_projects/components/import_projects_table_spec.js +++ b/spec/frontend/import_entities/import_projects/components/import_projects_table_spec.js @@ -1,6 +1,7 @@ import { GlLoadingIcon, GlButton, GlIntersectionObserver, GlSearchBoxByClick } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; +// eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; import { STATUSES } from '~/import_entities/constants'; import ImportProjectsTable from '~/import_entities/import_projects/components/import_projects_table.vue'; diff --git a/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js b/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js index 57e232a4c46..b4890c09fe2 100644 --- a/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js +++ b/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js @@ -1,9 +1,11 @@ import { GlBadge, GlButton } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; +// eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; -import { STATUSES } from '~/import_entities//constants'; -import ImportGroupDropdown from '~/import_entities/components/group_dropdown.vue'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; + +import { STATUSES } from '~/import_entities/constants'; +import ImportTargetDropdown from '~/import_entities/components/import_target_dropdown.vue'; import ImportStatus from '~/import_entities/components/import_status.vue'; import ProviderRepoTableRow from '~/import_entities/import_projects/components/provider_repo_table_row.vue'; @@ -39,8 +41,9 @@ describe('ProviderRepoTableRow', () => { const findImportButton = () => findButton('Import'); const findReimportButton = () => findButton('Re-import'); - const findGroupDropdown = () => wrapper.findComponent(ImportGroupDropdown); + const findImportTargetDropdown = () => wrapper.findComponent(ImportTargetDropdown); const findImportStatus = () => wrapper.findComponent(ImportStatus); + const findProviderLink = () => wrapper.findByTestId('providerLink'); const findCancelButton = () => { const buttons = wrapper @@ -55,7 +58,7 @@ describe('ProviderRepoTableRow', () => { const store = initStore(); - wrapper = shallowMount(ProviderRepoTableRow, { + wrapper = shallowMountExtended(ProviderRepoTableRow, { store, propsData: { userNamespace, optionalStages: {}, ...props }, }); @@ -75,7 +78,7 @@ describe('ProviderRepoTableRow', () => { }); it('renders project information', () => { - const providerLink = wrapper.find('[data-testid=providerLink]'); + const providerLink = findProviderLink(); expect(providerLink.attributes().href).toMatch(repo.importSource.providerLink); expect(providerLink.text()).toMatch(repo.importSource.fullName); @@ -86,7 +89,7 @@ describe('ProviderRepoTableRow', () => { }); it('renders a group namespace select', () => { - expect(wrapper.findComponent(ImportGroupDropdown).exists()).toBe(true); + expect(findImportTargetDropdown().exists()).toBe(true); }); it('renders import button', () => { @@ -106,7 +109,11 @@ describe('ProviderRepoTableRow', () => { it('includes optionalStages to import', async () => { const OPTIONAL_STAGES = { stage1: true, stage2: false }; - await wrapper.setProps({ optionalStages: OPTIONAL_STAGES }); + + mountComponent({ + repo, + optionalStages: OPTIONAL_STAGES, + }); findImportButton().vm.$emit('click'); @@ -192,7 +199,7 @@ describe('ProviderRepoTableRow', () => { }); it('renders project information', () => { - const providerLink = wrapper.find('[data-testid=providerLink]'); + const providerLink = findProviderLink(); expect(providerLink.attributes().href).toMatch(repo.importSource.providerLink); expect(providerLink.text()).toMatch(repo.importSource.fullName); @@ -203,7 +210,7 @@ describe('ProviderRepoTableRow', () => { }); it('does not render a namespace select', () => { - expect(findGroupDropdown().exists()).toBe(false); + expect(findImportTargetDropdown().exists()).toBe(false); }); it('does not render import button', () => { @@ -219,7 +226,7 @@ describe('ProviderRepoTableRow', () => { await nextTick(); - expect(findGroupDropdown().exists()).toBe(true); + expect(findImportTargetDropdown().exists()).toBe(true); }); it('imports repo when clicking re-import button', async () => { @@ -282,7 +289,7 @@ describe('ProviderRepoTableRow', () => { }); it('renders project information', () => { - const providerLink = wrapper.find('[data-testid=providerLink]'); + const providerLink = findProviderLink(); expect(providerLink.attributes().href).toMatch(repo.importSource.providerLink); expect(providerLink.text()).toMatch(repo.importSource.fullName); diff --git a/spec/frontend/import_entities/mock_data.js b/spec/frontend/import_entities/mock_data.js new file mode 100644 index 00000000000..9208f99651f --- /dev/null +++ b/spec/frontend/import_entities/mock_data.js @@ -0,0 +1,34 @@ +const mockGroupFactory = (fullPath) => ({ + id: `gid://gitlab/Group/${fullPath}`, + fullPath, + name: fullPath, + visibility: 'public', + webUrl: `http://gdk.test:3000/groups/${fullPath}`, + __typename: 'Group', +}); + +export const mockAvailableNamespaces = [ + mockGroupFactory('match1'), + mockGroupFactory('unrelated'), + mockGroupFactory('match2'), +]; + +export const mockNamespacesResponse = { + data: { + currentUser: { + id: 'gid://gitlab/User/1', + groups: { + nodes: mockAvailableNamespaces, + __typename: 'GroupConnection', + }, + namespace: { + id: 'gid://gitlab/Namespaces::UserNamespace/1', + fullPath: 'root', + __typename: 'Namespace', + }, + __typename: 'UserCore', + }, + }, +}; + +export const mockUserNamespace = 'user1'; |