diff options
Diffstat (limited to 'spec/frontend/pages/projects')
6 files changed, 460 insertions, 182 deletions
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); + }); + }); + }); }); |