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:
Diffstat (limited to 'spec/frontend/pages/projects')
-rw-r--r--spec/frontend/pages/projects/forks/new/components/app_spec.js1
-rw-r--r--spec/frontend/pages/projects/forks/new/components/fork_form_spec.js182
-rw-r--r--spec/frontend/pages/projects/forks/new/components/fork_groups_list_spec.js2
-rw-r--r--spec/frontend/pages/projects/graphs/__snapshots__/code_coverage_spec.js.snap2
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap2
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap2
-rw-r--r--spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js27
7 files changed, 202 insertions, 16 deletions
diff --git a/spec/frontend/pages/projects/forks/new/components/app_spec.js b/spec/frontend/pages/projects/forks/new/components/app_spec.js
index e1820606704..a7b4b9c42bd 100644
--- a/spec/frontend/pages/projects/forks/new/components/app_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/app_spec.js
@@ -13,6 +13,7 @@ describe('App component', () => {
projectPath: 'project-name',
projectDescription: 'some project description',
projectVisibility: 'private',
+ restrictedVisibilityLevels: [],
};
const createComponent = (props = {}) => {
diff --git a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
index 6d853120232..c80ccfa8256 100644
--- a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
@@ -1,4 +1,5 @@
-import { GlFormInputGroup, GlFormInput, GlForm } from '@gitlab/ui';
+import { GlFormInputGroup, GlFormInput, GlForm, GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
+import { getByRole, getAllByRole } from '@testing-library/dom';
import { mount, shallowMount } from '@vue/test-utils';
import axios from 'axios';
import AxiosMockAdapter from 'axios-mock-adapter';
@@ -15,6 +16,13 @@ describe('ForkForm component', () => {
let wrapper;
let axiosMock;
+ const PROJECT_VISIBILITY_TYPE = {
+ private:
+ 'Private Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group.',
+ internal: 'Internal The project can be accessed by any logged in user.',
+ public: 'Public The project can be accessed without any authentication.',
+ };
+
const GON_GITLAB_URL = 'https://gitlab.com';
const GON_API_VERSION = 'v7';
@@ -37,6 +45,7 @@ describe('ForkForm component', () => {
projectPath: 'project-name',
projectDescription: 'some project description',
projectVisibility: 'private',
+ restrictedVisibilityLevels: [],
};
const mockGetRequest = (data = {}, statusCode = httpStatus.OK) => {
@@ -61,6 +70,8 @@ describe('ForkForm component', () => {
stubs: {
GlFormInputGroup,
GlFormInput,
+ GlFormRadioGroup,
+ GlFormRadio,
},
});
};
@@ -81,6 +92,7 @@ describe('ForkForm component', () => {
axiosMock.restore();
});
+ const findFormSelectOptions = () => wrapper.find('select[name="namespace"]').findAll('option');
const findPrivateRadio = () => wrapper.find('[data-testid="radio-private"]');
const findInternalRadio = () => wrapper.find('[data-testid="radio-internal"]');
const findPublicRadio = () => wrapper.find('[data-testid="radio-public"]');
@@ -203,24 +215,145 @@ describe('ForkForm component', () => {
});
describe('visibility level', () => {
+ it('displays the correct description', () => {
+ mockGetRequest();
+ createComponent();
+
+ const formRadios = wrapper.findAll(GlFormRadio);
+
+ Object.keys(PROJECT_VISIBILITY_TYPE).forEach((visibilityType, index) => {
+ expect(formRadios.at(index).text()).toBe(PROJECT_VISIBILITY_TYPE[visibilityType]);
+ });
+ });
+
+ it('displays all 3 visibility levels', () => {
+ mockGetRequest();
+ createComponent();
+
+ expect(wrapper.findAll(GlFormRadio)).toHaveLength(3);
+ });
+
+ describe('when the namespace is changed', () => {
+ const namespaces = [
+ {
+ visibility: 'private',
+ },
+ {
+ visibility: 'internal',
+ },
+ {
+ visibility: 'public',
+ },
+ ];
+
+ beforeEach(() => {
+ mockGetRequest();
+ });
+
+ it('resets the visibility to default "private"', async () => {
+ createFullComponent({ projectVisibility: 'public' }, { namespaces });
+
+ expect(wrapper.vm.form.fields.visibility.value).toBe('public');
+ await findFormSelectOptions().at(1).setSelected();
+
+ await wrapper.vm.$nextTick();
+
+ expect(getByRole(wrapper.element, 'radio', { name: /private/i }).checked).toBe(true);
+ });
+
+ it('sets the visibility to be null when restrictedVisibilityLevels is set', async () => {
+ createFullComponent({ restrictedVisibilityLevels: [10] }, { namespaces });
+
+ await findFormSelectOptions().at(1).setSelected();
+
+ await wrapper.vm.$nextTick();
+
+ const container = getByRole(wrapper.element, 'radiogroup', { name: /visibility/i });
+ const visibilityRadios = getAllByRole(container, 'radio');
+ expect(visibilityRadios.filter((e) => e.checked)).toHaveLength(0);
+ });
+ });
+
+ it.each`
+ project | restrictedVisibilityLevels
+ ${'private'} | ${[]}
+ ${'internal'} | ${[]}
+ ${'public'} | ${[]}
+ ${'private'} | ${[0]}
+ ${'private'} | ${[10]}
+ ${'private'} | ${[20]}
+ ${'private'} | ${[0, 10]}
+ ${'private'} | ${[0, 20]}
+ ${'private'} | ${[10, 20]}
+ ${'private'} | ${[0, 10, 20]}
+ ${'internal'} | ${[0]}
+ ${'internal'} | ${[10]}
+ ${'internal'} | ${[20]}
+ ${'internal'} | ${[0, 10]}
+ ${'internal'} | ${[0, 20]}
+ ${'internal'} | ${[10, 20]}
+ ${'internal'} | ${[0, 10, 20]}
+ ${'public'} | ${[0]}
+ ${'public'} | ${[10]}
+ ${'public'} | ${[0, 10]}
+ ${'public'} | ${[0, 20]}
+ ${'public'} | ${[10, 20]}
+ ${'public'} | ${[0, 10, 20]}
+ `('checks the correct radio button', async ({ project, restrictedVisibilityLevels }) => {
+ mockGetRequest();
+ createFullComponent({
+ projectVisibility: project,
+ restrictedVisibilityLevels,
+ });
+
+ if (restrictedVisibilityLevels.length === 0) {
+ expect(wrapper.find('[name="visibility"]:checked').attributes('value')).toBe(project);
+ } else {
+ expect(wrapper.find('[name="visibility"]:checked').exists()).toBe(false);
+ }
+ });
+
it.each`
- project | namespace | privateIsDisabled | internalIsDisabled | publicIsDisabled
- ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'}
- ${'private'} | ${'internal'} | ${undefined} | ${'true'} | ${'true'}
- ${'private'} | ${'public'} | ${undefined} | ${'true'} | ${'true'}
- ${'internal'} | ${'private'} | ${undefined} | ${'true'} | ${'true'}
- ${'internal'} | ${'internal'} | ${undefined} | ${undefined} | ${'true'}
- ${'internal'} | ${'public'} | ${undefined} | ${undefined} | ${'true'}
- ${'public'} | ${'private'} | ${undefined} | ${'true'} | ${'true'}
- ${'public'} | ${'internal'} | ${undefined} | ${undefined} | ${'true'}
- ${'public'} | ${'public'} | ${undefined} | ${undefined} | ${undefined}
+ project | namespace | privateIsDisabled | internalIsDisabled | publicIsDisabled | restrictedVisibilityLevels
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[]}
+ ${'private'} | ${'internal'} | ${undefined} | ${'true'} | ${'true'} | ${[]}
+ ${'private'} | ${'public'} | ${undefined} | ${'true'} | ${'true'} | ${[]}
+ ${'internal'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[]}
+ ${'internal'} | ${'internal'} | ${undefined} | ${undefined} | ${'true'} | ${[]}
+ ${'internal'} | ${'public'} | ${undefined} | ${undefined} | ${'true'} | ${[]}
+ ${'public'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[]}
+ ${'public'} | ${'internal'} | ${undefined} | ${undefined} | ${'true'} | ${[]}
+ ${'public'} | ${'public'} | ${undefined} | ${undefined} | ${undefined} | ${[]}
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[0]}
+ ${'internal'} | ${'internal'} | ${'true'} | ${undefined} | ${'true'} | ${[0]}
+ ${'public'} | ${'public'} | ${'true'} | ${undefined} | ${undefined} | ${[0]}
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[10]}
+ ${'internal'} | ${'internal'} | ${undefined} | ${'true'} | ${'true'} | ${[10]}
+ ${'public'} | ${'public'} | ${undefined} | ${'true'} | ${undefined} | ${[10]}
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[20]}
+ ${'internal'} | ${'internal'} | ${undefined} | ${undefined} | ${'true'} | ${[20]}
+ ${'public'} | ${'public'} | ${undefined} | ${undefined} | ${'true'} | ${[20]}
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[10, 20]}
+ ${'internal'} | ${'internal'} | ${undefined} | ${'true'} | ${'true'} | ${[10, 20]}
+ ${'public'} | ${'public'} | ${undefined} | ${'true'} | ${'true'} | ${[10, 20]}
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[0, 10, 20]}
+ ${'internal'} | ${'internal'} | ${undefined} | ${'true'} | ${'true'} | ${[0, 10, 20]}
+ ${'public'} | ${'public'} | ${undefined} | ${'true'} | ${'true'} | ${[0, 10, 20]}
`(
'sets appropriate radio button disabled state',
- async ({ project, namespace, privateIsDisabled, internalIsDisabled, publicIsDisabled }) => {
+ async ({
+ project,
+ namespace,
+ privateIsDisabled,
+ internalIsDisabled,
+ publicIsDisabled,
+ restrictedVisibilityLevels,
+ }) => {
mockGetRequest();
createComponent(
{
projectVisibility: project,
+ restrictedVisibilityLevels,
},
{
form: { fields: { namespace: { value: { visibility: namespace } } } },
@@ -235,7 +368,7 @@ describe('ForkForm component', () => {
});
describe('onSubmit', () => {
- beforeEach(() => {
+ const setupComponent = (fields = {}) => {
jest.spyOn(urlUtility, 'redirectTo').mockImplementation();
mockGetRequest();
@@ -245,9 +378,14 @@ describe('ForkForm component', () => {
namespaces: MOCK_NAMESPACES_RESPONSE,
form: {
state: true,
+ ...fields,
},
},
);
+ };
+
+ beforeEach(() => {
+ setupComponent();
});
const selectedMockNamespaceIndex = 1;
@@ -279,6 +417,22 @@ describe('ForkForm component', () => {
expect(urlUtility.redirectTo).not.toHaveBeenCalled();
});
+
+ it('does not make POST request if no visbility is checked', async () => {
+ jest.spyOn(axios, 'post');
+
+ setupComponent({
+ fields: {
+ visibility: {
+ value: null,
+ },
+ },
+ });
+
+ await submitForm();
+
+ expect(axios.post).not.toHaveBeenCalled();
+ });
});
describe('with valid form', () => {
@@ -330,7 +484,7 @@ describe('ForkForm component', () => {
expect(urlUtility.redirectTo).not.toHaveBeenCalled();
expect(createFlash).toHaveBeenCalledWith({
- message: dummyError,
+ message: 'An error occurred while forking the project. Please try again.',
});
});
});
diff --git a/spec/frontend/pages/projects/forks/new/components/fork_groups_list_spec.js b/spec/frontend/pages/projects/forks/new/components/fork_groups_list_spec.js
index e7ac837a4c8..9f8dbf3d542 100644
--- a/spec/frontend/pages/projects/forks/new/components/fork_groups_list_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/fork_groups_list_spec.js
@@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
+import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
import ForkGroupsList from '~/pages/projects/forks/new/components/fork_groups_list.vue';
import ForkGroupsListItem from '~/pages/projects/forks/new/components/fork_groups_list_item.vue';
diff --git a/spec/frontend/pages/projects/graphs/__snapshots__/code_coverage_spec.js.snap b/spec/frontend/pages/projects/graphs/__snapshots__/code_coverage_spec.js.snap
index c4c48ea7517..4ba9120d196 100644
--- a/spec/frontend/pages/projects/graphs/__snapshots__/code_coverage_spec.js.snap
+++ b/spec/frontend/pages/projects/graphs/__snapshots__/code_coverage_spec.js.snap
@@ -66,7 +66,7 @@ exports[`Code Coverage when fetching data is successful matches the snapshot 1`]
<gl-area-chart-stub
annotations=""
data="[object Object]"
- formattooltiptext="function () { [native code] }"
+ formattooltiptext="[Function]"
height="200"
includelegendavgmax="true"
legendaveragetext="Avg"
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap
index 350669433f0..59b42de2485 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap
+++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap
@@ -92,6 +92,7 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
aria-hidden="true"
class="gl-icon s16"
data-testid="completed-icon"
+ role="img"
>
<use
href="#check-circle-filled"
@@ -114,6 +115,7 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
aria-hidden="true"
class="gl-icon s16"
data-testid="completed-icon"
+ role="img"
>
<use
href="#check-circle-filled"
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap
index c9d8ab4566c..091edc7505c 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap
+++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap
@@ -81,6 +81,7 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
aria-hidden="true"
class="gl-text-green-500 gl-icon s16"
data-testid="completed-icon"
+ role="img"
>
<use
href="#check-circle-filled"
@@ -142,6 +143,7 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
aria-hidden="true"
class="gl-text-green-500 gl-icon s16"
data-testid="completed-icon"
+ role="img"
>
<use
href="#check-circle-filled"
diff --git a/spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js b/spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js
index 27cd0fe34bf..de0d70a07d7 100644
--- a/spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js
+++ b/spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js
@@ -1,3 +1,4 @@
+import { GlIcon } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { trimText } from 'helpers/text_helper';
import IntervalPatternInput from '~/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue';
@@ -27,6 +28,7 @@ describe('Interval Pattern Input Component', () => {
const findAllLabels = () => wrapper.findAll('label');
const findSelectedRadio = () =>
wrapper.findAll('input[type="radio"]').wrappers.find((x) => x.element.checked);
+ const findIcon = () => wrapper.findComponent(GlIcon);
const findSelectedRadioKey = () => findSelectedRadio()?.attributes('data-testid');
const selectEveryDayRadio = () => findEveryDayRadio().trigger('click');
const selectEveryWeekRadio = () => findEveryWeekRadio().trigger('click');
@@ -40,6 +42,11 @@ describe('Interval Pattern Input Component', () => {
wrapper = mount(IntervalPatternInput, {
propsData: { ...props },
+ provide: {
+ glFeatures: {
+ ciDailyLimitForPipelineSchedules: true,
+ },
+ },
data() {
return {
randomHour: data?.hour || mockHour,
@@ -202,4 +209,24 @@ describe('Interval Pattern Input Component', () => {
expect(findSelectedRadioKey()).toBe(customKey);
});
});
+
+ describe('Custom cron syntax quota info', () => {
+ it('the info message includes 5 minutes', () => {
+ createWrapper({ dailyLimit: '288' });
+
+ expect(findIcon().attributes('title')).toContain('5 minutes');
+ });
+
+ it('the info message includes 60 minutes', () => {
+ createWrapper({ dailyLimit: '24' });
+
+ expect(findIcon().attributes('title')).toContain('60 minutes');
+ });
+
+ it('the info message icon is not shown when there is no daily limit', () => {
+ createWrapper();
+
+ expect(findIcon().exists()).toBe(false);
+ });
+ });
});