diff options
Diffstat (limited to 'spec/frontend/projects')
11 files changed, 477 insertions, 40 deletions
diff --git a/spec/frontend/projects/commits/components/author_select_spec.js b/spec/frontend/projects/commits/components/author_select_spec.js index d11090cba8a..57e5ef0ed1d 100644 --- a/spec/frontend/projects/commits/components/author_select_spec.js +++ b/spec/frontend/projects/commits/components/author_select_spec.js @@ -71,7 +71,7 @@ describe('Author Select', () => { wrapper.setData({ hasSearchParam: true }); await nextTick(); - expect(findDropdownContainer().attributes('disabled')).toBeFalsy(); + expect(findDropdownContainer().attributes('disabled')).toBeUndefined(); }); it('has correct tooltip message', async () => { @@ -91,13 +91,13 @@ describe('Author Select', () => { wrapper.setData({ hasSearchParam: false }); await nextTick(); - expect(findDropdown().attributes('disabled')).toBeFalsy(); + expect(findDropdown().attributes('disabled')).toBeUndefined(); }); it('hasSearchParam if user types a truthy string', () => { wrapper.vm.setSearchParam('false'); - expect(wrapper.vm.hasSearchParam).toBeTruthy(); + expect(wrapper.vm.hasSearchParam).toBe(true); }); }); @@ -153,9 +153,9 @@ describe('Author Select', () => { }); it('has the correct props', async () => { - const [{ avatar_url, username }] = authors; + const [{ avatar_url: avatarUrl, username }] = authors; const result = { - avatarUrl: avatar_url, + avatarUrl, secondaryText: username, isChecked: true, }; diff --git a/spec/frontend/projects/compare/components/app_spec.js b/spec/frontend/projects/compare/components/app_spec.js index 18e7f2e0f6e..c9ffdf20c32 100644 --- a/spec/frontend/projects/compare/components/app_spec.js +++ b/spec/frontend/projects/compare/components/app_spec.js @@ -34,7 +34,8 @@ describe('CompareApp component', () => { expect(wrapper.props()).toEqual( expect.objectContaining({ projectCompareIndexPath: defaultProps.projectCompareIndexPath, - refsProjectPath: defaultProps.refsProjectPath, + sourceProjectRefsPath: defaultProps.sourceProjectRefsPath, + targetProjectRefsPath: defaultProps.targetProjectRefsPath, paramsFrom: defaultProps.paramsFrom, paramsTo: defaultProps.paramsTo, }), diff --git a/spec/frontend/projects/compare/components/mock_data.js b/spec/frontend/projects/compare/components/mock_data.js index 61309928c26..81d64469a2a 100644 --- a/spec/frontend/projects/compare/components/mock_data.js +++ b/spec/frontend/projects/compare/components/mock_data.js @@ -1,7 +1,12 @@ -const refsProjectPath = 'some/refs/path'; +const sourceProjectRefsPath = 'some/refs/path'; +const targetProjectRefsPath = 'some/refs/path'; const paramsName = 'to'; const paramsBranch = 'main'; -const defaultProject = { +const sourceProject = { + name: 'some-to-name', + id: '2', +}; +const targetProject = { name: 'some-to-name', id: '1', }; @@ -9,29 +14,31 @@ const defaultProject = { export const appDefaultProps = { projectCompareIndexPath: 'some/path', projectMergeRequestPath: '', - projects: [defaultProject], + projects: [sourceProject], paramsFrom: 'main', paramsTo: 'target/branch', createMrPath: '', - refsProjectPath, - defaultProject, + sourceProjectRefsPath, + targetProjectRefsPath, + sourceProject, + targetProject, }; export const revisionCardDefaultProps = { - selectedProject: defaultProject, + selectedProject: targetProject, paramsBranch, revisionText: 'Source', - refsProjectPath, + refsProjectPath: sourceProjectRefsPath, paramsName, }; export const repoDropdownDefaultProps = { - selectedProject: defaultProject, + selectedProject: targetProject, paramsName, }; export const revisionDropdownDefaultProps = { - refsProjectPath, + refsProjectPath: sourceProjectRefsPath, paramsBranch, paramsName, }; diff --git a/spec/frontend/projects/project_new_spec.js b/spec/frontend/projects/project_new_spec.js index 3034037fb1d..4fcecc3a307 100644 --- a/spec/frontend/projects/project_new_spec.js +++ b/spec/frontend/projects/project_new_spec.js @@ -1,6 +1,7 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; import { TEST_HOST } from 'helpers/test_constants'; import projectNew from '~/projects/project_new'; +import { mockTracking, triggerEvent, unmockTracking } from 'helpers/tracking_helper'; describe('New Project', () => { let $projectImportUrl; @@ -12,21 +13,27 @@ describe('New Project', () => { beforeEach(() => { setHTMLFixture(` - <div class='toggle-import-form'> - <div class='import-url-data'> - <div class="form-group"> - <input id="project_import_url" /> - </div> - <div id="import-url-auth-method"> - <div class="form-group"> - <input id="project-import-url-user" /> + <div class="tab-pane active"> + <div class='toggle-import-form'> + <form id="new_project"> + <div class='import-url-data'> + <div class="form-group"> + <input id="project_import_url" /> + </div> + <div id="import-url-auth-method"> + <div class="form-group"> + <input id="project-import-url-user" /> + </div> + <div class="form-group"> + <input id="project_import_url_password" /> + </div> + </div> + <input id="project_name" /> + <input id="project_path" /> </div> - <div class="form-group"> - <input id="project_import_url_password" /> - </div> - </div> - <input id="project_name" /> - <input id="project_path" /> + <div class="js-user-readme-repo"></div> + <button class="js-create-project-button"/> + </form> </div> </div> `); @@ -45,6 +52,38 @@ describe('New Project', () => { el.value = value; }; + describe('tracks manual path input', () => { + let trackingSpy; + + beforeEach(() => { + trackingSpy = mockTracking('_category_', undefined, jest.spyOn); + projectNew.bindEvents(); + $projectPath.oldInputValue = '_old_value_'; + }); + + afterEach(() => { + unmockTracking(); + }); + + it('tracks the event', () => { + $projectPath.value = '_new_value_'; + + triggerEvent($projectPath, 'blur'); + + expect(trackingSpy).toHaveBeenCalledWith(undefined, 'user_input_path_slug', { + label: 'new_project_form', + }); + }); + + it('does not track the event when there has been no change', () => { + $projectPath.value = '_old_value_'; + + triggerEvent($projectPath, 'blur'); + + expect(trackingSpy).not.toHaveBeenCalled(); + }); + }); + describe('deriveProjectPathFromUrl', () => { const dummyImportUrl = `${TEST_HOST}/dummy/import/url.git`; diff --git a/spec/frontend/projects/settings/branch_rules/branch_dropdown_spec.js b/spec/frontend/projects/settings/branch_rules/branch_dropdown_spec.js index 5997c2a083c..79bce5a4b3f 100644 --- a/spec/frontend/projects/settings/branch_rules/branch_dropdown_spec.js +++ b/spec/frontend/projects/settings/branch_rules/branch_dropdown_spec.js @@ -1,6 +1,6 @@ import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; -import { GlDropdown, GlSearchBoxByType, GlDropdownItem } from '@gitlab/ui'; +import { GlDropdown, GlSearchBoxByType, GlDropdownItem, GlSprintf } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import BranchDropdown, { i18n, @@ -36,15 +36,20 @@ describe('Branch dropdown', () => { await waitForPromises(); }; - const findGlDropdown = () => wrapper.find(GlDropdown); - const findAllBranches = () => wrapper.findAll(GlDropdownItem); + const findGlDropdown = () => wrapper.findComponent(GlDropdown); + const findAllBranches = () => wrapper.findAllComponents(GlDropdownItem); const findNoDataMsg = () => wrapper.findByTestId('no-data'); - const findGlSearchBoxByType = () => wrapper.find(GlSearchBoxByType); + const findGlSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType); const findWildcardButton = () => wrapper.findByTestId('create-wildcard-button'); + const findHelpText = () => wrapper.findComponent(GlSprintf); const setSearchTerm = (searchTerm) => findGlSearchBoxByType().vm.$emit('input', searchTerm); beforeEach(() => createComponent()); + afterEach(() => { + wrapper.destroy(); + }); + it('renders a GlDropdown component with the correct props', () => { expect(findGlDropdown().props()).toMatchObject({ text: value }); }); @@ -85,6 +90,10 @@ describe('Branch dropdown', () => { findWildcardButton().vm.$emit('click'); expect(wrapper.emitted('createWildcard')).toEqual([[searchTerm]]); }); + + it('renders help text', () => { + expect(findHelpText().attributes('message')).toBe(i18n.branchHelpText); + }); }); it('displays an error message if fetch failed', async () => { diff --git a/spec/frontend/projects/settings/branch_rules/components/protections/index_spec.js b/spec/frontend/projects/settings/branch_rules/components/protections/index_spec.js new file mode 100644 index 00000000000..3592fa50622 --- /dev/null +++ b/spec/frontend/projects/settings/branch_rules/components/protections/index_spec.js @@ -0,0 +1,57 @@ +import { nextTick } from 'vue'; +import { GlLink } from '@gitlab/ui'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import Protections, { + i18n, +} from '~/projects/settings/branch_rules/components/protections/index.vue'; +import PushProtections from '~/projects/settings/branch_rules/components/protections/push_protections.vue'; +import MergeProtections from '~/projects/settings/branch_rules/components/protections/merge_protections.vue'; +import { protections } from '../../mock_data'; + +describe('Branch Protections', () => { + let wrapper; + + const createComponent = async () => { + wrapper = mountExtended(Protections, { + propsData: { protections }, + }); + await nextTick(); + }; + + const findHeading = () => wrapper.find('h4'); + const findHelpText = () => wrapper.findByTestId('protections-help-text'); + const findHelpLink = () => wrapper.findComponent(GlLink); + const findPushProtections = () => wrapper.findComponent(PushProtections); + const findMergeProtections = () => wrapper.findComponent(MergeProtections); + + beforeEach(() => createComponent()); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders a heading', () => { + expect(findHeading().text()).toBe(i18n.protections); + }); + + it('renders help text', () => { + expect(findHelpText().text()).toMatchInterpolatedText(i18n.protectionsHelpText); + expect(findHelpLink().attributes('href')).toBe('/help/user/project/protected_branches'); + }); + + it('renders a PushProtections component with correct props', () => { + expect(findPushProtections().props('membersAllowedToPush')).toStrictEqual( + protections.membersAllowedToPush, + ); + expect(findPushProtections().props('allowForcePush')).toBe(protections.allowForcePush); + }); + + it('renders a MergeProtections component with correct props', () => { + expect(findMergeProtections().props('membersAllowedToMerge')).toStrictEqual( + protections.membersAllowedToMerge, + ); + expect(findMergeProtections().props('requireCodeOwnersApproval')).toBe( + protections.requireCodeOwnersApproval, + ); + }); +}); diff --git a/spec/frontend/projects/settings/branch_rules/components/protections/merge_protections_spec.js b/spec/frontend/projects/settings/branch_rules/components/protections/merge_protections_spec.js new file mode 100644 index 00000000000..0e168a2ad78 --- /dev/null +++ b/spec/frontend/projects/settings/branch_rules/components/protections/merge_protections_spec.js @@ -0,0 +1,53 @@ +import { GlFormGroup, GlFormCheckbox } from '@gitlab/ui'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import MergeProtections, { + i18n, +} from '~/projects/settings/branch_rules/components/protections/merge_protections.vue'; +import { membersAllowedToMerge, requireCodeOwnersApproval } from '../../mock_data'; + +describe('Merge Protections', () => { + let wrapper; + + const propsData = { + membersAllowedToMerge, + requireCodeOwnersApproval, + }; + + const createComponent = () => { + wrapper = mountExtended(MergeProtections, { + propsData, + }); + }; + + const findFormGroup = () => wrapper.findComponent(GlFormGroup); + const findCodeOwnersApprovalCheckbox = () => wrapper.findComponent(GlFormCheckbox); + + beforeEach(() => createComponent()); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders a form group with the correct label', () => { + expect(findFormGroup().text()).toContain(i18n.allowedToMerge); + }); + + describe('Require code owners approval checkbox', () => { + it('renders a checkbox with the correct props', () => { + expect(findCodeOwnersApprovalCheckbox().vm.$attrs.checked).toBe( + propsData.requireCodeOwnersApproval, + ); + }); + + it('renders help text', () => { + expect(findCodeOwnersApprovalCheckbox().text()).toContain(i18n.requireApprovalTitle); + expect(findCodeOwnersApprovalCheckbox().text()).toContain(i18n.requireApprovalHelpText); + }); + + it('emits a change-allow-force-push event when changed', () => { + findCodeOwnersApprovalCheckbox().vm.$emit('change', false); + + expect(wrapper.emitted('change-require-code-owners-approval')[0]).toEqual([false]); + }); + }); +}); diff --git a/spec/frontend/projects/settings/branch_rules/components/protections/push_protections_spec.js b/spec/frontend/projects/settings/branch_rules/components/protections/push_protections_spec.js new file mode 100644 index 00000000000..d54dad08338 --- /dev/null +++ b/spec/frontend/projects/settings/branch_rules/components/protections/push_protections_spec.js @@ -0,0 +1,50 @@ +import { GlFormGroup, GlSprintf, GlFormCheckbox } from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import PushProtections, { + i18n, +} from '~/projects/settings/branch_rules/components/protections/push_protections.vue'; +import { membersAllowedToPush, allowForcePush } from '../../mock_data'; + +describe('Push Protections', () => { + let wrapper; + const propsData = { + membersAllowedToPush, + allowForcePush, + }; + + const createComponent = () => { + wrapper = shallowMountExtended(PushProtections, { + propsData, + }); + }; + + const findFormGroup = () => wrapper.findComponent(GlFormGroup); + const findAllowForcePushCheckbox = () => wrapper.findComponent(GlFormCheckbox); + const findHelpText = () => wrapper.findComponent(GlSprintf); + + beforeEach(() => createComponent()); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders a form group with the correct label', () => { + expect(findFormGroup().attributes('label')).toBe(i18n.allowedToPush); + }); + + describe('Allow force push checkbox', () => { + it('renders a checkbox with the correct props', () => { + expect(findAllowForcePushCheckbox().vm.$attrs.checked).toBe(propsData.allowForcePush); + }); + + it('renders help text', () => { + expect(findHelpText().attributes('message')).toBe(i18n.forcePushTitle); + }); + + it('emits a change-allow-force-push event when changed', () => { + findAllowForcePushCheckbox().vm.$emit('change', false); + + expect(wrapper.emitted('change-allow-force-push')[0]).toEqual([false]); + }); + }); +}); diff --git a/spec/frontend/projects/settings/branch_rules/mock_data.js b/spec/frontend/projects/settings/branch_rules/mock_data.js new file mode 100644 index 00000000000..32cca027d19 --- /dev/null +++ b/spec/frontend/projects/settings/branch_rules/mock_data.js @@ -0,0 +1,10 @@ +export const membersAllowedToPush = ['Maintainers', 'Developers']; +export const allowForcePush = false; +export const membersAllowedToMerge = ['Maintainers']; +export const requireCodeOwnersApproval = false; +export const protections = { + membersAllowedToPush, + allowForcePush, + membersAllowedToMerge, + requireCodeOwnersApproval, +}; diff --git a/spec/frontend/projects/settings/branch_rules/rule_edit_spec.js b/spec/frontend/projects/settings/branch_rules/rule_edit_spec.js index 66ae6ddc02d..b0b2b9191d4 100644 --- a/spec/frontend/projects/settings/branch_rules/rule_edit_spec.js +++ b/spec/frontend/projects/settings/branch_rules/rule_edit_spec.js @@ -3,9 +3,12 @@ import { getParameterByName } from '~/lib/utils/url_utility'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import RuleEdit from '~/projects/settings/branch_rules/components/rule_edit.vue'; import BranchDropdown from '~/projects/settings/branch_rules/components/branch_dropdown.vue'; +import Protections from '~/projects/settings/branch_rules/components/protections/index.vue'; jest.mock('~/lib/utils/url_utility', () => ({ getParameterByName: jest.fn().mockImplementation(() => 'main'), + joinPaths: jest.fn(), + setUrlFragment: jest.fn(), })); describe('Edit branch rule', () => { @@ -16,10 +19,15 @@ describe('Edit branch rule', () => { wrapper = shallowMountExtended(RuleEdit, { propsData: { projectPath } }); }; - const findBranchDropdown = () => wrapper.find(BranchDropdown); + const findBranchDropdown = () => wrapper.findComponent(BranchDropdown); + const findProtections = () => wrapper.findComponent(Protections); beforeEach(() => createComponent()); + afterEach(() => { + wrapper.destroy(); + }); + it('gets the branch param from url', () => { expect(getParameterByName).toHaveBeenCalledWith('branch'); }); @@ -46,4 +54,55 @@ describe('Edit branch rule', () => { expect(findBranchDropdown().props('value')).toBe(wildcard); }); }); + + describe('Protections', () => { + it('renders a Protections component with the correct props', () => { + expect(findProtections().props('protections')).toMatchObject({ + membersAllowedToPush: [], + allowForcePush: false, + membersAllowedToMerge: [], + requireCodeOwnersApproval: false, + }); + }); + + it('updates protections when change-allowed-to-push-members is emitted', async () => { + const membersAllowedToPush = ['test']; + findProtections().vm.$emit('change-allowed-to-push-members', membersAllowedToPush); + await nextTick(); + + expect(findProtections().props('protections')).toEqual( + expect.objectContaining({ membersAllowedToPush }), + ); + }); + + it('updates protections when change-allow-force-push is emitted', async () => { + const allowForcePush = true; + findProtections().vm.$emit('change-allow-force-push', allowForcePush); + await nextTick(); + + expect(findProtections().props('protections')).toEqual( + expect.objectContaining({ allowForcePush }), + ); + }); + + it('updates protections when change-allowed-to-merge-members is emitted', async () => { + const membersAllowedToMerge = ['test']; + findProtections().vm.$emit('change-allowed-to-merge-members', membersAllowedToMerge); + await nextTick(); + + expect(findProtections().props('protections')).toEqual( + expect.objectContaining({ membersAllowedToMerge }), + ); + }); + + it('updates protections when change-require-code-owners-approval is emitted', async () => { + const requireCodeOwnersApproval = true; + findProtections().vm.$emit('change-require-code-owners-approval', requireCodeOwnersApproval); + await nextTick(); + + expect(findProtections().props('protections')).toEqual( + expect.objectContaining({ requireCodeOwnersApproval }), + ); + }); + }); }); diff --git a/spec/frontend/projects/settings/components/transfer_project_form_spec.js b/spec/frontend/projects/settings/components/transfer_project_form_spec.js index 85b09ced024..bde7148078d 100644 --- a/spec/frontend/projects/settings/components/transfer_project_form_spec.js +++ b/spec/frontend/projects/settings/components/transfer_project_form_spec.js @@ -1,11 +1,19 @@ +import Vue, { nextTick } from 'vue'; +import VueApollo from 'vue-apollo'; +import searchNamespacesWhereUserCanTransferProjectsQueryResponsePage1 from 'test_fixtures/graphql/projects/settings/search_namespaces_where_user_can_transfer_projects_page_1.query.graphql.json'; +import searchNamespacesWhereUserCanTransferProjectsQueryResponsePage2 from 'test_fixtures/graphql/projects/settings/search_namespaces_where_user_can_transfer_projects_page_2.query.graphql.json'; import { groupNamespaces, userNamespaces, } from 'jest/vue_shared/components/namespace_select/mock_data'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import TransferProjectForm from '~/projects/settings/components/transfer_project_form.vue'; import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select.vue'; import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue'; +import searchNamespacesWhereUserCanTransferProjectsQuery from '~/projects/settings/graphql/queries/search_namespaces_where_user_can_transfer_projects.query.graphql'; +import waitForPromises from 'helpers/wait_for_promises'; describe('Transfer project form', () => { let wrapper; @@ -13,36 +21,50 @@ describe('Transfer project form', () => { const confirmButtonText = 'Confirm'; const confirmationPhrase = 'You must construct additional pylons!'; - const createComponent = () => - shallowMountExtended(TransferProjectForm, { + const runDebounce = () => jest.runAllTimers(); + + Vue.use(VueApollo); + + const defaultQueryHandler = jest + .fn() + .mockResolvedValue(searchNamespacesWhereUserCanTransferProjectsQueryResponsePage1); + + const createComponent = ({ + requestHandlers = [[searchNamespacesWhereUserCanTransferProjectsQuery, defaultQueryHandler]], + } = {}) => { + wrapper = shallowMountExtended(TransferProjectForm, { propsData: { userNamespaces, groupNamespaces, confirmButtonText, confirmationPhrase, }, + apolloProvider: createMockApollo(requestHandlers), }); + }; const findNamespaceSelect = () => wrapper.findComponent(NamespaceSelect); const findConfirmDanger = () => wrapper.findComponent(ConfirmDanger); - beforeEach(() => { - wrapper = createComponent(); - }); - afterEach(() => { wrapper.destroy(); }); it('renders the namespace selector', () => { + createComponent(); + expect(findNamespaceSelect().exists()).toBe(true); }); it('renders the confirm button', () => { + createComponent(); + expect(findConfirmDanger().exists()).toBe(true); }); it('disables the confirm button by default', () => { + createComponent(); + expect(findConfirmDanger().attributes('disabled')).toBe('true'); }); @@ -50,6 +72,8 @@ describe('Transfer project form', () => { const [selectedItem] = groupNamespaces; beforeEach(() => { + createComponent(); + findNamespaceSelect().vm.$emit('select', selectedItem); }); @@ -69,4 +93,132 @@ describe('Transfer project form', () => { expect(wrapper.emitted('confirm')).toBeDefined(); }); }); + + it('passes correct props to `NamespaceSelect` component', async () => { + createComponent(); + + runDebounce(); + await waitForPromises(); + + const { + namespace, + groups, + } = searchNamespacesWhereUserCanTransferProjectsQueryResponsePage1.data.currentUser; + + expect(findNamespaceSelect().props()).toMatchObject({ + userNamespaces: [ + { + id: getIdFromGraphQLId(namespace.id), + humanName: namespace.fullName, + }, + ], + groupNamespaces: groups.nodes.map((node) => ({ + id: getIdFromGraphQLId(node.id), + humanName: node.fullName, + })), + hasNextPageOfGroups: true, + isLoadingMoreGroups: false, + isSearchLoading: false, + shouldFilterNamespaces: false, + }); + }); + + describe('when `search` event is fired', () => { + const arrange = async () => { + createComponent(); + + findNamespaceSelect().vm.$emit('search', 'foo'); + + await nextTick(); + }; + + it('sets `isSearchLoading` prop to `true`', async () => { + await arrange(); + + expect(findNamespaceSelect().props('isSearchLoading')).toBe(true); + }); + + it('passes `search` variable to query', async () => { + await arrange(); + + runDebounce(); + await waitForPromises(); + + expect(defaultQueryHandler).toHaveBeenCalledWith(expect.objectContaining({ search: 'foo' })); + }); + }); + + describe('when `load-more-groups` event is fired', () => { + let queryHandler; + + const arrange = async () => { + queryHandler = jest.fn(); + queryHandler.mockResolvedValueOnce( + searchNamespacesWhereUserCanTransferProjectsQueryResponsePage1, + ); + queryHandler.mockResolvedValueOnce( + searchNamespacesWhereUserCanTransferProjectsQueryResponsePage2, + ); + + createComponent({ + requestHandlers: [[searchNamespacesWhereUserCanTransferProjectsQuery, queryHandler]], + }); + + runDebounce(); + await waitForPromises(); + + findNamespaceSelect().vm.$emit('load-more-groups'); + await nextTick(); + }; + + it('sets `isLoadingMoreGroups` prop to `true`', async () => { + await arrange(); + + expect(findNamespaceSelect().props('isLoadingMoreGroups')).toBe(true); + }); + + it('passes `after` and `first` variables to query', async () => { + await arrange(); + + runDebounce(); + await waitForPromises(); + + expect(queryHandler).toHaveBeenCalledWith( + expect.objectContaining({ + first: 25, + after: + searchNamespacesWhereUserCanTransferProjectsQueryResponsePage1.data.currentUser.groups + .pageInfo.endCursor, + }), + ); + }); + + it('updates `groupNamespaces` prop with new groups', async () => { + await arrange(); + + runDebounce(); + await waitForPromises(); + + expect(findNamespaceSelect().props('groupNamespaces')).toEqual( + [ + ...searchNamespacesWhereUserCanTransferProjectsQueryResponsePage1.data.currentUser.groups + .nodes, + ...searchNamespacesWhereUserCanTransferProjectsQueryResponsePage2.data.currentUser.groups + .nodes, + ].map((node) => ({ + id: getIdFromGraphQLId(node.id), + humanName: node.fullName, + })), + ); + }); + + it('updates `hasNextPageOfGroups` prop', async () => { + await arrange(); + + runDebounce(); + await waitForPromises(); + + expect(findNamespaceSelect().props('hasNextPageOfGroups')).toBe(false); + }); + }); }); |