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>2022-09-20 02:18:09 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-09-20 02:18:09 +0300
commit6ed4ec3e0b1340f96b7c043ef51d1b33bbe85fde (patch)
treedc4d20fe6064752c0bd323187252c77e0a89144b /spec/frontend/pages
parent9868dae7fc0655bd7ce4a6887d4e6d487690eeed (diff)
Add latest changes from gitlab-org/gitlab@15-4-stable-eev15.4.0-rc42
Diffstat (limited to 'spec/frontend/pages')
-rw-r--r--spec/frontend/pages/admin/application_settings/metrics_and_profiling/usage_statistics_spec.js2
-rw-r--r--spec/frontend/pages/import/bitbucket_server/components/bitbucket_server_status_table_spec.js4
-rw-r--r--spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js8
-rw-r--r--spec/frontend/pages/import/history/components/import_error_details_spec.js6
-rw-r--r--spec/frontend/pages/import/history/components/import_history_app_spec.js10
-rw-r--r--spec/frontend/pages/profiles/show/emoji_menu_spec.js115
-rw-r--r--spec/frontend/pages/projects/forks/new/components/fork_form_spec.js173
-rw-r--r--spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js177
-rw-r--r--spec/frontend/pages/projects/graphs/code_coverage_spec.js8
-rw-r--r--spec/frontend/pages/projects/merge_requests/edit/update_form_spec.js59
-rw-r--r--spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js2
-rw-r--r--spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js223
-rw-r--r--spec/frontend/pages/shared/wikis/components/wiki_content_spec.js2
-rw-r--r--spec/frontend/pages/shared/wikis/components/wiki_form_spec.js50
14 files changed, 489 insertions, 350 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
index 3a52c243867..3c512cfd6ae 100644
--- 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
@@ -48,7 +48,7 @@ describe('UsageStatistics', () => {
expectEnabledservicePingFeaturesCheckBox();
});
- it('is switched to disabled when Service Ping checkbox is unchecked ', () => {
+ it('is switched to disabled when Service Ping checkbox is unchecked', () => {
servicePingCheckBox.click();
servicePingFeaturesCheckBox.click();
expectEnabledservicePingFeaturesCheckBox();
diff --git a/spec/frontend/pages/import/bitbucket_server/components/bitbucket_server_status_table_spec.js b/spec/frontend/pages/import/bitbucket_server/components/bitbucket_server_status_table_spec.js
index 7a8a249cb2a..b020caa3010 100644
--- a/spec/frontend/pages/import/bitbucket_server/components/bitbucket_server_status_table_spec.js
+++ b/spec/frontend/pages/import/bitbucket_server/components/bitbucket_server_status_table_spec.js
@@ -14,7 +14,7 @@ describe('BitbucketServerStatusTable', () => {
const findReconfigureButton = () =>
wrapper
- .findAll(GlButton)
+ .findAllComponents(GlButton)
.filter((w) => w.props().variant === 'info')
.at(0);
@@ -36,7 +36,7 @@ describe('BitbucketServerStatusTable', () => {
it('renders bitbucket status table component', () => {
createComponent();
- expect(wrapper.find(BitbucketStatusTable).exists()).toBe(true);
+ expect(wrapper.findComponent(BitbucketStatusTable).exists()).toBe(true);
});
it('renders Reconfigure button', async () => {
diff --git a/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js b/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
index a850b1655f7..1790a9c9bf5 100644
--- a/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
+++ b/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
@@ -84,7 +84,7 @@ describe('BulkImportsHistoryApp', () => {
describe('general behavior', () => {
it('renders loading state when loading', () => {
createComponent();
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
it('renders empty state when no data is available', async () => {
@@ -92,8 +92,8 @@ describe('BulkImportsHistoryApp', () => {
createComponent();
await axios.waitForAll();
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
- expect(wrapper.find(GlEmptyState).exists()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
+ expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true);
});
it('renders table with data when history is available', async () => {
@@ -101,7 +101,7 @@ describe('BulkImportsHistoryApp', () => {
createComponent();
await axios.waitForAll();
- const table = wrapper.find(GlTable);
+ const table = wrapper.findComponent(GlTable);
expect(table.exists()).toBe(true);
// can't use .props() or .attributes() here
expect(table.vm.$attrs.items).toHaveLength(DUMMY_RESPONSE.length);
diff --git a/spec/frontend/pages/import/history/components/import_error_details_spec.js b/spec/frontend/pages/import/history/components/import_error_details_spec.js
index 4ff3f0361cf..82a3e11186e 100644
--- a/spec/frontend/pages/import/history/components/import_error_details_spec.js
+++ b/spec/frontend/pages/import/history/components/import_error_details_spec.js
@@ -41,7 +41,7 @@ describe('ImportErrorDetails', () => {
describe('general behavior', () => {
it('renders loading state when loading', () => {
createComponent();
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
it('renders import_error if it is available', async () => {
@@ -50,7 +50,7 @@ describe('ImportErrorDetails', () => {
createComponent();
await axios.waitForAll();
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
expect(wrapper.find('pre').text()).toBe(FAKE_IMPORT_ERROR);
});
@@ -59,7 +59,7 @@ describe('ImportErrorDetails', () => {
createComponent();
await axios.waitForAll();
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
expect(wrapper.find('pre').text()).toBe('No additional information provided.');
});
});
diff --git a/spec/frontend/pages/import/history/components/import_history_app_spec.js b/spec/frontend/pages/import/history/components/import_history_app_spec.js
index 0d821b114cf..5030adae2fa 100644
--- a/spec/frontend/pages/import/history/components/import_history_app_spec.js
+++ b/spec/frontend/pages/import/history/components/import_history_app_spec.js
@@ -79,7 +79,7 @@ describe('ImportHistoryApp', () => {
describe('general behavior', () => {
it('renders loading state when loading', () => {
createComponent();
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
it('renders empty state when no data is available', async () => {
@@ -87,8 +87,8 @@ describe('ImportHistoryApp', () => {
createComponent();
await axios.waitForAll();
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
- expect(wrapper.find(GlEmptyState).exists()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
+ expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true);
});
it('renders table with data when history is available', async () => {
@@ -96,7 +96,7 @@ describe('ImportHistoryApp', () => {
createComponent();
await axios.waitForAll();
- const table = wrapper.find(GlTable);
+ const table = wrapper.findComponent(GlTable);
expect(table.exists()).toBe(true);
expect(table.props().items).toStrictEqual(DUMMY_RESPONSE);
});
@@ -127,7 +127,7 @@ describe('ImportHistoryApp', () => {
expect(mock.history.get.length).toBe(1);
expect(mock.history.get[0].params).toStrictEqual(expect.objectContaining({ page: NEW_PAGE }));
- expect(wrapper.find(GlTable).props().items).toStrictEqual(FAKE_NEXT_PAGE_REPLY);
+ expect(wrapper.findComponent(GlTable).props().items).toStrictEqual(FAKE_NEXT_PAGE_REPLY);
});
});
diff --git a/spec/frontend/pages/profiles/show/emoji_menu_spec.js b/spec/frontend/pages/profiles/show/emoji_menu_spec.js
deleted file mode 100644
index fa6e7e51a60..00000000000
--- a/spec/frontend/pages/profiles/show/emoji_menu_spec.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import $ from 'jquery';
-import { TEST_HOST } from 'helpers/test_constants';
-import axios from '~/lib/utils/axios_utils';
-import EmojiMenu from '~/pages/profiles/show/emoji_menu';
-
-describe('EmojiMenu', () => {
- const dummyEmojiTag = '<dummy></tag>';
- const dummyToggleButtonSelector = '.toggle-button-selector';
- const dummyMenuClass = 'dummy-menu-class';
-
- let emojiMenu;
- let dummySelectEmojiCallback;
- let dummyEmojiList;
-
- beforeEach(() => {
- dummySelectEmojiCallback = jest.fn().mockName('dummySelectEmojiCallback');
- dummyEmojiList = {
- glEmojiTag() {
- return dummyEmojiTag;
- },
- normalizeEmojiName(emoji) {
- return emoji;
- },
- isEmojiNameValid() {
- return true;
- },
- getEmojiCategoryMap() {
- return { dummyCategory: [] };
- },
- };
-
- emojiMenu = new EmojiMenu(
- dummyEmojiList,
- dummyToggleButtonSelector,
- dummyMenuClass,
- dummySelectEmojiCallback,
- );
- });
-
- afterEach(() => {
- emojiMenu.destroy();
- });
-
- describe('addAward', () => {
- const dummyAwardUrl = `${TEST_HOST}/award/url`;
- const dummyEmoji = 'tropical_fish';
- const dummyVotesBlock = () => $('<div />');
-
- it('calls selectEmojiCallback', async () => {
- expect(dummySelectEmojiCallback).not.toHaveBeenCalled();
-
- await emojiMenu.addAward(dummyVotesBlock(), dummyAwardUrl, dummyEmoji, false);
- expect(dummySelectEmojiCallback).toHaveBeenCalledWith(dummyEmoji, dummyEmojiTag);
- });
-
- it('does not make an axios request', async () => {
- jest.spyOn(axios, 'request').mockReturnValue();
-
- await emojiMenu.addAward(dummyVotesBlock(), dummyAwardUrl, dummyEmoji, false);
- expect(axios.request).not.toHaveBeenCalled();
- });
- });
-
- describe('bindEvents', () => {
- beforeEach(() => {
- jest.spyOn(emojiMenu, 'registerEventListener').mockReturnValue();
- });
-
- it('binds event listeners to custom toggle button', () => {
- emojiMenu.bindEvents();
-
- expect(emojiMenu.registerEventListener).toHaveBeenCalledWith(
- 'one',
- expect.anything(),
- 'mouseenter focus',
- dummyToggleButtonSelector,
- 'mouseenter focus',
- expect.anything(),
- );
-
- expect(emojiMenu.registerEventListener).toHaveBeenCalledWith(
- 'on',
- expect.anything(),
- 'click',
- dummyToggleButtonSelector,
- expect.anything(),
- );
- });
-
- it('binds event listeners to custom menu class', () => {
- emojiMenu.bindEvents();
-
- expect(emojiMenu.registerEventListener).toHaveBeenCalledWith(
- 'on',
- expect.anything(),
- 'click',
- `.js-awards-block .js-emoji-btn, .${dummyMenuClass} .js-emoji-btn`,
- expect.anything(),
- );
- });
- });
-
- describe('createEmojiMenu', () => {
- it('renders the menu with custom menu class', () => {
- const menuElement = () =>
- document.body.querySelector(`.emoji-menu.${dummyMenuClass} .emoji-menu-content`);
-
- expect(menuElement()).toBe(null);
-
- emojiMenu.createEmojiMenu();
-
- expect(menuElement()).not.toBe(null);
- });
- });
-});
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 2a0fde45384..f221a90da61 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
@@ -4,11 +4,14 @@ import { mount, shallowMount } from '@vue/test-utils';
import axios from 'axios';
import AxiosMockAdapter from 'axios-mock-adapter';
import { kebabCase } from 'lodash';
-import { nextTick } from 'vue';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
import createFlash from '~/flash';
-import httpStatus from '~/lib/utils/http_status';
import * as urlUtility from '~/lib/utils/url_utility';
import ForkForm from '~/pages/projects/forks/new/components/fork_form.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import searchQuery from '~/pages/projects/forks/new/queries/search_forkable_namespaces.query.graphql';
+import ProjectNamespace from '~/pages/projects/forks/new/components/project_namespace.vue';
jest.mock('~/flash');
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
@@ -16,6 +19,7 @@ jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
describe('ForkForm component', () => {
let wrapper;
let axiosMock;
+ let mockQueryResponse;
const PROJECT_VISIBILITY_TYPE = {
private:
@@ -24,26 +28,11 @@ describe('ForkForm component', () => {
public: 'Public The project can be accessed without any authentication.',
};
- const GON_GITLAB_URL = 'https://gitlab.com';
const GON_API_VERSION = 'v7';
- const MOCK_NAMESPACES_RESPONSE = [
- {
- name: 'one',
- full_name: 'one-group/one',
- id: 1,
- },
- {
- name: 'two',
- full_name: 'two-group/two',
- id: 2,
- },
- ];
-
const DEFAULT_PROVIDE = {
newGroupPath: 'some/groups/path',
visibilityHelpPath: 'some/visibility/help/path',
- endpoint: '/some/project-full-path/-/forks/new.json',
projectFullPath: '/some/project-full-path',
projectId: '10',
projectName: 'Project Name',
@@ -53,12 +42,44 @@ describe('ForkForm component', () => {
restrictedVisibilityLevels: [],
};
- const mockGetRequest = (data = {}, statusCode = httpStatus.OK) => {
- axiosMock.onGet(DEFAULT_PROVIDE.endpoint).replyOnce(statusCode, data);
- };
+ Vue.use(VueApollo);
const createComponentFactory = (mountFn) => (provide = {}, data = {}) => {
+ const queryResponse = {
+ project: {
+ id: 'gid://gitlab/Project/1',
+ forkTargets: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Group/21',
+ fullPath: 'flightjs',
+ name: 'Flight JS',
+ visibility: 'public',
+ },
+ {
+ id: 'gid://gitlab/Namespace/4',
+ fullPath: 'root',
+ name: 'Administrator',
+ visibility: 'public',
+ },
+ ],
+ },
+ },
+ };
+
+ mockQueryResponse = jest.fn().mockResolvedValue({ data: queryResponse });
+ const requestHandlers = [[searchQuery, mockQueryResponse]];
+ const apolloProvider = createMockApollo(requestHandlers);
+
+ apolloProvider.clients.defaultClient.cache.writeQuery({
+ query: searchQuery,
+ data: {
+ ...queryResponse,
+ },
+ });
+
wrapper = mountFn(ForkForm, {
+ apolloProvider,
provide: {
...DEFAULT_PROVIDE,
...provide,
@@ -83,7 +104,6 @@ describe('ForkForm component', () => {
beforeEach(() => {
axiosMock = new AxiosMockAdapter(axios);
window.gon = {
- gitlab_url: GON_GITLAB_URL,
api_version: GON_API_VERSION,
};
});
@@ -93,12 +113,11 @@ 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"]');
const findForkNameInput = () => wrapper.find('[data-testid="fork-name-input"]');
- const findForkUrlInput = () => wrapper.find('[data-testid="fork-url-input"]');
+ const findForkUrlInput = () => wrapper.findComponent(ProjectNamespace);
const findForkSlugInput = () => wrapper.find('[data-testid="fork-slug-input"]');
const findForkDescriptionTextarea = () =>
wrapper.find('[data-testid="fork-description-textarea"]');
@@ -106,7 +125,6 @@ describe('ForkForm component', () => {
wrapper.find('[data-testid="fork-visibility-radio-group"]');
it('will go to projectFullPath when click cancel button', () => {
- mockGetRequest();
createComponent();
const { projectFullPath } = DEFAULT_PROVIDE;
@@ -115,8 +133,13 @@ describe('ForkForm component', () => {
expect(cancelButton.attributes('href')).toBe(projectFullPath);
});
+ const selectedMockNamespace = { name: 'two', full_name: 'two-group/two', id: 2 };
+
+ const fillForm = () => {
+ findForkUrlInput().vm.$emit('select', selectedMockNamespace);
+ };
+
it('has input with csrf token', () => {
- mockGetRequest();
createComponent();
expect(wrapper.find('input[name="authenticity_token"]').attributes('value')).toBe(
@@ -125,7 +148,6 @@ describe('ForkForm component', () => {
});
it('pre-populate form from project props', () => {
- mockGetRequest();
createComponent();
expect(findForkNameInput().attributes('value')).toBe(DEFAULT_PROVIDE.projectName);
@@ -135,75 +157,19 @@ describe('ForkForm component', () => {
);
});
- it('sets project URL prepend text with gon.gitlab_url', () => {
- mockGetRequest();
- createComponent();
-
- expect(wrapper.find(GlFormInputGroup).text()).toContain(`${GON_GITLAB_URL}/`);
- });
-
it('will have required attribute for required fields', () => {
- mockGetRequest();
createComponent();
expect(findForkNameInput().attributes('required')).not.toBeUndefined();
- expect(findForkUrlInput().attributes('required')).not.toBeUndefined();
expect(findForkSlugInput().attributes('required')).not.toBeUndefined();
expect(findVisibilityRadioGroup().attributes('required')).not.toBeUndefined();
expect(findForkDescriptionTextarea().attributes('required')).toBeUndefined();
});
- describe('forks namespaces', () => {
- beforeEach(() => {
- mockGetRequest({ namespaces: MOCK_NAMESPACES_RESPONSE });
- createFullComponent();
- });
-
- it('make GET request from endpoint', async () => {
- await axios.waitForAll();
-
- expect(axiosMock.history.get[0].url).toBe(DEFAULT_PROVIDE.endpoint);
- });
-
- it('generate default option', async () => {
- await axios.waitForAll();
-
- const optionsArray = findForkUrlInput().findAll('option');
-
- expect(optionsArray.at(0).text()).toBe('Select a namespace');
- });
-
- it('populate project url namespace options', async () => {
- await axios.waitForAll();
-
- const optionsArray = findForkUrlInput().findAll('option');
-
- expect(optionsArray).toHaveLength(MOCK_NAMESPACES_RESPONSE.length + 1);
- 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]);
- });
- });
-
describe('project slug', () => {
const projectPath = 'some other project slug';
beforeEach(() => {
- mockGetRequest();
createComponent({
projectPath,
});
@@ -232,10 +198,9 @@ describe('ForkForm component', () => {
describe('visibility level', () => {
it('displays the correct description', () => {
- mockGetRequest();
createComponent();
- const formRadios = wrapper.findAll(GlFormRadio);
+ const formRadios = wrapper.findAllComponents(GlFormRadio);
Object.keys(PROJECT_VISIBILITY_TYPE).forEach((visibilityType, index) => {
expect(formRadios.at(index).text()).toBe(PROJECT_VISIBILITY_TYPE[visibilityType]);
@@ -243,10 +208,9 @@ describe('ForkForm component', () => {
});
it('displays all 3 visibility levels', () => {
- mockGetRequest();
createComponent();
- expect(wrapper.findAll(GlFormRadio)).toHaveLength(3);
+ expect(wrapper.findAllComponents(GlFormRadio)).toHaveLength(3);
});
describe('when the namespace is changed', () => {
@@ -262,16 +226,12 @@ describe('ForkForm component', () => {
},
];
- 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();
+ fillForm();
await nextTick();
expect(getByRole(wrapper.element, 'radio', { name: /private/i }).checked).toBe(true);
@@ -280,8 +240,7 @@ describe('ForkForm component', () => {
it('sets the visibility to be null when restrictedVisibilityLevels is set', async () => {
createFullComponent({ restrictedVisibilityLevels: [10] }, { namespaces });
- await findFormSelectOptions().at(1).setSelected();
-
+ fillForm();
await nextTick();
const container = getByRole(wrapper.element, 'radiogroup', { name: /visibility/i });
@@ -315,8 +274,7 @@ describe('ForkForm component', () => {
${'public'} | ${[0, 20]}
${'public'} | ${[10, 20]}
${'public'} | ${[0, 10, 20]}
- `('checks the correct radio button', async ({ project, restrictedVisibilityLevels }) => {
- mockGetRequest();
+ `('checks the correct radio button', ({ project, restrictedVisibilityLevels }) => {
createFullComponent({
projectVisibility: project,
restrictedVisibilityLevels,
@@ -357,7 +315,7 @@ describe('ForkForm component', () => {
${'public'} | ${'public'} | ${undefined} | ${'true'} | ${'true'} | ${[0, 10, 20]}
`(
'sets appropriate radio button disabled state',
- async ({
+ ({
project,
namespace,
privateIsDisabled,
@@ -365,7 +323,6 @@ describe('ForkForm component', () => {
publicIsDisabled,
restrictedVisibilityLevels,
}) => {
- mockGetRequest();
createComponent(
{
projectVisibility: project,
@@ -387,11 +344,9 @@ describe('ForkForm component', () => {
const setupComponent = (fields = {}) => {
jest.spyOn(urlUtility, 'redirectTo').mockImplementation();
- mockGetRequest();
createFullComponent(
{},
{
- namespaces: MOCK_NAMESPACES_RESPONSE,
form: {
state: true,
...fields,
@@ -400,25 +355,21 @@ describe('ForkForm component', () => {
);
};
- const selectedMockNamespaceIndex = 1;
- const namespaceId = MOCK_NAMESPACES_RESPONSE[selectedMockNamespaceIndex].id;
-
- const fillForm = async () => {
- const namespaceOptions = findForkUrlInput().findAll('option');
-
- await namespaceOptions.at(selectedMockNamespaceIndex + 1).setSelected();
- };
+ beforeEach(() => {
+ setupComponent();
+ });
const submitForm = async () => {
- await fillForm();
- const form = wrapper.find(GlForm);
+ fillForm();
+ await nextTick();
+ const form = wrapper.findComponent(GlForm);
await form.trigger('submit');
await nextTick();
};
describe('with invalid form', () => {
- it('does not make POST request', async () => {
+ it('does not make POST request', () => {
jest.spyOn(axios, 'post');
setupComponent();
@@ -471,7 +422,7 @@ describe('ForkForm component', () => {
description: projectDescription,
id: projectId,
name: projectName,
- namespace_id: namespaceId,
+ namespace_id: selectedMockNamespace.id,
path: projectPath,
visibility: projectVisibility,
};
diff --git a/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js b/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js
new file mode 100644
index 00000000000..1a88aebae32
--- /dev/null
+++ b/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js
@@ -0,0 +1,177 @@
+import {
+ GlButton,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownSectionHeader,
+ GlSearchBoxByType,
+ GlTruncate,
+} from '@gitlab/ui';
+import { mount, shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import createFlash from '~/flash';
+import searchQuery from '~/pages/projects/forks/new/queries/search_forkable_namespaces.query.graphql';
+import ProjectNamespace from '~/pages/projects/forks/new/components/project_namespace.vue';
+
+jest.mock('~/flash');
+
+describe('ProjectNamespace component', () => {
+ let wrapper;
+ let originalGon;
+
+ const data = {
+ project: {
+ __typename: 'Project',
+ id: 'gid://gitlab/Project/1',
+ forkTargets: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Group/21',
+ fullPath: 'flightjs',
+ name: 'Flight JS',
+ visibility: 'public',
+ },
+ {
+ id: 'gid://gitlab/Namespace/4',
+ fullPath: 'root',
+ name: 'Administrator',
+ visibility: 'public',
+ },
+ ],
+ },
+ },
+ };
+
+ const mockQueryResponse = jest.fn().mockResolvedValue({ data });
+
+ const emptyQueryResponse = {
+ project: {
+ __typename: 'Project',
+ id: 'gid://gitlab/Project/1',
+ forkTargets: {
+ nodes: [],
+ },
+ },
+ };
+
+ const mockQueryError = jest.fn().mockRejectedValue(new Error('Network error'));
+
+ Vue.use(VueApollo);
+
+ const gitlabUrl = 'https://gitlab.com';
+
+ const defaultProvide = {
+ projectFullPath: 'gitlab-org/project',
+ };
+
+ const mountComponent = ({
+ provide = defaultProvide,
+ queryHandler = mockQueryResponse,
+ mountFn = shallowMount,
+ } = {}) => {
+ const requestHandlers = [[searchQuery, queryHandler]];
+ const apolloProvider = createMockApollo(requestHandlers);
+
+ wrapper = mountFn(ProjectNamespace, {
+ apolloProvider,
+ provide,
+ });
+ };
+
+ const findButtonLabel = () => wrapper.findComponent(GlButton);
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdownText = () => wrapper.findComponent(GlTruncate);
+ const findInput = () => wrapper.findComponent(GlSearchBoxByType);
+
+ const clickDropdownItem = async () => {
+ wrapper.findComponent(GlDropdownItem).vm.$emit('click');
+ await nextTick();
+ };
+
+ const showDropdown = () => {
+ findDropdown().vm.$emit('shown');
+ };
+
+ beforeAll(() => {
+ originalGon = window.gon;
+ window.gon = { gitlab_url: gitlabUrl };
+ });
+
+ afterAll(() => {
+ window.gon = originalGon;
+ wrapper.destroy();
+ });
+
+ describe('Initial state', () => {
+ beforeEach(() => {
+ mountComponent({ mountFn: mount });
+ jest.runOnlyPendingTimers();
+ });
+
+ it('renders the root url as a label', () => {
+ expect(findButtonLabel().text()).toBe(`${gitlabUrl}/`);
+ expect(findButtonLabel().props('label')).toBe(true);
+ });
+
+ it('renders placeholder text', () => {
+ expect(findDropdownText().props('text')).toBe('Select a namespace');
+ });
+ });
+
+ describe('After user interactions', () => {
+ beforeEach(async () => {
+ mountComponent({ mountFn: mount });
+ jest.runOnlyPendingTimers();
+ await nextTick();
+ showDropdown();
+ });
+
+ it('focuses on the input when the dropdown is opened', () => {
+ const spy = jest.spyOn(findInput().vm, 'focusInput');
+ showDropdown();
+ expect(spy).toHaveBeenCalledTimes(1);
+ });
+
+ it('displays fetched namespaces', () => {
+ const listItems = wrapper.findAll('li');
+ expect(listItems).toHaveLength(3);
+ expect(listItems.at(0).findComponent(GlDropdownSectionHeader).text()).toBe('Namespaces');
+ expect(listItems.at(1).text()).toBe(data.project.forkTargets.nodes[0].fullPath);
+ expect(listItems.at(2).text()).toBe(data.project.forkTargets.nodes[1].fullPath);
+ });
+
+ it('sets the selected namespace', async () => {
+ const { fullPath } = data.project.forkTargets.nodes[0];
+ await clickDropdownItem();
+ expect(findDropdownText().props('text')).toBe(fullPath);
+ });
+ });
+
+ describe('With empty query response', () => {
+ beforeEach(() => {
+ mountComponent({ queryHandler: emptyQueryResponse, mountFn: mount });
+ jest.runOnlyPendingTimers();
+ });
+
+ it('renders `No matches found`', () => {
+ expect(wrapper.find('li').text()).toBe('No matches found');
+ });
+ });
+
+ describe('With error while fetching data', () => {
+ beforeEach(async () => {
+ mountComponent({ queryHandler: mockQueryError });
+ jest.runOnlyPendingTimers();
+ await nextTick();
+ });
+
+ it('creates a flash message and captures the error', () => {
+ expect(createFlash).toHaveBeenCalledWith({
+ message: 'Something went wrong while loading data. Please refresh the page to try again.',
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+ });
+});
diff --git a/spec/frontend/pages/projects/graphs/code_coverage_spec.js b/spec/frontend/pages/projects/graphs/code_coverage_spec.js
index f272891919d..2f2edd6b025 100644
--- a/spec/frontend/pages/projects/graphs/code_coverage_spec.js
+++ b/spec/frontend/pages/projects/graphs/code_coverage_spec.js
@@ -20,9 +20,9 @@ describe('Code Coverage', () => {
const graphRef = 'master';
const graphCsvPath = 'url/';
- const findAlert = () => wrapper.find(GlAlert);
- const findAreaChart = () => wrapper.find(GlAreaChart);
- const findAllDropdownItems = () => wrapper.findAll(GlDropdownItem);
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findAreaChart = () => wrapper.findComponent(GlAreaChart);
+ const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
const findFirstDropdownItem = () => findAllDropdownItems().at(0);
const findSecondDropdownItem = () => findAllDropdownItems().at(1);
const findDownloadButton = () => wrapper.find('[data-testid="download-button"]');
@@ -142,7 +142,7 @@ describe('Code Coverage', () => {
});
it('renders the dropdown with all custom names as options', () => {
- expect(wrapper.find(GlDropdown).exists()).toBeDefined();
+ expect(wrapper.findComponent(GlDropdown).exists()).toBeDefined();
expect(findAllDropdownItems()).toHaveLength(codeCoverageMockData.length);
expect(findFirstDropdownItem().text()).toBe(codeCoverageMockData[0].group_name);
});
diff --git a/spec/frontend/pages/projects/merge_requests/edit/update_form_spec.js b/spec/frontend/pages/projects/merge_requests/edit/update_form_spec.js
new file mode 100644
index 00000000000..72077038dff
--- /dev/null
+++ b/spec/frontend/pages/projects/merge_requests/edit/update_form_spec.js
@@ -0,0 +1,59 @@
+import { setHTMLFixture, resetHTMLFixture } from 'jest/__helpers__/fixtures';
+import initFormUpdate from '~/pages/projects/merge_requests/edit/update_form';
+
+describe('Update form state', () => {
+ const submitEvent = new Event('submit', {
+ bubbles: true,
+ cancelable: true,
+ });
+
+ const submitForm = () => document.querySelector('.merge-request-form').dispatchEvent(submitEvent);
+ const hiddenInputs = () => document.querySelectorAll('input[type="hidden"]');
+ const checkboxes = () => document.querySelectorAll('.js-form-update');
+
+ beforeEach(() => {
+ setHTMLFixture(`
+ <form class="merge-request-form">
+ <div class="form-check">
+ <input type="hidden" name="merge_request[force_remove_source_branch]" value="0" autocomplete="off">
+ <input type="checkbox" name="merge_request[force_remove_source_branch]" id="merge_request_force_remove_source_branch" value="1" class="form-check-input js-form-update">
+ </div>
+ <div class="form-check">
+ <input type="hidden" name="merge_request[squash]" value="0" autocomplete="off">
+ <input type="checkbox" name="merge_request[squash]" id="merge_request_squash" value="1" class="form-check-input js-form-update">
+ </div>
+ </form>`);
+ initFormUpdate();
+ });
+
+ afterEach(() => {
+ resetHTMLFixture();
+ });
+
+ it('at initial state', () => {
+ submitForm();
+ expect(hiddenInputs()).toHaveLength(2);
+ });
+
+ it('when one element is checked', () => {
+ checkboxes()[0].setAttribute('checked', true);
+ submitForm();
+ expect(hiddenInputs()).toHaveLength(1);
+ });
+
+ it('when all elements are checked', () => {
+ checkboxes()[0].setAttribute('checked', true);
+ checkboxes()[1].setAttribute('checked', true);
+ submitForm();
+ expect(hiddenInputs()).toHaveLength(0);
+ });
+
+ it('when checked and then unchecked', () => {
+ checkboxes()[0].setAttribute('checked', true);
+ checkboxes()[0].removeAttribute('checked');
+ checkboxes()[1].setAttribute('checked', true);
+ checkboxes()[1].removeAttribute('checked');
+ submitForm();
+ expect(hiddenInputs()).toHaveLength(2);
+ });
+});
diff --git a/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js b/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
index ca7f70f4434..a633332ab65 100644
--- a/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
+++ b/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
@@ -21,7 +21,7 @@ describe('Pipeline Schedule Callout', () => {
};
const findInnerContentOfCallout = () => wrapper.find('[data-testid="innerContent"]');
- const findDismissCalloutBtn = () => wrapper.find(GlButton);
+ const findDismissCalloutBtn = () => wrapper.findComponent(GlButton);
describe(`when ${cookieKey} cookie is set`, () => {
beforeEach(async () => {
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 f908508c4b5..ed7d4ad269e 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
@@ -5,8 +5,12 @@ import settingsPanel from '~/pages/projects/shared/permissions/components/settin
import {
featureAccessLevel,
visibilityLevelDescriptions,
- visibilityOptions,
} from '~/pages/projects/shared/permissions/constants';
+import {
+ VISIBILITY_LEVEL_PRIVATE_INTEGER,
+ VISIBILITY_LEVEL_INTERNAL_INTEGER,
+ VISIBILITY_LEVEL_PUBLIC_INTEGER,
+} from '~/visibility_level/constants';
import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue';
const defaultProps = {
@@ -81,15 +85,17 @@ describe('Settings Panel', () => {
});
};
- const findLFSSettingsRow = () => wrapper.find({ ref: 'git-lfs-settings' });
+ const findLFSSettingsRow = () => wrapper.findComponent({ ref: 'git-lfs-settings' });
const findLFSSettingsMessage = () => findLFSSettingsRow().find('p');
- const findLFSFeatureToggle = () => findLFSSettingsRow().find(GlToggle);
- const findRepositoryFeatureProjectRow = () => wrapper.find({ ref: 'repository-settings' });
+ const findLFSFeatureToggle = () => findLFSSettingsRow().findComponent(GlToggle);
+ const findRepositoryFeatureProjectRow = () =>
+ wrapper.findComponent({ ref: 'repository-settings' });
const findRepositoryFeatureSetting = () =>
- findRepositoryFeatureProjectRow().find(ProjectFeatureSetting);
- const findProjectVisibilitySettings = () => wrapper.find({ ref: 'project-visibility-settings' });
- const findIssuesSettingsRow = () => wrapper.find({ ref: 'issues-settings' });
- const findAnalyticsRow = () => wrapper.find({ ref: 'analytics-settings' });
+ findRepositoryFeatureProjectRow().findComponent(ProjectFeatureSetting);
+ const findProjectVisibilitySettings = () =>
+ wrapper.findComponent({ ref: 'project-visibility-settings' });
+ const findIssuesSettingsRow = () => wrapper.findComponent({ ref: 'issues-settings' });
+ const findAnalyticsRow = () => wrapper.findComponent({ ref: 'analytics-settings' });
const findProjectVisibilityLevelInput = () => wrapper.find('[name="project[visibility_level]"]');
const findRequestAccessEnabledInput = () =>
wrapper.find('[name="project[request_access_enabled]"]');
@@ -99,35 +105,40 @@ describe('Settings Panel', () => {
wrapper.find('[name="project[project_feature_attributes][forking_access_level]"]');
const findBuildsAccessLevelInput = () =>
wrapper.find('[name="project[project_feature_attributes][builds_access_level]"]');
- const findContainerRegistrySettings = () => wrapper.find({ ref: 'container-registry-settings' });
+ const findContainerRegistrySettings = () =>
+ wrapper.findComponent({ ref: 'container-registry-settings' });
const findContainerRegistryPublicNoteGlSprintfComponent = () =>
findContainerRegistrySettings().findComponent(GlSprintf);
const findContainerRegistryAccessLevelInput = () =>
wrapper.find('[name="project[project_feature_attributes][container_registry_access_level]"]');
- const findPackageSettings = () => wrapper.find({ ref: 'package-settings' });
+ const findPackageSettings = () => wrapper.findComponent({ ref: 'package-settings' });
const findPackageAccessLevel = () =>
wrapper.find('[data-testid="package-registry-access-level"]');
const findPackageAccessLevels = () =>
wrapper.find('[name="project[project_feature_attributes][package_registry_access_level]"]');
const findPackagesEnabledInput = () => wrapper.find('[name="project[packages_enabled]"]');
- const findPagesSettings = () => wrapper.find({ ref: 'pages-settings' });
+ const findPagesSettings = () => wrapper.findComponent({ ref: 'pages-settings' });
const findPagesAccessLevels = () =>
wrapper.find('[name="project[project_feature_attributes][pages_access_level]"]');
- const findEmailSettings = () => wrapper.find({ ref: 'email-settings' });
+ const findEmailSettings = () => wrapper.findComponent({ ref: 'email-settings' });
const findShowDefaultAwardEmojis = () =>
wrapper.find('input[name="project[project_setting_attributes][show_default_award_emojis]"]');
const findWarnAboutPuc = () =>
wrapper.find(
'input[name="project[project_setting_attributes][warn_about_potentially_unwanted_characters]"]',
);
- const findMetricsVisibilitySettings = () => wrapper.find({ ref: 'metrics-visibility-settings' });
+ const findMetricsVisibilitySettings = () =>
+ wrapper.findComponent({ ref: 'metrics-visibility-settings' });
const findMetricsVisibilityInput = () =>
findMetricsVisibilitySettings().findComponent(ProjectFeatureSetting);
- const findOperationsSettings = () => wrapper.find({ ref: 'operations-settings' });
+ const findOperationsSettings = () => wrapper.findComponent({ ref: 'operations-settings' });
const findOperationsVisibilityInput = () =>
findOperationsSettings().findComponent(ProjectFeatureSetting);
const findConfirmDangerButton = () => wrapper.findComponent(ConfirmDanger);
const findEnvironmentsSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
+ const findFeatureFlagsSettings = () => wrapper.findComponent({ ref: 'feature-flags-settings' });
+ const findReleasesSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
+ const findMonitorSettings = () => wrapper.findComponent({ ref: 'monitor-settings' });
afterEach(() => {
wrapper.destroy();
@@ -156,13 +167,13 @@ describe('Settings Panel', () => {
});
it.each`
- option | allowedOptions | disabled
- ${visibilityOptions.PRIVATE} | ${[visibilityOptions.PRIVATE, visibilityOptions.INTERNAL, visibilityOptions.PUBLIC]} | ${false}
- ${visibilityOptions.PRIVATE} | ${[visibilityOptions.INTERNAL, visibilityOptions.PUBLIC]} | ${true}
- ${visibilityOptions.INTERNAL} | ${[visibilityOptions.PRIVATE, visibilityOptions.INTERNAL, visibilityOptions.PUBLIC]} | ${false}
- ${visibilityOptions.INTERNAL} | ${[visibilityOptions.PRIVATE, visibilityOptions.PUBLIC]} | ${true}
- ${visibilityOptions.PUBLIC} | ${[visibilityOptions.PRIVATE, visibilityOptions.INTERNAL, visibilityOptions.PUBLIC]} | ${false}
- ${visibilityOptions.PUBLIC} | ${[visibilityOptions.PRIVATE, visibilityOptions.INTERNAL]} | ${true}
+ option | allowedOptions | disabled
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${[VISIBILITY_LEVEL_PRIVATE_INTEGER, VISIBILITY_LEVEL_INTERNAL_INTEGER, VISIBILITY_LEVEL_PUBLIC_INTEGER]} | ${false}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${[VISIBILITY_LEVEL_INTERNAL_INTEGER, VISIBILITY_LEVEL_PUBLIC_INTEGER]} | ${true}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${[VISIBILITY_LEVEL_PRIVATE_INTEGER, VISIBILITY_LEVEL_INTERNAL_INTEGER, VISIBILITY_LEVEL_PUBLIC_INTEGER]} | ${false}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${[VISIBILITY_LEVEL_PRIVATE_INTEGER, VISIBILITY_LEVEL_PUBLIC_INTEGER]} | ${true}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${[VISIBILITY_LEVEL_PRIVATE_INTEGER, VISIBILITY_LEVEL_INTERNAL_INTEGER, VISIBILITY_LEVEL_PUBLIC_INTEGER]} | ${false}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${[VISIBILITY_LEVEL_PRIVATE_INTEGER, VISIBILITY_LEVEL_INTERNAL_INTEGER]} | ${true}
`(
'sets disabled to $disabled for the visibility option $option when given $allowedOptions',
({ option, allowedOptions, disabled }) => {
@@ -181,35 +192,37 @@ describe('Settings Panel', () => {
it('should set the visibility level description based upon the selected visibility level', () => {
wrapper = mountComponent({ stubs: { GlSprintf } });
- findProjectVisibilityLevelInput().setValue(visibilityOptions.INTERNAL);
+ findProjectVisibilityLevelInput().setValue(VISIBILITY_LEVEL_INTERNAL_INTEGER);
expect(findProjectVisibilitySettings().text()).toContain(
- visibilityLevelDescriptions[visibilityOptions.INTERNAL],
+ visibilityLevelDescriptions[VISIBILITY_LEVEL_INTERNAL_INTEGER],
);
});
it('should show the request access checkbox if the visibility level is not private', () => {
wrapper = mountComponent({
- currentSettings: { visibilityLevel: visibilityOptions.INTERNAL },
+ currentSettings: { visibilityLevel: VISIBILITY_LEVEL_INTERNAL_INTEGER },
});
expect(findRequestAccessEnabledInput().exists()).toBe(true);
});
it('should not show the request access checkbox if the visibility level is private', () => {
- wrapper = mountComponent({ currentSettings: { visibilityLevel: visibilityOptions.PRIVATE } });
+ wrapper = mountComponent({
+ currentSettings: { visibilityLevel: VISIBILITY_LEVEL_PRIVATE_INTEGER },
+ });
expect(findRequestAccessEnabledInput().exists()).toBe(false);
});
it('does not require confirmation if the visibility is reduced', async () => {
wrapper = mountComponent({
- currentSettings: { visibilityLevel: visibilityOptions.INTERNAL },
+ currentSettings: { visibilityLevel: VISIBILITY_LEVEL_INTERNAL_INTEGER },
});
expect(findConfirmDangerButton().exists()).toBe(false);
- await findProjectVisibilityLevelInput().setValue(visibilityOptions.PRIVATE);
+ await findProjectVisibilityLevelInput().setValue(VISIBILITY_LEVEL_PRIVATE_INTEGER);
expect(findConfirmDangerButton().exists()).toBe(false);
});
@@ -217,7 +230,7 @@ describe('Settings Panel', () => {
describe('showVisibilityConfirmModal=true', () => {
beforeEach(() => {
wrapper = mountComponent({
- currentSettings: { visibilityLevel: visibilityOptions.INTERNAL },
+ currentSettings: { visibilityLevel: VISIBILITY_LEVEL_INTERNAL_INTEGER },
showVisibilityConfirmModal: true,
});
});
@@ -225,7 +238,7 @@ describe('Settings Panel', () => {
it('will render the confirmation dialog if the visibility is reduced', async () => {
expect(findConfirmDangerButton().exists()).toBe(false);
- await findProjectVisibilityLevelInput().setValue(visibilityOptions.PRIVATE);
+ await findProjectVisibilityLevelInput().setValue(VISIBILITY_LEVEL_PRIVATE_INTEGER);
expect(findConfirmDangerButton().exists()).toBe(true);
});
@@ -233,7 +246,7 @@ describe('Settings Panel', () => {
it('emits the `confirm` event when the reduce visibility warning is confirmed', async () => {
expect(wrapper.emitted('confirm')).toBeUndefined();
- await findProjectVisibilityLevelInput().setValue(visibilityOptions.PRIVATE);
+ await findProjectVisibilityLevelInput().setValue(VISIBILITY_LEVEL_PRIVATE_INTEGER);
await findConfirmDangerButton().vm.$emit('confirm');
expect(wrapper.emitted('confirm')).toHaveLength(1);
@@ -253,7 +266,9 @@ describe('Settings Panel', () => {
describe('Repository', () => {
it('should set the repository help text when the visibility level is set to private', () => {
- wrapper = mountComponent({ currentSettings: { visibilityLevel: visibilityOptions.PRIVATE } });
+ wrapper = mountComponent({
+ currentSettings: { visibilityLevel: VISIBILITY_LEVEL_PRIVATE_INTEGER },
+ });
expect(findRepositoryFeatureProjectRow().props('helpText')).toBe(
'View and edit files in this project.',
@@ -261,7 +276,9 @@ describe('Settings Panel', () => {
});
it('should set the repository help text with a read access warning when the visibility level is set to non-private', () => {
- wrapper = mountComponent({ currentSettings: { visibilityLevel: visibilityOptions.PUBLIC } });
+ wrapper = mountComponent({
+ currentSettings: { visibilityLevel: VISIBILITY_LEVEL_PUBLIC_INTEGER },
+ });
expect(findRepositoryFeatureProjectRow().props('helpText')).toBe(
'View and edit files in this project. Non-project members have only read access.',
@@ -345,7 +362,7 @@ describe('Settings Panel', () => {
it('should show the container registry public note if the visibility level is public and the registry is available', () => {
wrapper = mountComponent({
currentSettings: {
- visibilityLevel: visibilityOptions.PUBLIC,
+ visibilityLevel: VISIBILITY_LEVEL_PUBLIC_INTEGER,
containerRegistryAccessLevel: featureAccessLevel.EVERYONE,
},
registryAvailable: true,
@@ -360,7 +377,7 @@ describe('Settings Panel', () => {
it('should hide the container registry public note if the visibility level is public but the registry is private', () => {
wrapper = mountComponent({
currentSettings: {
- visibilityLevel: visibilityOptions.PUBLIC,
+ visibilityLevel: VISIBILITY_LEVEL_PUBLIC_INTEGER,
containerRegistryAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
},
registryAvailable: true,
@@ -371,7 +388,7 @@ describe('Settings Panel', () => {
it('should hide the container registry public note if the visibility level is private and the registry is available', () => {
wrapper = mountComponent({
- currentSettings: { visibilityLevel: visibilityOptions.PRIVATE },
+ currentSettings: { visibilityLevel: VISIBILITY_LEVEL_PRIVATE_INTEGER },
registryAvailable: true,
});
@@ -380,7 +397,7 @@ describe('Settings Panel', () => {
it('has label for the toggle', () => {
wrapper = mountComponent({
- currentSettings: { visibilityLevel: visibilityOptions.PUBLIC },
+ currentSettings: { visibilityLevel: VISIBILITY_LEVEL_PUBLIC_INTEGER },
registryAvailable: true,
});
@@ -569,10 +586,10 @@ describe('Settings Panel', () => {
});
it.each`
- visibilityLevel | output
- ${visibilityOptions.PRIVATE} | ${[[featureAccessLevel.PROJECT_MEMBERS, 'Only Project Members'], [30, 'Everyone']]}
- ${visibilityOptions.INTERNAL} | ${[[featureAccessLevel.EVERYONE, 'Everyone With Access'], [30, 'Everyone']]}
- ${visibilityOptions.PUBLIC} | ${[[30, 'Everyone']]}
+ visibilityLevel | output
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${[[featureAccessLevel.PROJECT_MEMBERS, 'Only Project Members'], [30, 'Everyone']]}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${[[featureAccessLevel.EVERYONE, 'Everyone With Access'], [30, 'Everyone']]}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${[[30, 'Everyone']]}
`(
'renders correct options when visibilityLevel is $visibilityLevel',
async ({ visibilityLevel, output }) => {
@@ -589,23 +606,23 @@ describe('Settings Panel', () => {
);
it.each`
- initialProjectVisibilityLevel | newProjectVisibilityLevel | initialPackageRegistryOption | expectedPackageRegistryOption
- ${visibilityOptions.PRIVATE} | ${visibilityOptions.INTERNAL} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${visibilityOptions.PRIVATE} | ${visibilityOptions.INTERNAL} | ${featureAccessLevel.PROJECT_MEMBERS} | ${featureAccessLevel.EVERYONE}
- ${visibilityOptions.PRIVATE} | ${visibilityOptions.INTERNAL} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${visibilityOptions.PRIVATE} | ${visibilityOptions.PUBLIC} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${visibilityOptions.PRIVATE} | ${visibilityOptions.PUBLIC} | ${featureAccessLevel.PROJECT_MEMBERS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${visibilityOptions.PRIVATE} | ${visibilityOptions.PUBLIC} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${visibilityOptions.INTERNAL} | ${visibilityOptions.PRIVATE} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${visibilityOptions.INTERNAL} | ${visibilityOptions.PRIVATE} | ${featureAccessLevel.EVERYONE} | ${featureAccessLevel.PROJECT_MEMBERS}
- ${visibilityOptions.INTERNAL} | ${visibilityOptions.PRIVATE} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${visibilityOptions.INTERNAL} | ${visibilityOptions.PUBLIC} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${visibilityOptions.INTERNAL} | ${visibilityOptions.PUBLIC} | ${featureAccessLevel.EVERYONE} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${visibilityOptions.INTERNAL} | ${visibilityOptions.PUBLIC} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${visibilityOptions.PUBLIC} | ${visibilityOptions.PRIVATE} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${visibilityOptions.PUBLIC} | ${visibilityOptions.PRIVATE} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${featureAccessLevel.PROJECT_MEMBERS}
- ${visibilityOptions.PUBLIC} | ${visibilityOptions.INTERNAL} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${visibilityOptions.PUBLIC} | ${visibilityOptions.INTERNAL} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${featureAccessLevel.EVERYONE}
+ initialProjectVisibilityLevel | newProjectVisibilityLevel | initialPackageRegistryOption | expectedPackageRegistryOption
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.PROJECT_MEMBERS} | ${featureAccessLevel.EVERYONE}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.PROJECT_MEMBERS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${featureAccessLevel.EVERYONE} | ${featureAccessLevel.PROJECT_MEMBERS}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.EVERYONE} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${featureAccessLevel.PROJECT_MEMBERS}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${featureAccessLevel.EVERYONE}
`(
'changes option from $initialPackageRegistryOption to $expectedPackageRegistryOption when visibilityLevel changed from $initialProjectVisibilityLevel to $newProjectVisibilityLevel',
async ({
@@ -635,13 +652,13 @@ 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']]}
+ visibilityLevel | pagesAccessControlForced | output
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${true} | ${[[VISIBILITY_LEVEL_INTERNAL_INTEGER, 'Only Project Members'], [VISIBILITY_LEVEL_PUBLIC_INTEGER, 'Everyone With Access']]}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${false} | ${[[VISIBILITY_LEVEL_INTERNAL_INTEGER, 'Only Project Members'], [VISIBILITY_LEVEL_PUBLIC_INTEGER, 'Everyone With Access'], [30, 'Everyone']]}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${true} | ${[[VISIBILITY_LEVEL_INTERNAL_INTEGER, 'Only Project Members'], [VISIBILITY_LEVEL_PUBLIC_INTEGER, 'Everyone With Access']]}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${false} | ${[[VISIBILITY_LEVEL_INTERNAL_INTEGER, 'Only Project Members'], [VISIBILITY_LEVEL_PUBLIC_INTEGER, 'Everyone With Access'], [30, 'Everyone']]}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${true} | ${[[VISIBILITY_LEVEL_INTERNAL_INTEGER, 'Only Project Members'], [VISIBILITY_LEVEL_PUBLIC_INTEGER, 'Everyone With Access']]}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${false} | ${[[VISIBILITY_LEVEL_INTERNAL_INTEGER, 'Only Project Members'], [VISIBILITY_LEVEL_PUBLIC_INTEGER, 'Everyone With Access'], [30, 'Everyone']]}
`(
'renders correct options when pagesAccessControlForced is $pagesAccessControlForced and visibilityLevel is $visibilityLevel',
async ({ visibilityLevel, pagesAccessControlForced, output }) => {
@@ -760,13 +777,13 @@ describe('Settings Panel', () => {
it('should reduce Metrics visibility level when visibility is set to private', async () => {
wrapper = mountComponent({
currentSettings: {
- visibilityLevel: visibilityOptions.PUBLIC,
+ visibilityLevel: VISIBILITY_LEVEL_PUBLIC_INTEGER,
operationsAccessLevel: featureAccessLevel.EVERYONE,
metricsDashboardAccessLevel: featureAccessLevel.EVERYONE,
},
});
- await findProjectVisibilityLevelInput().setValue(visibilityOptions.PRIVATE);
+ await findProjectVisibilityLevelInput().setValue(VISIBILITY_LEVEL_PRIVATE_INTEGER);
expect(findMetricsVisibilityInput().props('value')).toBe(featureAccessLevel.PROJECT_MEMBERS);
});
@@ -806,4 +823,78 @@ describe('Settings Panel', () => {
});
});
});
+ describe('Feature Flags', () => {
+ describe('with feature flag', () => {
+ it('should show the feature flags toggle', () => {
+ wrapper = mountComponent({
+ glFeatures: { splitOperationsVisibilityPermissions: true },
+ });
+
+ expect(findFeatureFlagsSettings().exists()).toBe(true);
+ });
+ });
+ describe('without feature flag', () => {
+ it('should not show the feature flags toggle', () => {
+ wrapper = mountComponent({});
+
+ expect(findFeatureFlagsSettings().exists()).toBe(false);
+ });
+ });
+ });
+ describe('Releases', () => {
+ describe('with feature flag', () => {
+ it('should show the releases toggle', () => {
+ wrapper = mountComponent({
+ glFeatures: { splitOperationsVisibilityPermissions: true },
+ });
+
+ expect(findReleasesSettings().exists()).toBe(true);
+ });
+ });
+ describe('without feature flag', () => {
+ it('should not show the releases toggle', () => {
+ wrapper = mountComponent({});
+
+ expect(findReleasesSettings().exists()).toBe(false);
+ });
+ });
+ });
+ describe('Monitor', () => {
+ const expectedAccessLevel = [
+ [10, 'Only Project Members'],
+ [20, 'Everyone With Access'],
+ ];
+ describe('with feature flag', () => {
+ it('shows Monitor toggle instead of Operations toggle', () => {
+ wrapper = mountComponent({
+ glFeatures: { splitOperationsVisibilityPermissions: true },
+ });
+
+ expect(findMonitorSettings().exists()).toBe(true);
+ expect(findOperationsSettings().exists()).toBe(false);
+ expect(findMonitorSettings().findComponent(ProjectFeatureSetting).props('options')).toEqual(
+ expectedAccessLevel,
+ );
+ });
+ it('when monitorAccessLevel is for project members, it is also for everyone', () => {
+ wrapper = mountComponent({
+ glFeatures: { splitOperationsVisibilityPermissions: true },
+ currentSettings: { monitorAccessLevel: featureAccessLevel.PROJECT_MEMBERS },
+ });
+
+ expect(findMetricsVisibilityInput().props('value')).toBe(featureAccessLevel.EVERYONE);
+ });
+ });
+ describe('without feature flag', () => {
+ it('shows Operations toggle instead of Monitor toggle', () => {
+ wrapper = mountComponent({});
+
+ expect(findMonitorSettings().exists()).toBe(false);
+ expect(findOperationsSettings().exists()).toBe(true);
+ expect(
+ findOperationsSettings().findComponent(ProjectFeatureSetting).props('options'),
+ ).toEqual(expectedAccessLevel);
+ });
+ });
+ });
});
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js
index 108f816fe01..982c81b9272 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js
@@ -38,7 +38,7 @@ describe('pages/shared/wikis/components/wiki_content', () => {
const findGlAlert = () => wrapper.findComponent(GlAlert);
const findGlSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
- const findContent = () => wrapper.find('[data-testid="wiki_page_content"]');
+ const findContent = () => wrapper.find('[data-testid="wiki-page-content"]');
describe('when loading content', () => {
beforeEach(() => {
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
index 204c48f8de1..b37d2f06191 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
@@ -39,7 +39,7 @@ describe('WikiForm', () => {
const findMarkdownHelpLink = () => wrapper.findByTestId('wiki-markdown-help-link');
const findContentEditor = () => wrapper.findComponent(ContentEditor);
const findClassicEditor = () => wrapper.findComponent(MarkdownField);
- const findLocalStorageSync = () => wrapper.find(LocalStorageSync);
+ const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
const setFormat = (value) => {
const format = findFormat();
@@ -302,19 +302,15 @@ describe('WikiForm', () => {
});
it.each`
- format | enabled | action
+ format | exists | action
${'markdown'} | ${true} | ${'displays'}
${'rdoc'} | ${false} | ${'hides'}
${'asciidoc'} | ${false} | ${'hides'}
${'org'} | ${false} | ${'hides'}
- `('$action toggle editing mode button when format is $format', async ({ format, enabled }) => {
+ `('$action toggle editing mode button when format is $format', async ({ format, exists }) => {
await setFormat(format);
- expect(findToggleEditingModeButton().exists()).toBe(enabled);
- });
-
- it('displays toggle editing mode button', () => {
- expect(findToggleEditingModeButton().exists()).toBe(true);
+ expect(findToggleEditingModeButton().exists()).toBe(exists);
});
describe('when content editor is not active', () => {
@@ -351,15 +347,8 @@ describe('WikiForm', () => {
});
describe('when content editor is active', () => {
- let mockContentEditor;
-
beforeEach(() => {
createWrapper();
- mockContentEditor = {
- getSerializedContent: jest.fn(),
- setSerializedContent: jest.fn(),
- };
-
findToggleEditingModeButton().vm.$emit('input', 'richText');
});
@@ -368,14 +357,7 @@ describe('WikiForm', () => {
});
describe('when clicking the toggle editing mode button', () => {
- const contentEditorFakeSerializedContent = 'fake content';
-
beforeEach(async () => {
- mockContentEditor.getSerializedContent.mockReturnValueOnce(
- contentEditorFakeSerializedContent,
- );
-
- findContentEditor().vm.$emit('initialized', mockContentEditor);
await findToggleEditingModeButton().vm.$emit('input', 'source');
await nextTick();
});
@@ -387,10 +369,6 @@ describe('WikiForm', () => {
it('displays the classic editor', () => {
expect(findClassicEditor().exists()).toBe(true);
});
-
- it('updates the classic editor content field', () => {
- expect(findContent().element.value).toBe(contentEditorFakeSerializedContent);
- });
});
describe('when content editor is loading', () => {
@@ -480,8 +458,14 @@ describe('WikiForm', () => {
});
describe('when wiki content is updated', () => {
+ const updatedMarkdown = 'hello **world**';
+
beforeEach(() => {
- findContentEditor().vm.$emit('change', { empty: false });
+ findContentEditor().vm.$emit('change', {
+ empty: false,
+ changed: true,
+ markdown: updatedMarkdown,
+ });
});
it('sets before unload warning', () => {
@@ -512,16 +496,8 @@ describe('WikiForm', () => {
});
});
- it('updates content from content editor on form submit', async () => {
- // old value
- expect(findContent().element.value).toBe(' My page content ');
-
- // wait for content editor to load
- await waitForPromises();
-
- await triggerFormSubmit();
-
- expect(findContent().element.value).toBe('hello **world**');
+ it('sets content field to the content editor updated markdown', async () => {
+ expect(findContent().element.value).toBe(updatedMarkdown);
});
});
});