diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-17 15:13:40 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-17 15:13:40 +0300 |
commit | db30b31f056d0de120d9238a7786e19cafbce69f (patch) | |
tree | 9fc08f552865dc4e28eb9db475014f86cc061495 /spec/frontend | |
parent | aab0be458344b772293da292cba11648011c4c1e (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
5 files changed, 184 insertions, 17 deletions
diff --git a/spec/frontend/projects/settings/components/new_access_dropdown_spec.js b/spec/frontend/projects/settings/components/new_access_dropdown_spec.js index b4b6603888c..f3e536de703 100644 --- a/spec/frontend/projects/settings/components/new_access_dropdown_spec.js +++ b/spec/frontend/projects/settings/components/new_access_dropdown_spec.js @@ -94,6 +94,7 @@ describe('Access Level Dropdown', () => { const findAllDropdownItems = () => findDropdown().findAllComponents(GlDropdownItem); const findAllDropdownHeaders = () => findDropdown().findAllComponents(GlDropdownSectionHeader); const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); + const findDeployKeyDropdownItem = () => wrapper.findByTestId('deploy_key-dropdown-item'); const findDropdownItemWithText = (items, text) => items.filter((item) => item.text().includes(text)).at(0); @@ -138,6 +139,21 @@ describe('Access Level Dropdown', () => { it('renders dropdown item for each access level type', () => { expect(findAllDropdownItems()).toHaveLength(12); }); + + it.each` + accessLevel | shouldRenderDeployKeyItems + ${ACCESS_LEVELS.PUSH} | ${true} + ${ACCESS_LEVELS.CREATE} | ${true} + ${ACCESS_LEVELS.MERGE} | ${false} + `( + 'conditionally renders deploy keys based on access levels', + async ({ accessLevel, shouldRenderDeployKeyItems }) => { + createComponent({ accessLevel }); + await waitForPromises(); + + expect(findDeployKeyDropdownItem().exists()).toBe(shouldRenderDeployKeyItems); + }, + ); }); describe('toggleLabel', () => { diff --git a/spec/frontend/repository/components/fork_info_spec.js b/spec/frontend/repository/components/fork_info_spec.js index 4b86d9425bc..7a2b03a8d8f 100644 --- a/spec/frontend/repository/components/fork_info_spec.js +++ b/spec/frontend/repository/components/fork_info_spec.js @@ -1,13 +1,16 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; -import { GlSkeletonLoader, GlIcon, GlLink, GlSprintf } from '@gitlab/ui'; +import { GlSkeletonLoader, GlIcon, GlLink, GlSprintf, GlButton, GlLoadingIcon } from '@gitlab/ui'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; +import { stubComponent } from 'helpers/stub_component'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { createAlert } from '~/alert'; import ForkInfo, { i18n } from '~/repository/components/fork_info.vue'; +import ConflictsModal from '~/repository/components/fork_sync_conflicts_modal.vue'; import forkDetailsQuery from '~/repository/queries/fork_details.query.graphql'; +import syncForkMutation from '~/repository/mutations/sync_fork.mutation.graphql'; import { propsForkInfo } from '../mock_data'; jest.mock('~/alert'); @@ -17,26 +20,56 @@ describe('ForkInfo component', () => { let mockResolver; const forkInfoError = new Error('Something went wrong'); const projectId = 'gid://gitlab/Project/1'; + const showMock = jest.fn(); + const synchronizeFork = true; Vue.use(VueApollo); - const createCommitData = ({ ahead = 3, behind = 7 }) => { + const createForkDetailsData = ( + forkDetails = { ahead: 3, behind: 7, isSyncing: false, hasConflicts: false }, + ) => { return { data: { - project: { id: projectId, forkDetails: { ahead, behind, __typename: 'ForkDetails' } }, + project: { id: projectId, forkDetails }, }, }; }; - const createComponent = (props = {}, data = {}, isRequestFailed = false) => { + const createSyncForkDetailsData = ( + forkDetails = { ahead: 3, behind: 7, isSyncing: false, hasConflicts: false }, + ) => { + return { + data: { + projectSyncFork: { details: forkDetails, errors: [] }, + }, + }; + }; + + const createComponent = (props = {}, data = {}, mutationData = {}, isRequestFailed = false) => { mockResolver = isRequestFailed ? jest.fn().mockRejectedValue(forkInfoError) - : jest.fn().mockResolvedValue(createCommitData(data)); + : jest.fn().mockResolvedValue(createForkDetailsData(data)); wrapper = shallowMountExtended(ForkInfo, { - apolloProvider: createMockApollo([[forkDetailsQuery, mockResolver]]), + apolloProvider: createMockApollo([ + [forkDetailsQuery, mockResolver], + [syncForkMutation, jest.fn().mockResolvedValue(createSyncForkDetailsData(mutationData))], + ]), propsData: { ...propsForkInfo, ...props }, - stubs: { GlSprintf }, + stubs: { + GlSprintf, + GlButton, + ConflictsModal: stubComponent(ConflictsModal, { + template: + '<div><slot name="modal-title"></slot><slot></slot><slot name="modal-footer"></slot></div>', + methods: { show: showMock }, + }), + }, + provide: { + glFeatures: { + synchronizeFork, + }, + }, }); return waitForPromises(); }; @@ -44,6 +77,8 @@ describe('ForkInfo component', () => { const findLink = () => wrapper.findComponent(GlLink); const findSkeleton = () => wrapper.findComponent(GlSkeletonLoader); const findIcon = () => wrapper.findComponent(GlIcon); + const findUpdateForkButton = () => wrapper.findComponent(GlButton); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findDivergenceMessage = () => wrapper.findByTestId('divergence-message'); const findInaccessibleMessage = () => wrapper.findByTestId('inaccessible-project'); const findCompareLinks = () => findDivergenceMessage().findAllComponents(GlLink); @@ -87,14 +122,50 @@ describe('ForkInfo component', () => { expect(link.attributes('href')).toBe(propsForkInfo.sourcePath); }); - it('renders unknown divergence message when divergence is unknown', async () => { - await createComponent({}, { ahead: null, behind: null }); - expect(findDivergenceMessage().text()).toBe(i18n.unknown); + describe('Unknown divergence', () => { + beforeEach(async () => { + await createComponent( + {}, + { ahead: null, behind: null, isSyncing: false, hasConflicts: false }, + ); + }); + + it('renders unknown divergence message when divergence is unknown', async () => { + expect(findDivergenceMessage().text()).toBe(i18n.unknown); + }); + + it('renders Update Fork button', async () => { + expect(findUpdateForkButton().exists()).toBe(true); + expect(findUpdateForkButton().text()).toBe(i18n.sync); + }); + }); + + describe('Up to date divergence', () => { + beforeEach(async () => { + await createComponent({}, { ahead: 0, behind: 0, isSyncing: false, hasConflicts: false }); + }); + + it('renders up to date message when fork is up to date', async () => { + expect(findDivergenceMessage().text()).toBe(i18n.upToDate); + }); + + it('does not render Update Fork button', async () => { + expect(findUpdateForkButton().exists()).toBe(false); + }); }); - it('renders up to date message when divergence is unknown', async () => { - await createComponent({}, { ahead: 0, behind: 0 }); - expect(findDivergenceMessage().text()).toBe(i18n.upToDate); + describe('Limited visibility project', () => { + beforeEach(async () => { + await createComponent({}, null); + }); + + it('renders limited visibility messsage when forkDetails are empty', async () => { + expect(findDivergenceMessage().text()).toBe(i18n.limitedVisibility); + }); + + it('does not render Update Fork button', async () => { + expect(findUpdateForkButton().exists()).toBe(false); + }); }); describe.each([ @@ -104,6 +175,7 @@ describe('ForkInfo component', () => { message: '3 commits behind, 7 commits ahead of the upstream repository.', firstLink: propsForkInfo.behindComparePath, secondLink: propsForkInfo.aheadComparePath, + hasButton: true, }, { ahead: 7, @@ -111,6 +183,7 @@ describe('ForkInfo component', () => { message: '7 commits ahead of the upstream repository.', firstLink: propsForkInfo.aheadComparePath, secondLink: '', + hasButton: false, }, { ahead: 0, @@ -118,12 +191,13 @@ describe('ForkInfo component', () => { message: '3 commits behind the upstream repository.', firstLink: propsForkInfo.behindComparePath, secondLink: '', + hasButton: true, }, ])( 'renders correct divergence message for ahead: $ahead, behind: $behind divergence commits', - ({ ahead, behind, message, firstLink, secondLink }) => { + ({ ahead, behind, message, firstLink, secondLink, hasButton }) => { beforeEach(async () => { - await createComponent({}, { ahead, behind }); + await createComponent({}, { ahead, behind, isSyncing: false, hasConflicts: false }); }); it('displays correct text', () => { @@ -138,9 +212,38 @@ describe('ForkInfo component', () => { expect(links.at(1).attributes('href')).toBe(secondLink); } }); + + it('renders Update Fork button when fork is behind', () => { + expect(findUpdateForkButton().exists()).toBe(hasButton); + if (hasButton) { + expect(findUpdateForkButton().text()).toBe(i18n.sync); + } + }); }, ); + describe('when sync is not possible due to conflicts', () => { + it('opens Conflicts Modal', async () => { + await createComponent({}, { ahead: 7, behind: 3, isSyncing: false, hasConflicts: true }); + findUpdateForkButton().vm.$emit('click'); + expect(showMock).toHaveBeenCalled(); + }); + }); + + describe('projectSyncFork mutation', () => { + it('changes button to have loading state', async () => { + await createComponent( + {}, + { ahead: 0, behind: 3, isSyncing: false, hasConflicts: false }, + { ahead: 0, behind: 3, isSyncing: true, hasConflicts: false }, + ); + expect(findLoadingIcon().exists()).toBe(false); + findUpdateForkButton().vm.$emit('click'); + await waitForPromises(); + expect(findLoadingIcon().exists()).toBe(true); + }); + }); + it('renders alert with error message when request fails', async () => { await createComponent({}, {}, true); expect(createAlert).toHaveBeenCalledWith({ diff --git a/spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js b/spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js new file mode 100644 index 00000000000..f97c970275b --- /dev/null +++ b/spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js @@ -0,0 +1,42 @@ +import { GlModal } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import ConflictsModal, { i18n } from '~/repository/components/fork_sync_conflicts_modal.vue'; +import { propsConflictsModal } from '../mock_data'; + +describe('ConflictsModal', () => { + let wrapper; + + function createComponent({ props = {} } = {}) { + wrapper = shallowMount(ConflictsModal, { + propsData: props, + stubs: { GlModal }, + }); + } + + beforeEach(() => { + createComponent({ props: propsConflictsModal }); + }); + + const findModal = () => wrapper.findComponent(GlModal); + const findInstructions = () => wrapper.findAll('[ data-testid="resolve-conflict-instructions"]'); + + it('renders a modal', () => { + expect(findModal().exists()).toBe(true); + }); + + it('passes title as a prop to a gl-modal component', () => { + expect(findModal().props().title).toBe(i18n.modalTitle); + }); + + it('renders a selection of markdown fields', () => { + expect(findInstructions().length).toBe(3); + }); + + it('renders a source url in a first intruction', () => { + expect(findInstructions().at(0).text()).toContain(propsConflictsModal.sourcePath); + }); + + it('renders default branch name in a first intruction', () => { + expect(findInstructions().at(0).text()).toContain(propsConflictsModal.sourceDefaultBranch); + }); +}); diff --git a/spec/frontend/repository/components/tree_content_spec.js b/spec/frontend/repository/components/tree_content_spec.js index 0f4edb19632..9597d8a7b77 100644 --- a/spec/frontend/repository/components/tree_content_spec.js +++ b/spec/frontend/repository/components/tree_content_spec.js @@ -20,9 +20,9 @@ let vm; let $apollo; const mockResponse = jest.fn().mockReturnValue(Promise.resolve({ data: {} })); -function factory(path, appoloMockResponse = mockResponse) { +function factory(path, apolloMockResponse = mockResponse) { $apollo = { - query: appoloMockResponse, + query: apolloMockResponse, }; vm = shallowMount(TreeContent, { diff --git a/spec/frontend/repository/mock_data.js b/spec/frontend/repository/mock_data.js index 04ffe52bc3f..418a93a10cc 100644 --- a/spec/frontend/repository/mock_data.js +++ b/spec/frontend/repository/mock_data.js @@ -126,3 +126,9 @@ export const propsForkInfo = { aheadComparePath: '/nataliia/myGitLab/-/compare/main...ref?from_project_id=1', behindComparePath: 'gitlab-org/gitlab/-/compare/ref...main?from_project_id=2', }; + +export const propsConflictsModal = { + sourceDefaultBranch: 'branch-name', + sourceName: 'source-name', + sourcePath: 'path/to/project', +}; |