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')
-rw-r--r--spec/frontend/pages/admin/application_settings/metrics_and_profiling/usage_statistics_spec.js57
-rw-r--r--spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap79
-rw-r--r--spec/frontend/pages/admin/users/components/delete_user_modal_spec.js167
-rw-r--r--spec/frontend/pages/admin/users/components/stubs/modal_stub.js23
-rw-r--r--spec/frontend/pages/admin/users/components/user_modal_manager_spec.js126
-rw-r--r--spec/frontend/pages/projects/forks/new/components/fork_form_spec.js23
-rw-r--r--spec/frontend/pages/projects/forks/new/components/fork_groups_list_item_spec.js4
-rw-r--r--spec/frontend/pages/projects/new/components/app_spec.js33
-rw-r--r--spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js25
9 files changed, 104 insertions, 433 deletions
diff --git a/spec/frontend/pages/admin/application_settings/metrics_and_profiling/usage_statistics_spec.js b/spec/frontend/pages/admin/application_settings/metrics_and_profiling/usage_statistics_spec.js
new file mode 100644
index 00000000000..858c7b76ac8
--- /dev/null
+++ b/spec/frontend/pages/admin/application_settings/metrics_and_profiling/usage_statistics_spec.js
@@ -0,0 +1,57 @@
+import initSetHelperText, {
+ HELPER_TEXT_SERVICE_PING_DISABLED,
+ HELPER_TEXT_SERVICE_PING_ENABLED,
+} from '~/pages/admin/application_settings/metrics_and_profiling/usage_statistics';
+
+describe('UsageStatistics', () => {
+ const FIXTURE = 'application_settings/usage.html';
+ let usagePingCheckBox;
+ let usagePingFeaturesCheckBox;
+ let usagePingFeaturesLabel;
+ let usagePingFeaturesHelperText;
+
+ beforeEach(() => {
+ loadFixtures(FIXTURE);
+ initSetHelperText();
+ usagePingCheckBox = document.getElementById('application_setting_usage_ping_enabled');
+ usagePingFeaturesCheckBox = document.getElementById(
+ 'application_setting_usage_ping_features_enabled',
+ );
+ usagePingFeaturesLabel = document.getElementById('service_ping_features_label');
+ usagePingFeaturesHelperText = document.getElementById('service_ping_features_helper_text');
+ });
+
+ const expectEnabledUsagePingFeaturesCheckBox = () => {
+ expect(usagePingFeaturesCheckBox.classList.contains('gl-cursor-not-allowed')).toBe(false);
+ expect(usagePingFeaturesHelperText.textContent).toEqual(HELPER_TEXT_SERVICE_PING_ENABLED);
+ };
+
+ const expectDisabledUsagePingFeaturesCheckBox = () => {
+ expect(usagePingFeaturesLabel.classList.contains('gl-cursor-not-allowed')).toBe(true);
+ expect(usagePingFeaturesHelperText.textContent).toEqual(HELPER_TEXT_SERVICE_PING_DISABLED);
+ };
+
+ describe('Registration Features checkbox', () => {
+ it('is disabled when Usage Ping checkbox is unchecked', () => {
+ expect(usagePingCheckBox.checked).toBe(false);
+ expectDisabledUsagePingFeaturesCheckBox();
+ });
+
+ it('is enabled when Usage Ping checkbox is checked', () => {
+ usagePingCheckBox.click();
+ expect(usagePingCheckBox.checked).toBe(true);
+ expectEnabledUsagePingFeaturesCheckBox();
+ });
+
+ it('is switched to disabled when Usage Ping checkbox is unchecked ', () => {
+ usagePingCheckBox.click();
+ usagePingFeaturesCheckBox.click();
+ expectEnabledUsagePingFeaturesCheckBox();
+
+ usagePingCheckBox.click();
+ expect(usagePingCheckBox.checked).toBe(false);
+ expect(usagePingFeaturesCheckBox.checked).toBe(false);
+ expectDisabledUsagePingFeaturesCheckBox();
+ });
+ });
+});
diff --git a/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap b/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
deleted file mode 100644
index 4c644a0d05f..00000000000
--- a/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
+++ /dev/null
@@ -1,79 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`User Operation confirmation modal renders modal with form included 1`] = `
-<div>
- <p>
- <gl-sprintf-stub
- message="content"
- />
- </p>
-
- <oncall-schedules-list-stub
- schedules="schedule1,schedule2"
- />
-
- <p>
- <gl-sprintf-stub
- message="To confirm, type %{username}"
- />
- </p>
-
- <form
- action="delete-url"
- method="post"
- >
- <input
- name="_method"
- type="hidden"
- value="delete"
- />
-
- <input
- name="authenticity_token"
- type="hidden"
- value="csrf"
- />
-
- <gl-form-input-stub
- autocomplete="off"
- autofocus=""
- name="username"
- type="text"
- value=""
- />
- </form>
- <gl-button-stub
- buttontextclasses=""
- category="primary"
- icon=""
- size="medium"
- variant="default"
- >
- Cancel
- </gl-button-stub>
-
- <gl-button-stub
- buttontextclasses=""
- category="secondary"
- disabled="true"
- icon=""
- size="medium"
- variant="danger"
- >
-
- secondaryAction
-
- </gl-button-stub>
-
- <gl-button-stub
- buttontextclasses=""
- category="primary"
- disabled="true"
- icon=""
- size="medium"
- variant="danger"
- >
- action
- </gl-button-stub>
-</div>
-`;
diff --git a/spec/frontend/pages/admin/users/components/delete_user_modal_spec.js b/spec/frontend/pages/admin/users/components/delete_user_modal_spec.js
deleted file mode 100644
index 93d9ee43179..00000000000
--- a/spec/frontend/pages/admin/users/components/delete_user_modal_spec.js
+++ /dev/null
@@ -1,167 +0,0 @@
-import { GlButton, GlFormInput } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import DeleteUserModal from '~/pages/admin/users/components/delete_user_modal.vue';
-import OncallSchedulesList from '~/vue_shared/components/oncall_schedules_list.vue';
-import ModalStub from './stubs/modal_stub';
-
-const TEST_DELETE_USER_URL = 'delete-url';
-const TEST_BLOCK_USER_URL = 'block-url';
-const TEST_CSRF = 'csrf';
-
-describe('User Operation confirmation modal', () => {
- let wrapper;
- let formSubmitSpy;
-
- const findButton = (variant, category) =>
- wrapper
- .findAll(GlButton)
- .filter((w) => w.attributes('variant') === variant && w.attributes('category') === category)
- .at(0);
- const findForm = () => wrapper.find('form');
- const findUsernameInput = () => wrapper.findComponent(GlFormInput);
- const findPrimaryButton = () => findButton('danger', 'primary');
- const findSecondaryButton = () => findButton('danger', 'secondary');
- const findAuthenticityToken = () => new FormData(findForm().element).get('authenticity_token');
- const getUsername = () => findUsernameInput().attributes('value');
- const getMethodParam = () => new FormData(findForm().element).get('_method');
- const getFormAction = () => findForm().attributes('action');
- const findOnCallSchedulesList = () => wrapper.findComponent(OncallSchedulesList);
-
- const setUsername = (username) => {
- findUsernameInput().vm.$emit('input', username);
- };
-
- const username = 'username';
- const badUsername = 'bad_username';
- const oncallSchedules = '["schedule1", "schedule2"]';
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(DeleteUserModal, {
- propsData: {
- username,
- title: 'title',
- content: 'content',
- action: 'action',
- secondaryAction: 'secondaryAction',
- deleteUserUrl: TEST_DELETE_USER_URL,
- blockUserUrl: TEST_BLOCK_USER_URL,
- csrfToken: TEST_CSRF,
- oncallSchedules,
- ...props,
- },
- stubs: {
- GlModal: ModalStub,
- },
- });
- };
-
- beforeEach(() => {
- formSubmitSpy = jest.spyOn(HTMLFormElement.prototype, 'submit').mockImplementation();
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- it('renders modal with form included', () => {
- createComponent();
- expect(wrapper.element).toMatchSnapshot();
- });
-
- describe('on created', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('has disabled buttons', () => {
- expect(findPrimaryButton().attributes('disabled')).toBeTruthy();
- expect(findSecondaryButton().attributes('disabled')).toBeTruthy();
- });
- });
-
- describe('with incorrect username', () => {
- beforeEach(() => {
- createComponent();
- setUsername(badUsername);
-
- return wrapper.vm.$nextTick();
- });
-
- it('shows incorrect username', () => {
- expect(getUsername()).toEqual(badUsername);
- });
-
- it('has disabled buttons', () => {
- expect(findPrimaryButton().attributes('disabled')).toBeTruthy();
- expect(findSecondaryButton().attributes('disabled')).toBeTruthy();
- });
- });
-
- describe('with correct username', () => {
- beforeEach(() => {
- createComponent();
- setUsername(username);
-
- return wrapper.vm.$nextTick();
- });
-
- it('shows correct username', () => {
- expect(getUsername()).toEqual(username);
- });
-
- it('has enabled buttons', () => {
- expect(findPrimaryButton().attributes('disabled')).toBeFalsy();
- expect(findSecondaryButton().attributes('disabled')).toBeFalsy();
- });
-
- describe('when primary action is submitted', () => {
- beforeEach(() => {
- findPrimaryButton().vm.$emit('click');
-
- return wrapper.vm.$nextTick();
- });
-
- it('clears the input', () => {
- expect(getUsername()).toEqual('');
- });
-
- it('has correct form attributes and calls submit', () => {
- expect(getFormAction()).toBe(TEST_DELETE_USER_URL);
- expect(getMethodParam()).toBe('delete');
- expect(findAuthenticityToken()).toBe(TEST_CSRF);
- expect(formSubmitSpy).toHaveBeenCalled();
- });
- });
-
- describe('when secondary action is submitted', () => {
- beforeEach(() => {
- findSecondaryButton().vm.$emit('click');
-
- return wrapper.vm.$nextTick();
- });
-
- it('has correct form attributes and calls submit', () => {
- expect(getFormAction()).toBe(TEST_BLOCK_USER_URL);
- expect(getMethodParam()).toBe('put');
- expect(findAuthenticityToken()).toBe(TEST_CSRF);
- expect(formSubmitSpy).toHaveBeenCalled();
- });
- });
- });
-
- describe('Related oncall-schedules list', () => {
- it('does NOT render the list when user has no related schedules', () => {
- createComponent({ oncallSchedules: '[]' });
- expect(findOnCallSchedulesList().exists()).toBe(false);
- });
-
- it('renders the list when user has related schedules', () => {
- createComponent();
-
- const schedules = findOnCallSchedulesList();
- expect(schedules.exists()).toBe(true);
- expect(schedules.props('schedules')).toEqual(JSON.parse(oncallSchedules));
- });
- });
-});
diff --git a/spec/frontend/pages/admin/users/components/stubs/modal_stub.js b/spec/frontend/pages/admin/users/components/stubs/modal_stub.js
deleted file mode 100644
index 4dc55e909a0..00000000000
--- a/spec/frontend/pages/admin/users/components/stubs/modal_stub.js
+++ /dev/null
@@ -1,23 +0,0 @@
-const ModalStub = {
- inheritAttrs: false,
- name: 'glmodal-stub',
- data() {
- return {
- showWasCalled: false,
- };
- },
- methods: {
- show() {
- this.showWasCalled = true;
- },
- hide() {},
- },
- render(h) {
- const children = [this.$slots.default, this.$slots['modal-footer']]
- .filter(Boolean)
- .reduce((acc, nodes) => acc.concat(nodes), []);
- return h('div', children);
- },
-};
-
-export default ModalStub;
diff --git a/spec/frontend/pages/admin/users/components/user_modal_manager_spec.js b/spec/frontend/pages/admin/users/components/user_modal_manager_spec.js
deleted file mode 100644
index 3669bc40d7e..00000000000
--- a/spec/frontend/pages/admin/users/components/user_modal_manager_spec.js
+++ /dev/null
@@ -1,126 +0,0 @@
-import { mount } from '@vue/test-utils';
-import UserModalManager from '~/pages/admin/users/components/user_modal_manager.vue';
-import ModalStub from './stubs/modal_stub';
-
-describe('Users admin page Modal Manager', () => {
- let wrapper;
-
- const modalConfiguration = {
- action1: {
- title: 'action1',
- content: 'Action Modal 1',
- },
- action2: {
- title: 'action2',
- content: 'Action Modal 2',
- },
- };
-
- const findModal = () => wrapper.find({ ref: 'modal' });
-
- const createComponent = (props = {}) => {
- wrapper = mount(UserModalManager, {
- propsData: {
- selector: '.js-delete-user-modal-button',
- modalConfiguration,
- csrfToken: 'dummyCSRF',
- ...props,
- },
- stubs: {
- DeleteUserModal: ModalStub,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('render behavior', () => {
- it('does not renders modal when initialized', () => {
- createComponent();
- expect(findModal().exists()).toBeFalsy();
- });
-
- it('throws if action has no proper configuration', () => {
- createComponent({
- modalConfiguration: {},
- });
- expect(() => wrapper.vm.show({ glModalAction: 'action1' })).toThrow();
- });
-
- it('renders modal with expected props when valid configuration is passed', () => {
- createComponent();
- wrapper.vm.show({
- glModalAction: 'action1',
- extraProp: 'extraPropValue',
- });
-
- return wrapper.vm.$nextTick().then(() => {
- const modal = findModal();
- expect(modal.exists()).toBeTruthy();
- expect(modal.vm.$attrs.csrfToken).toEqual('dummyCSRF');
- expect(modal.vm.$attrs.extraProp).toEqual('extraPropValue');
- expect(modal.vm.showWasCalled).toBeTruthy();
- });
- });
- });
-
- describe('click handling', () => {
- let button;
- let button2;
-
- const createButtons = () => {
- button = document.createElement('button');
- button2 = document.createElement('button');
- button.setAttribute('class', 'js-delete-user-modal-button');
- button.setAttribute('data-username', 'foo');
- button.setAttribute('data-gl-modal-action', 'action1');
- button.setAttribute('data-block-user-url', '/block');
- button.setAttribute('data-delete-user-url', '/delete');
- document.body.appendChild(button);
- document.body.appendChild(button2);
- };
- const removeButtons = () => {
- button.remove();
- button = null;
- button2.remove();
- button2 = null;
- };
-
- beforeEach(() => {
- createButtons();
- createComponent();
- });
-
- afterEach(() => {
- removeButtons();
- });
-
- it('renders the modal when the button is clicked', async () => {
- button.click();
-
- await wrapper.vm.$nextTick();
-
- expect(findModal().exists()).toBe(true);
- });
-
- it('does not render the modal when a misconfigured button is clicked', async () => {
- button.removeAttribute('data-gl-modal-action');
- button.click();
-
- await wrapper.vm.$nextTick();
-
- expect(findModal().exists()).toBe(false);
- });
-
- it('does not render the modal when a button without the selector class is clicked', async () => {
- button2.click();
-
- await wrapper.vm.$nextTick();
-
- expect(findModal().exists()).toBe(false);
- });
- });
-});
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 c80ccfa8256..dd617b1ffc2 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
@@ -29,10 +29,12 @@ describe('ForkForm component', () => {
const MOCK_NAMESPACES_RESPONSE = [
{
name: 'one',
+ full_name: 'one-group/one',
id: 1,
},
{
name: 'two',
+ full_name: 'two-group/two',
id: 2,
},
];
@@ -155,7 +157,7 @@ describe('ForkForm component', () => {
describe('forks namespaces', () => {
beforeEach(() => {
mockGetRequest({ namespaces: MOCK_NAMESPACES_RESPONSE });
- createComponent();
+ createFullComponent();
});
it('make GET request from endpoint', async () => {
@@ -178,8 +180,23 @@ describe('ForkForm component', () => {
const optionsArray = findForkUrlInput().findAll('option');
expect(optionsArray).toHaveLength(MOCK_NAMESPACES_RESPONSE.length + 1);
- expect(optionsArray.at(1).text()).toBe(MOCK_NAMESPACES_RESPONSE[0].name);
- expect(optionsArray.at(2).text()).toBe(MOCK_NAMESPACES_RESPONSE[1].name);
+ expect(optionsArray.at(1).text()).toBe(MOCK_NAMESPACES_RESPONSE[0].full_name);
+ expect(optionsArray.at(2).text()).toBe(MOCK_NAMESPACES_RESPONSE[1].full_name);
+ });
+
+ it('set namespaces in alphabetical order', async () => {
+ const namespace = {
+ name: 'three',
+ full_name: 'aaa/three',
+ id: 3,
+ };
+ mockGetRequest({
+ namespaces: [...MOCK_NAMESPACES_RESPONSE, namespace],
+ });
+ createComponent();
+ await axios.waitForAll();
+
+ expect(wrapper.vm.namespaces).toEqual([namespace, ...MOCK_NAMESPACES_RESPONSE]);
});
});
diff --git a/spec/frontend/pages/projects/forks/new/components/fork_groups_list_item_spec.js b/spec/frontend/pages/projects/forks/new/components/fork_groups_list_item_spec.js
index b5425fa6f2e..490dafed4ae 100644
--- a/spec/frontend/pages/projects/forks/new/components/fork_groups_list_item_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/fork_groups_list_item_spec.js
@@ -34,10 +34,10 @@ describe('Fork groups list item component', () => {
});
};
- it('renders pending removal badge if applicable', () => {
+ it('renders pending deletion badge if applicable', () => {
createWrapper({ group: { ...DEFAULT_GROUP_DATA, marked_for_deletion: true } });
- expect(wrapper.find(GlBadge).text()).toBe('pending removal');
+ expect(wrapper.find(GlBadge).text()).toBe('pending deletion');
});
it('renders go to fork button if has forked project', () => {
diff --git a/spec/frontend/pages/projects/new/components/app_spec.js b/spec/frontend/pages/projects/new/components/app_spec.js
index b604e636243..ab8c6d529a8 100644
--- a/spec/frontend/pages/projects/new/components/app_spec.js
+++ b/spec/frontend/pages/projects/new/components/app_spec.js
@@ -1,13 +1,10 @@
import { shallowMount } from '@vue/test-utils';
-import { assignGitlabExperiment } from 'helpers/experimentation_helper';
import App from '~/pages/projects/new/components/app.vue';
import NewNamespacePage from '~/vue_shared/new_namespace/new_namespace_page.vue';
describe('Experimental new project creation app', () => {
let wrapper;
- const findNewNamespacePage = () => wrapper.findComponent(NewNamespacePage);
-
const createComponent = (propsData) => {
wrapper = shallowMount(App, { propsData });
};
@@ -16,36 +13,6 @@ describe('Experimental new project creation app', () => {
wrapper.destroy();
});
- describe('new_repo experiment', () => {
- it('passes new_repo experiment', () => {
- createComponent();
-
- expect(findNewNamespacePage().props().experiment).toBe('new_repo');
- });
-
- describe('when in the candidate variant', () => {
- assignGitlabExperiment('new_repo', 'candidate');
-
- it('has "repository" in the panel title', () => {
- createComponent();
-
- expect(findNewNamespacePage().props().panels[0].title).toBe(
- 'Create blank project/repository',
- );
- });
- });
-
- describe('when in the control variant', () => {
- assignGitlabExperiment('new_repo', 'control');
-
- it('has "project" in the panel title', () => {
- createComponent();
-
- expect(findNewNamespacePage().props().panels[0].title).toBe('Create blank project');
- });
- });
- });
-
it('passes custom new project guideline text to underlying component', () => {
const DEMO_GUIDELINES = 'Demo guidelines';
const guidelineSelector = '#new-project-guideline';
diff --git a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
index 878721666ff..4c253f0610b 100644
--- a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
+++ b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
@@ -94,6 +94,8 @@ describe('Settings Panel', () => {
const findPackageSettings = () => wrapper.find({ ref: 'package-settings' });
const findPackagesEnabledInput = () => wrapper.find('[name="project[packages_enabled]"]');
const findPagesSettings = () => wrapper.find({ ref: 'pages-settings' });
+ const findPagesAccessLevels = () =>
+ wrapper.find('[name="project[project_feature_attributes][pages_access_level]"]');
const findEmailSettings = () => wrapper.find({ ref: 'email-settings' });
const findShowDefaultAwardEmojis = () =>
wrapper.find('input[name="project[project_setting_attributes][show_default_award_emojis]"]');
@@ -479,6 +481,29 @@ describe('Settings Panel', () => {
describe('Pages', () => {
it.each`
+ visibilityLevel | pagesAccessControlForced | output
+ ${visibilityOptions.PRIVATE} | ${true} | ${[[visibilityOptions.INTERNAL, 'Only Project Members'], [visibilityOptions.PUBLIC, 'Everyone With Access']]}
+ ${visibilityOptions.PRIVATE} | ${false} | ${[[visibilityOptions.INTERNAL, 'Only Project Members'], [visibilityOptions.PUBLIC, 'Everyone With Access'], [30, 'Everyone']]}
+ ${visibilityOptions.INTERNAL} | ${true} | ${[[visibilityOptions.INTERNAL, 'Only Project Members'], [visibilityOptions.PUBLIC, 'Everyone With Access']]}
+ ${visibilityOptions.INTERNAL} | ${false} | ${[[visibilityOptions.INTERNAL, 'Only Project Members'], [visibilityOptions.PUBLIC, 'Everyone With Access'], [30, 'Everyone']]}
+ ${visibilityOptions.PUBLIC} | ${true} | ${[[visibilityOptions.INTERNAL, 'Only Project Members'], [visibilityOptions.PUBLIC, 'Everyone With Access']]}
+ ${visibilityOptions.PUBLIC} | ${false} | ${[[visibilityOptions.INTERNAL, 'Only Project Members'], [visibilityOptions.PUBLIC, 'Everyone With Access'], [30, 'Everyone']]}
+ `(
+ 'renders correct options when pagesAccessControlForced is $pagesAccessControlForced and visibilityLevel is $visibilityLevel',
+ async ({ visibilityLevel, pagesAccessControlForced, output }) => {
+ wrapper = mountComponent({
+ pagesAvailable: true,
+ pagesAccessControlEnabled: true,
+ pagesAccessControlForced,
+ });
+
+ await findProjectVisibilityLevelInput().trigger('change', visibilityLevel);
+
+ expect(findPagesAccessLevels().props('options')).toStrictEqual(output);
+ },
+ );
+
+ it.each`
pagesAvailable | pagesAccessControlEnabled | visibility
${true} | ${true} | ${'show'}
${true} | ${false} | ${'hide'}