Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-03-17 15:13:40 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-17 15:13:40 +0300
commitdb30b31f056d0de120d9238a7786e19cafbce69f (patch)
tree9fc08f552865dc4e28eb9db475014f86cc061495 /spec/frontend
parentaab0be458344b772293da292cba11648011c4c1e (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/projects/settings/components/new_access_dropdown_spec.js16
-rw-r--r--spec/frontend/repository/components/fork_info_spec.js133
-rw-r--r--spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js42
-rw-r--r--spec/frontend/repository/components/tree_content_spec.js4
-rw-r--r--spec/frontend/repository/mock_data.js6
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',
+};