import { shallowMount, mount } from '@vue/test-utils'; import settingsPanel from '~/pages/projects/shared/permissions/components/settings_panel.vue'; import { featureAccessLevel, visibilityLevelDescriptions, visibilityOptions, } from '~/pages/projects/shared/permissions/constants'; const defaultProps = { currentSettings: { visibilityLevel: 10, requestAccessEnabled: true, issuesAccessLevel: 20, repositoryAccessLevel: 20, forkingAccessLevel: 20, mergeRequestsAccessLevel: 20, buildsAccessLevel: 20, wikiAccessLevel: 20, snippetsAccessLevel: 20, pagesAccessLevel: 10, containerRegistryEnabled: true, lfsEnabled: true, emailsDisabled: false, packagesEnabled: true, showDefaultAwardEmojis: true, }, canDisableEmails: true, canChangeVisibilityLevel: true, allowedVisibilityOptions: [0, 10, 20], visibilityHelpPath: '/help/public_access/public_access', registryAvailable: false, registryHelpPath: '/help/user/packages/container_registry/index', lfsAvailable: true, lfsHelpPath: '/help/topics/git/lfs/index', lfsObjectsExist: false, lfsObjectsRemovalHelpPath: `/help/topics/git/lfs/index#removing-objects-from-lfs`, pagesAvailable: true, pagesAccessControlEnabled: false, pagesAccessControlForced: false, pagesHelpPath: '/help/user/project/pages/introduction#gitlab-pages-access-control-core', packagesAvailable: false, packagesHelpPath: '/help/user/packages/index', }; describe('Settings Panel', () => { let wrapper; const mountComponent = ( { currentSettings = {}, ...customProps } = {}, mountFn = shallowMount, ) => { const propsData = { ...defaultProps, ...customProps, currentSettings: { ...defaultProps.currentSettings, ...currentSettings }, }; return mountFn(settingsPanel, { propsData, }); }; const overrideCurrentSettings = (currentSettingsProps, extraProps = {}) => { return mountComponent({ ...extraProps, currentSettings: currentSettingsProps }); }; const findLFSSettingsMessage = () => wrapper.find({ ref: 'git-lfs-settings' }).find('p'); beforeEach(() => { wrapper = mountComponent(); }); afterEach(() => { wrapper.destroy(); }); describe('Project Visibility', () => { it('should set the project visibility help path', () => { expect(wrapper.find({ ref: 'project-visibility-settings' }).props().helpPath).toBe( defaultProps.visibilityHelpPath, ); }); it('should not disable the visibility level dropdown', () => { wrapper.setProps({ canChangeVisibilityLevel: true }); return wrapper.vm.$nextTick(() => { expect( wrapper.find('[name="project[visibility_level]"]').attributes().disabled, ).toBeUndefined(); }); }); it('should disable the visibility level dropdown', () => { wrapper.setProps({ canChangeVisibilityLevel: false }); return wrapper.vm.$nextTick(() => { expect(wrapper.find('[name="project[visibility_level]"]').attributes().disabled).toBe( 'disabled', ); }); }); 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} `( 'sets disabled to $disabled for the visibility option $option when given $allowedOptions', ({ option, allowedOptions, disabled }) => { wrapper.setProps({ allowedVisibilityOptions: allowedOptions }); return wrapper.vm.$nextTick(() => { const attributeValue = wrapper .find(`[name="project[visibility_level]"] option[value="${option}"]`) .attributes().disabled; if (disabled) { expect(attributeValue).toBe('disabled'); } else { expect(attributeValue).toBeUndefined(); } }); }, ); it('should set the visibility level description based upon the selected visibility level', () => { wrapper.find('[name="project[visibility_level]"]').setValue(visibilityOptions.INTERNAL); expect(wrapper.find({ ref: 'project-visibility-settings' }).text()).toContain( visibilityLevelDescriptions[visibilityOptions.INTERNAL], ); }); it('should show the request access checkbox if the visibility level is not private', () => { wrapper = overrideCurrentSettings({ visibilityLevel: visibilityOptions.INTERNAL }); expect(wrapper.find('[name="project[request_access_enabled]"]').exists()).toBe(true); }); it('should not show the request access checkbox if the visibility level is private', () => { wrapper = overrideCurrentSettings({ visibilityLevel: visibilityOptions.PRIVATE }); expect(wrapper.find('[name="project[request_access_enabled]"]').exists()).toBe(false); }); }); describe('Repository', () => { it('should set the repository help text when the visibility level is set to private', () => { wrapper = overrideCurrentSettings({ visibilityLevel: visibilityOptions.PRIVATE }); expect(wrapper.find({ ref: 'repository-settings' }).props().helpText).toEqual( 'View and edit files in this project', ); }); it('should set the repository help text with a read access warning when the visibility level is set to non-private', () => { wrapper = overrideCurrentSettings({ visibilityLevel: visibilityOptions.PUBLIC }); expect(wrapper.find({ ref: 'repository-settings' }).props().helpText).toEqual( 'View and edit files in this project. Non-project members will only have read access', ); }); }); describe('Merge requests', () => { it('should enable the merge requests access level input when the repository is enabled', () => { wrapper = overrideCurrentSettings({ repositoryAccessLevel: featureAccessLevel.EVERYONE }); expect( wrapper .find('[name="project[project_feature_attributes][merge_requests_access_level]"]') .props().disabledInput, ).toEqual(false); }); it('should disable the merge requests access level input when the repository is disabled', () => { wrapper = overrideCurrentSettings({ repositoryAccessLevel: featureAccessLevel.NOT_ENABLED }); expect( wrapper .find('[name="project[project_feature_attributes][merge_requests_access_level]"]') .props().disabledInput, ).toEqual(true); }); }); describe('Forks', () => { it('should enable the forking access level input when the repository is enabled', () => { wrapper = overrideCurrentSettings({ repositoryAccessLevel: featureAccessLevel.EVERYONE }); expect( wrapper.find('[name="project[project_feature_attributes][forking_access_level]"]').props() .disabledInput, ).toEqual(false); }); it('should disable the forking access level input when the repository is disabled', () => { wrapper = overrideCurrentSettings({ repositoryAccessLevel: featureAccessLevel.NOT_ENABLED }); expect( wrapper.find('[name="project[project_feature_attributes][forking_access_level]"]').props() .disabledInput, ).toEqual(true); }); }); describe('Pipelines', () => { it('should enable the builds access level input when the repository is enabled', () => { wrapper = overrideCurrentSettings({ repositoryAccessLevel: featureAccessLevel.EVERYONE }); expect( wrapper.find('[name="project[project_feature_attributes][builds_access_level]"]').props() .disabledInput, ).toEqual(false); }); it('should disable the builds access level input when the repository is disabled', () => { wrapper = overrideCurrentSettings({ repositoryAccessLevel: featureAccessLevel.NOT_ENABLED }); expect( wrapper.find('[name="project[project_feature_attributes][builds_access_level]"]').props() .disabledInput, ).toEqual(true); }); }); describe('Container registry', () => { it('should show the container registry settings if the registry is available', () => { wrapper.setProps({ registryAvailable: true }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'container-registry-settings' }).exists()).toBe(true); }); }); it('should hide the container registry settings if the registry is not available', () => { wrapper.setProps({ registryAvailable: false }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'container-registry-settings' }).exists()).toBe(false); }); }); it('should set the container registry settings help path', () => { wrapper.setProps({ registryAvailable: true }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'container-registry-settings' }).props().helpPath).toBe( defaultProps.registryHelpPath, ); }); }); it('should show the container registry public note if the visibility level is public and the registry is available', () => { wrapper = overrideCurrentSettings( { visibilityLevel: visibilityOptions.PUBLIC }, { registryAvailable: true }, ); expect(wrapper.find({ ref: 'container-registry-settings' }).text()).toContain( 'Note: the container registry is always visible when a project is public', ); }); it('should hide the container registry public note if the visibility level is private and the registry is available', () => { wrapper = overrideCurrentSettings( { visibilityLevel: visibilityOptions.PRIVATE }, { registryAvailable: true }, ); expect(wrapper.find({ ref: 'container-registry-settings' }).text()).not.toContain( 'Note: the container registry is always visible when a project is public', ); }); it('should enable the container registry input when the repository is enabled', () => { wrapper = overrideCurrentSettings( { repositoryAccessLevel: featureAccessLevel.EVERYONE }, { registryAvailable: true }, ); expect( wrapper.find('[name="project[container_registry_enabled]"]').props().disabledInput, ).toEqual(false); }); it('should disable the container registry input when the repository is disabled', () => { wrapper = overrideCurrentSettings( { repositoryAccessLevel: featureAccessLevel.NOT_ENABLED }, { registryAvailable: true }, ); expect( wrapper.find('[name="project[container_registry_enabled]"]').props().disabledInput, ).toEqual(true); }); }); describe('Git Large File Storage', () => { it('should show the LFS settings if LFS is available', () => { wrapper.setProps({ lfsAvailable: true }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'git-lfs-settings' }).exists()).toEqual(true); }); }); it('should hide the LFS settings if LFS is not available', () => { wrapper.setProps({ lfsAvailable: false }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'git-lfs-settings' }).exists()).toEqual(false); }); }); it('should set the LFS settings help path', () => { expect(wrapper.find({ ref: 'git-lfs-settings' }).props().helpPath).toBe( defaultProps.lfsHelpPath, ); }); it('should enable the LFS input when the repository is enabled', () => { wrapper = overrideCurrentSettings( { repositoryAccessLevel: featureAccessLevel.EVERYONE }, { lfsAvailable: true }, ); expect(wrapper.find('[name="project[lfs_enabled]"]').props().disabledInput).toEqual(false); }); it('should disable the LFS input when the repository is disabled', () => { wrapper = overrideCurrentSettings( { repositoryAccessLevel: featureAccessLevel.NOT_ENABLED }, { lfsAvailable: true }, ); expect(wrapper.find('[name="project[lfs_enabled]"]').props().disabledInput).toEqual(true); }); describe.each` lfsObjectsExist | lfsEnabled | isShown ${true} | ${true} | ${false} ${true} | ${false} | ${true} ${false} | ${true} | ${false} ${false} | ${false} | ${false} `( 'with (lfsObjectsExist = $lfsObjectsExist, lfsEnabled = $lfsEnabled)', ({ lfsObjectsExist, lfsEnabled, isShown }) => { beforeEach(() => { wrapper = mountComponent({ lfsObjectsExist, currentSettings: { lfsEnabled } }, mount); }); if (isShown) { it('shows warning message', () => { const message = findLFSSettingsMessage(); const link = message.find('a'); expect(message.text()).toContain( 'LFS objects from this repository are still available to forks', ); expect(link.text()).toEqual('How do I remove them?'); expect(link.attributes('href')).toEqual( '/help/topics/git/lfs/index#removing-objects-from-lfs', ); }); } else { it('does not show warning message', () => { expect(findLFSSettingsMessage().exists()).toEqual(false); }); } }, ); }); describe('Packages', () => { it('should show the packages settings if packages are available', () => { wrapper.setProps({ packagesAvailable: true }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'package-settings' }).exists()).toEqual(true); }); }); it('should hide the packages settings if packages are not available', () => { wrapper.setProps({ packagesAvailable: false }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'package-settings' }).exists()).toEqual(false); }); }); it('should set the package settings help path', () => { wrapper.setProps({ packagesAvailable: true }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'package-settings' }).props().helpPath).toBe( defaultProps.packagesHelpPath, ); }); }); it('should enable the packages input when the repository is enabled', () => { wrapper = overrideCurrentSettings( { repositoryAccessLevel: featureAccessLevel.EVERYONE }, { packagesAvailable: true }, ); expect(wrapper.find('[name="project[packages_enabled]"]').props().disabledInput).toEqual( false, ); }); it('should disable the packages input when the repository is disabled', () => { wrapper = overrideCurrentSettings( { repositoryAccessLevel: featureAccessLevel.NOT_ENABLED }, { packagesAvailable: true }, ); expect(wrapper.find('[name="project[packages_enabled]"]').props().disabledInput).toEqual( true, ); }); }); describe('Pages', () => { it.each` pagesAvailable | pagesAccessControlEnabled | visibility ${true} | ${true} | ${'show'} ${true} | ${false} | ${'hide'} ${false} | ${true} | ${'hide'} ${false} | ${false} | ${'hide'} `( 'should $visibility the page settings if pagesAvailable is $pagesAvailable and pagesAccessControlEnabled is $pagesAccessControlEnabled', ({ pagesAvailable, pagesAccessControlEnabled, visibility }) => { wrapper.setProps({ pagesAvailable, pagesAccessControlEnabled }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'pages-settings' }).exists()).toBe(visibility === 'show'); }); }, ); it('should set the pages settings help path', () => { wrapper.setProps({ pagesAvailable: true, pagesAccessControlEnabled: true }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'pages-settings' }).props().helpPath).toBe( defaultProps.pagesHelpPath, ); }); }); }); describe('Email notifications', () => { it('should show the disable email notifications input if emails an be disabled', () => { wrapper.setProps({ canDisableEmails: true }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'email-settings' }).exists()).toBe(true); }); }); it('should hide the disable email notifications input if emails cannot be disabled', () => { wrapper.setProps({ canDisableEmails: false }); return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'email-settings' }).exists()).toBe(false); }); }); }); describe('Default award emojis', () => { it('should show the "Show default award emojis" input', () => { return wrapper.vm.$nextTick(() => { expect( wrapper .find('input[name="project[project_setting_attributes][show_default_award_emojis]"]') .exists(), ).toBe(true); }); }); }); describe('Metrics dashboard', () => { it('should show the metrics dashboard access toggle', () => { return wrapper.vm.$nextTick(() => { expect(wrapper.find({ ref: 'metrics-visibility-settings' }).exists()).toBe(true); }); }); it('should set the visibility level description based upon the selected visibility level', () => { wrapper .find('[name="project[project_feature_attributes][metrics_dashboard_access_level]"]') .setValue(visibilityOptions.PUBLIC); expect(wrapper.vm.metricsDashboardAccessLevel).toBe(visibilityOptions.PUBLIC); }); it('should contain help text', () => { expect(wrapper.find({ ref: 'metrics-visibility-settings' }).props().helpText).toEqual( 'With Metrics Dashboard you can visualize this project performance metrics', ); }); it('should disable the metrics visibility dropdown when the project visibility level changes to private', () => { wrapper = overrideCurrentSettings({ visibilityLevel: visibilityOptions.PRIVATE }); const metricsSettingsRow = wrapper.find({ ref: 'metrics-visibility-settings' }); expect(wrapper.vm.metricsOptionsDropdownEnabled).toBe(true); expect(metricsSettingsRow.find('select').attributes('disabled')).toEqual('disabled'); }); }); });