Commit fc7019a2 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera Committed by Phil Hughes

Setting for duplicate generic package uploads

parent c7e05e5a
<script>
import { GlSprintf, GlToggle, GlFormGroup, GlFormInput } from '@gitlab/ui';
import { isEqual } from 'lodash';
import {
DUPLICATES_TOGGLE_LABEL,
DUPLICATES_ALLOWED_DISABLED,
DUPLICATES_ALLOWED_ENABLED,
DUPLICATES_SETTING_EXCEPTION_TITLE,
DUPLICATES_SETTINGS_EXCEPTION_LEGEND,
} from '~/packages_and_registries/settings/group/constants';
export default {
name: 'DuplicatesSettings',
i18n: {
DUPLICATES_TOGGLE_LABEL,
DUPLICATES_SETTING_EXCEPTION_TITLE,
DUPLICATES_SETTINGS_EXCEPTION_LEGEND,
},
components: {
GlSprintf,
GlToggle,
GlFormGroup,
GlFormInput,
},
props: {
loading: {
type: Boolean,
required: false,
default: false,
},
duplicatesAllowed: {
type: Boolean,
default: false,
required: false,
},
duplicateExceptionRegex: {
type: String,
default: '',
required: false,
},
duplicateExceptionRegexError: {
type: String,
default: '',
required: false,
},
modelNames: {
type: Object,
required: true,
validator(value) {
return isEqual(Object.keys(value), ['allowed', 'exception']);
},
},
toggleQaSelector: {
type: String,
required: false,
default: null,
},
labelQaSelector: {
type: String,
required: false,
default: null,
},
},
computed: {
enabledButtonLabel() {
return this.duplicatesAllowed ? DUPLICATES_ALLOWED_ENABLED : DUPLICATES_ALLOWED_DISABLED;
},
isExceptionRegexValid() {
return !this.duplicateExceptionRegexError;
},
},
methods: {
update(type, value) {
this.$emit('update', { [type]: value });
},
},
};
</script>
<template>
<form>
<div class="gl-display-flex">
<gl-toggle
:data-qa-selector="toggleQaSelector"
:label="$options.i18n.DUPLICATES_TOGGLE_LABEL"
label-position="hidden"
:value="duplicatesAllowed"
@change="update(modelNames.allowed, $event)"
/>
<div class="gl-ml-5">
<div data-testid="toggle-label" :data-qa-selector="labelQaSelector">
<gl-sprintf :message="enabledButtonLabel">
<template #bold="{ content }">
<strong>{{ content }}</strong>
</template>
</gl-sprintf>
</div>
<gl-form-group
v-if="!duplicatesAllowed"
class="gl-mt-4"
:label="$options.i18n.DUPLICATES_SETTING_EXCEPTION_TITLE"
label-size="sm"
:state="isExceptionRegexValid"
:invalid-feedback="duplicateExceptionRegexError"
:description="$options.i18n.DUPLICATES_SETTINGS_EXCEPTION_LEGEND"
label-for="maven-duplicated-settings-regex-input"
>
<gl-form-input
id="maven-duplicated-settings-regex-input"
:value="duplicateExceptionRegex"
@change="update(modelNames.exception, $event)"
/>
</gl-form-group>
</div>
</div>
</form>
</template>
<script>
import { s__ } from '~/locale';
import SettingsTitles from '~/packages_and_registries/settings/group/components/settings_titles.vue';
export default {
name: 'GenericSettings',
components: {
SettingsTitles,
},
i18n: {
title: s__('PackageRegistry|Generic'),
subTitle: s__('PackageRegistry|Settings for Generic packages'),
},
modelNames: {
allowed: 'genericDuplicatesAllowed',
exception: 'genericDuplicateExceptionRegex',
},
};
</script>
<template>
<div>
<settings-titles :title="$options.i18n.title" :sub-title="$options.i18n.subTitle" />
<slot :model-names="$options.modelNames"></slot>
</div>
</template>
<script> <script>
import { GlSprintf, GlLink, GlAlert } from '@gitlab/ui'; import { GlSprintf, GlLink, GlAlert } from '@gitlab/ui';
import DuplicatesSettings from '~/packages_and_registries/settings/group/components/duplicates_settings.vue';
import GenericSettings from '~/packages_and_registries/settings/group/components/generic_settings.vue';
import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue'; import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue';
import { import {
PACKAGE_SETTINGS_HEADER, PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION, PACKAGE_SETTINGS_DESCRIPTION,
...@@ -30,6 +31,8 @@ export default { ...@@ -30,6 +31,8 @@ export default {
GlLink, GlLink,
SettingsBlock, SettingsBlock,
MavenSettings, MavenSettings,
GenericSettings,
DuplicatesSettings,
}, },
inject: ['defaultExpanded', 'groupPath'], inject: ['defaultExpanded', 'groupPath'],
apollo: { apollo: {
...@@ -128,13 +131,32 @@ export default { ...@@ -128,13 +131,32 @@ export default {
</span> </span>
</template> </template>
<template #default> <template #default>
<maven-settings <maven-settings data-testid="maven-settings">
:maven-duplicates-allowed="packageSettings.mavenDuplicatesAllowed" <template #default="{ modelNames }">
:maven-duplicate-exception-regex="packageSettings.mavenDuplicateExceptionRegex" <duplicates-settings
:maven-duplicate-exception-regex-error="errors.mavenDuplicateExceptionRegex" :duplicates-allowed="packageSettings.mavenDuplicatesAllowed"
:loading="isLoading" :duplicate-exception-regex="packageSettings.mavenDuplicateExceptionRegex"
@update="updateSettings" :duplicate-exception-regex-error="errors.mavenDuplicateExceptionRegex"
/> :model-names="modelNames"
:loading="isLoading"
toggle-qa-selector="allow_duplicates_toggle"
label-qa-selector="allow_duplicates_label"
@update="updateSettings"
/>
</template>
</maven-settings>
<generic-settings class="gl-mt-6" data-testid="generic-settings">
<template #default="{ modelNames }">
<duplicates-settings
:duplicates-allowed="packageSettings.genericDuplicatesAllowed"
:duplicate-exception-regex="packageSettings.genericDuplicateExceptionRegex"
:duplicate-exception-regex-error="errors.genericDuplicateExceptionRegex"
:model-names="modelNames"
:loading="isLoading"
@update="updateSettings"
/>
</template>
</generic-settings>
</template> </template>
</settings-block> </settings-block>
</div> </div>
......
<script> <script>
import { GlSprintf, GlToggle, GlFormGroup, GlFormInput } from '@gitlab/ui'; import { s__ } from '~/locale';
import SettingsTitles from '~/packages_and_registries/settings/group/components/settings_titles.vue';
import {
MAVEN_TOGGLE_LABEL,
MAVEN_TITLE,
MAVEN_SETTINGS_SUBTITLE,
MAVEN_DUPLICATES_ALLOWED_DISABLED,
MAVEN_DUPLICATES_ALLOWED_ENABLED,
MAVEN_SETTING_EXCEPTION_TITLE,
MAVEN_SETTINGS_EXCEPTION_LEGEND,
MAVEN_DUPLICATES_ALLOWED,
MAVEN_DUPLICATE_EXCEPTION_REGEX,
} from '~/packages_and_registries/settings/group/constants';
export default { export default {
name: 'MavenSettings', name: 'MavenSettings',
i18n: {
MAVEN_TOGGLE_LABEL,
MAVEN_TITLE,
MAVEN_SETTINGS_SUBTITLE,
MAVEN_SETTING_EXCEPTION_TITLE,
MAVEN_SETTINGS_EXCEPTION_LEGEND,
},
modelNames: {
MAVEN_DUPLICATES_ALLOWED,
MAVEN_DUPLICATE_EXCEPTION_REGEX,
},
components: { components: {
GlSprintf, SettingsTitles,
GlToggle,
GlFormGroup,
GlFormInput,
},
props: {
loading: {
type: Boolean,
required: false,
default: false,
},
mavenDuplicatesAllowed: {
type: Boolean,
default: false,
required: true,
},
mavenDuplicateExceptionRegex: {
type: String,
default: '',
required: true,
},
mavenDuplicateExceptionRegexError: {
type: String,
default: '',
required: false,
},
}, },
computed: { i18n: {
enabledButtonLabel() { title: s__('PackageRegistry|Maven'),
return this.mavenDuplicatesAllowed subTitle: s__('PackageRegistry|Settings for Maven packages'),
? MAVEN_DUPLICATES_ALLOWED_ENABLED
: MAVEN_DUPLICATES_ALLOWED_DISABLED;
},
isMavenDuplicateExceptionRegexValid() {
return !this.mavenDuplicateExceptionRegexError;
},
}, },
methods: { modelNames: {
update(type, value) { allowed: 'mavenDuplicatesAllowed',
this.$emit('update', { [type]: value }); exception: 'mavenDuplicateExceptionRegex',
},
}, },
}; };
</script> </script>
<template> <template>
<div> <div>
<h5 class="gl-border-b-solid gl-border-b-1 gl-border-gray-200"> <settings-titles :title="$options.i18n.title" :sub-title="$options.i18n.subTitle" />
{{ $options.i18n.MAVEN_TITLE }} <slot :model-names="$options.modelNames"></slot>
</h5>
<p>{{ $options.i18n.MAVEN_SETTINGS_SUBTITLE }}</p>
<form>
<div class="gl-display-flex">
<gl-toggle
data-qa-selector="allow_duplicates_toggle"
:label="$options.i18n.MAVEN_TOGGLE_LABEL"
label-position="hidden"
:value="mavenDuplicatesAllowed"
@change="update($options.modelNames.MAVEN_DUPLICATES_ALLOWED, $event)"
/>
<div class="gl-ml-5">
<div data-testid="toggle-label" data-qa-selector="allow_duplicates_label">
<gl-sprintf :message="enabledButtonLabel">
<template #bold="{ content }">
<strong>{{ content }}</strong>
</template>
</gl-sprintf>
</div>
<gl-form-group
v-if="!mavenDuplicatesAllowed"
class="gl-mt-4"
:label="$options.i18n.MAVEN_SETTING_EXCEPTION_TITLE"
label-size="sm"
:state="isMavenDuplicateExceptionRegexValid"
:invalid-feedback="mavenDuplicateExceptionRegexError"
:description="$options.i18n.MAVEN_SETTINGS_EXCEPTION_LEGEND"
label-for="maven-duplicated-settings-regex-input"
>
<gl-form-input
id="maven-duplicated-settings-regex-input"
:value="mavenDuplicateExceptionRegex"
@change="update($options.modelNames.MAVEN_DUPLICATE_EXCEPTION_REGEX, $event)"
/>
</gl-form-group>
</div>
</div>
</form>
</div> </div>
</template> </template>
<script>
export default {
name: 'SettingsTitle',
props: {
title: {
type: String,
required: true,
},
subTitle: {
type: String,
required: true,
},
},
};
</script>
<template>
<div>
<h5 class="gl-border-b-solid gl-border-b-1 gl-border-gray-200">
{{ title }}
</h5>
<p>{{ subTitle }}</p>
<slot></slot>
</div>
</template>
...@@ -6,17 +6,15 @@ export const PACKAGE_SETTINGS_DESCRIPTION = s__( ...@@ -6,17 +6,15 @@ export const PACKAGE_SETTINGS_DESCRIPTION = s__(
'PackageRegistry|GitLab Packages allows organizations to utilize GitLab as a private repository for a variety of common package formats. %{linkStart}More Information%{linkEnd}', 'PackageRegistry|GitLab Packages allows organizations to utilize GitLab as a private repository for a variety of common package formats. %{linkStart}More Information%{linkEnd}',
); );
export const MAVEN_TITLE = s__('PackageRegistry|Maven'); export const DUPLICATES_TOGGLE_LABEL = s__('PackageRegistry|Allow duplicates');
export const MAVEN_SETTINGS_SUBTITLE = s__('PackageRegistry|Settings for Maven packages'); export const DUPLICATES_ALLOWED_DISABLED = s__(
export const MAVEN_TOGGLE_LABEL = s__('PackageRegistry|Allow duplicates');
export const MAVEN_DUPLICATES_ALLOWED_DISABLED = s__(
'PackageRegistry|%{boldStart}Do not allow duplicates%{boldEnd} - Packages with the same name and version are rejected.', 'PackageRegistry|%{boldStart}Do not allow duplicates%{boldEnd} - Packages with the same name and version are rejected.',
); );
export const MAVEN_DUPLICATES_ALLOWED_ENABLED = s__( export const DUPLICATES_ALLOWED_ENABLED = s__(
'PackageRegistry|%{boldStart}Allow duplicates%{boldEnd} - Packages with the same name and version are accepted.', 'PackageRegistry|%{boldStart}Allow duplicates%{boldEnd} - Packages with the same name and version are accepted.',
); );
export const MAVEN_SETTING_EXCEPTION_TITLE = __('Exceptions'); export const DUPLICATES_SETTING_EXCEPTION_TITLE = __('Exceptions');
export const MAVEN_SETTINGS_EXCEPTION_LEGEND = s__( export const DUPLICATES_SETTINGS_EXCEPTION_LEGEND = s__(
'PackageRegistry|Packages can be published if their name or version matches this regex', 'PackageRegistry|Packages can be published if their name or version matches this regex',
); );
......
...@@ -3,6 +3,8 @@ mutation updateNamespacePackageSettings($input: UpdateNamespacePackageSettingsIn ...@@ -3,6 +3,8 @@ mutation updateNamespacePackageSettings($input: UpdateNamespacePackageSettingsIn
packageSettings { packageSettings {
mavenDuplicatesAllowed mavenDuplicatesAllowed
mavenDuplicateExceptionRegex mavenDuplicateExceptionRegex
genericDuplicatesAllowed
genericDuplicateExceptionRegex
} }
errors errors
} }
......
...@@ -3,6 +3,8 @@ query getGroupPackagesSettings($fullPath: ID!) { ...@@ -3,6 +3,8 @@ query getGroupPackagesSettings($fullPath: ID!) {
packageSettings { packageSettings {
mavenDuplicatesAllowed mavenDuplicatesAllowed
mavenDuplicateExceptionRegex mavenDuplicateExceptionRegex
genericDuplicatesAllowed
genericDuplicateExceptionRegex
} }
} }
} }
...@@ -23365,6 +23365,9 @@ msgstr "" ...@@ -23365,6 +23365,9 @@ msgstr ""
msgid "PackageRegistry|RubyGems" msgid "PackageRegistry|RubyGems"
msgstr "" msgstr ""
msgid "PackageRegistry|Settings for Generic packages"
msgstr ""
msgid "PackageRegistry|Settings for Maven packages" msgid "PackageRegistry|Settings for Maven packages"
msgstr "" msgstr ""
......
...@@ -11,7 +11,7 @@ module QA ...@@ -11,7 +11,7 @@ module QA
element :package_registry_settings_content element :package_registry_settings_content
end end
view 'app/assets/javascripts/packages_and_registries/settings/group/components/maven_settings.vue' do view 'app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue' do
element :allow_duplicates_toggle element :allow_duplicates_toggle
element :allow_duplicates_label element :allow_duplicates_label
end end
......
...@@ -66,28 +66,31 @@ RSpec.describe 'Group Packages & Registries settings' do ...@@ -66,28 +66,31 @@ RSpec.describe 'Group Packages & Registries settings' do
it 'automatically saves changes to the server', :js do it 'automatically saves changes to the server', :js do
visit_settings_page visit_settings_page
expect(page).to have_content('Allow duplicates') within '[data-testid="maven-settings"]' do
expect(page).to have_content('Allow duplicates')
find('.gl-toggle').click find('.gl-toggle').click
expect(page).to have_content('Do not allow duplicates') expect(page).to have_content('Do not allow duplicates')
visit_settings_page visit_settings_page
expect(page).to have_content('Do not allow duplicates') expect(page).to have_content('Do not allow duplicates')
end
end end
it 'shows an error on wrong regex', :js do it 'shows an error on wrong regex', :js do
visit_settings_page visit_settings_page
expect(page).to have_content('Allow duplicates') within '[data-testid="maven-settings"]' do
expect(page).to have_content('Allow duplicates')
find('.gl-toggle').click
expect(page).to have_content('Do not allow duplicates') find('.gl-toggle').click
fill_in 'Exceptions', with: ')' expect(page).to have_content('Do not allow duplicates')
fill_in 'Exceptions', with: ')'
end
# simulate blur event # simulate blur event
find('body').click find('body').click
...@@ -98,11 +101,13 @@ RSpec.describe 'Group Packages & Registries settings' do ...@@ -98,11 +101,13 @@ RSpec.describe 'Group Packages & Registries settings' do
it 'works correctly', :js do it 'works correctly', :js do
visit_sub_group_settings_page visit_sub_group_settings_page
expect(page).to have_content('Allow duplicates') within '[data-testid="maven-settings"]' do
expect(page).to have_content('Allow duplicates')
find('.gl-toggle').click find('.gl-toggle').click
expect(page).to have_content('Do not allow duplicates') expect(page).to have_content('Do not allow duplicates')
end
end end
end end
end end
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`settings_titles renders properly 1`] = `
<div>
<h5
class="gl-border-b-solid gl-border-b-1 gl-border-gray-200"
>
foo
</h5>
<p>
bar
</p>
</div>
`;
import { GlSprintf, GlToggle, GlFormGroup, GlFormInput } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import component from '~/packages_and_registries/settings/group/components/duplicates_settings.vue';
import {
DUPLICATES_TOGGLE_LABEL,
DUPLICATES_ALLOWED_ENABLED,
DUPLICATES_ALLOWED_DISABLED,
DUPLICATES_SETTING_EXCEPTION_TITLE,
DUPLICATES_SETTINGS_EXCEPTION_LEGEND,
} from '~/packages_and_registries/settings/group/constants';
describe('Duplicates Settings', () => {
let wrapper;
const defaultProps = {
duplicatesAllowed: false,
duplicateExceptionRegex: 'foo',
modelNames: {
allowed: 'allowedModel',
exception: 'exceptionModel',
},
};
const mountComponent = (propsData = defaultProps) => {
wrapper = shallowMount(component, {
propsData,
stubs: {
GlSprintf,
},
});
};
afterEach(() => {
wrapper.destroy();
});
const findToggle = () => wrapper.findComponent(GlToggle);
const findToggleLabel = () => wrapper.find('[data-testid="toggle-label"');
const findInputGroup = () => wrapper.findComponent(GlFormGroup);
const findInput = () => wrapper.findComponent(GlFormInput);
it('has a toggle', () => {
mountComponent();
expect(findToggle().exists()).toBe(true);
expect(findToggle().props()).toMatchObject({
label: DUPLICATES_TOGGLE_LABEL,
value: defaultProps.duplicatesAllowed,
});
});
it('toggle emits an update event', () => {
mountComponent();
findToggle().vm.$emit('change', false);
expect(wrapper.emitted('update')).toStrictEqual([
[{ [defaultProps.modelNames.allowed]: false }],
]);
});
describe('when the duplicates are disabled', () => {
it('the toggle has the disabled message', () => {
mountComponent();
expect(findToggleLabel().exists()).toBe(true);
expect(findToggleLabel().text()).toMatchInterpolatedText(DUPLICATES_ALLOWED_DISABLED);
});
it('shows a form group with an input field', () => {
mountComponent();
expect(findInputGroup().exists()).toBe(true);
expect(findInputGroup().attributes()).toMatchObject({
'label-for': 'maven-duplicated-settings-regex-input',
label: DUPLICATES_SETTING_EXCEPTION_TITLE,
description: DUPLICATES_SETTINGS_EXCEPTION_LEGEND,
});
});
it('shows an input field', () => {
mountComponent();
expect(findInput().exists()).toBe(true);
expect(findInput().attributes()).toMatchObject({
id: 'maven-duplicated-settings-regex-input',
value: defaultProps.duplicateExceptionRegex,
});
});
it('input change event emits an update event', () => {
mountComponent();
findInput().vm.$emit('change', 'bar');
expect(wrapper.emitted('update')).toStrictEqual([
[{ [defaultProps.modelNames.exception]: 'bar' }],
]);
});
describe('valid state', () => {
it('form group has correct props', () => {
mountComponent();
expect(findInputGroup().attributes()).toMatchObject({
state: 'true',
'invalid-feedback': '',
});
});
});
describe('invalid state', () => {
it('form group has correct props', () => {
const propsWithError = {
...defaultProps,
duplicateExceptionRegexError: 'some error string',
};
mountComponent(propsWithError);
expect(findInputGroup().attributes()).toMatchObject({
'invalid-feedback': propsWithError.duplicateExceptionRegexError,
});
});
});
});
describe('when the duplicates are enabled', () => {
it('has the correct toggle label', () => {
mountComponent({ ...defaultProps, duplicatesAllowed: true });
expect(findToggleLabel().exists()).toBe(true);
expect(findToggleLabel().text()).toMatchInterpolatedText(DUPLICATES_ALLOWED_ENABLED);
});
it('hides the form input group', () => {
mountComponent({ ...defaultProps, duplicatesAllowed: true });
expect(findInputGroup().exists()).toBe(false);
});
});
});
import { shallowMount } from '@vue/test-utils';
import GenericSettings from '~/packages_and_registries/settings/group/components/generic_settings.vue';
import SettingsTitles from '~/packages_and_registries/settings/group/components/settings_titles.vue';
describe('generic_settings', () => {
let wrapper;
const mountComponent = () => {
wrapper = shallowMount(GenericSettings, {
scopedSlots: {
default: '<div data-testid="default-slot">{{props.modelNames}}</div>',
},
});
};
const findSettingsTitle = () => wrapper.findComponent(SettingsTitles);
const findDefaultSlot = () => wrapper.find('[data-testid="default-slot"]');
afterEach(() => {
wrapper.destroy();
});
describe('title component', () => {
it('has a title component', () => {
mountComponent();
expect(findSettingsTitle().exists()).toBe(true);
});
it('passes the correct props', () => {
mountComponent();
expect(findSettingsTitle().props()).toMatchObject({
title: 'Generic',
subTitle: 'Settings for Generic packages',
});
});
});
describe('default slot', () => {
it('accept a default slots', () => {
mountComponent();
expect(findDefaultSlot().exists()).toBe(true);
});
it('binds model names', () => {
mountComponent();
expect(findDefaultSlot().text()).toContain('genericDuplicatesAllowed');
expect(findDefaultSlot().text()).toContain('genericDuplicateExceptionRegex');
});
});
});
...@@ -3,6 +3,8 @@ import { shallowMount, createLocalVue } from '@vue/test-utils'; ...@@ -3,6 +3,8 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import DuplicatesSettings from '~/packages_and_registries/settings/group/components/duplicates_settings.vue';
import GenericSettings from '~/packages_and_registries/settings/group/components/generic_settings.vue';
import component from '~/packages_and_registries/settings/group/components/group_settings_app.vue'; import component from '~/packages_and_registries/settings/group/components/group_settings_app.vue';
import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue'; import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue';
import { import {
...@@ -63,6 +65,8 @@ describe('Group Settings App', () => { ...@@ -63,6 +65,8 @@ describe('Group Settings App', () => {
stubs: { stubs: {
GlSprintf, GlSprintf,
SettingsBlock, SettingsBlock,
MavenSettings,
GenericSettings,
}, },
mocks: { mocks: {
$toast: { $toast: {
...@@ -78,14 +82,17 @@ describe('Group Settings App', () => { ...@@ -78,14 +82,17 @@ describe('Group Settings App', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
}); });
const findSettingsBlock = () => wrapper.find(SettingsBlock); const findSettingsBlock = () => wrapper.findComponent(SettingsBlock);
const findDescription = () => wrapper.find('[data-testid="description"'); const findDescription = () => wrapper.find('[data-testid="description"');
const findLink = () => wrapper.find(GlLink); const findLink = () => wrapper.findComponent(GlLink);
const findMavenSettings = () => wrapper.find(MavenSettings); const findAlert = () => wrapper.findComponent(GlAlert);
const findAlert = () => wrapper.find(GlAlert); const findMavenSettings = () => wrapper.findComponent(MavenSettings);
const findMavenDuplicatedSettings = () => findMavenSettings().findComponent(DuplicatesSettings);
const findGenericSettings = () => wrapper.findComponent(GenericSettings);
const findGenericDuplicatedSettings = () =>
findGenericSettings().findComponent(DuplicatesSettings);
const waitForApolloQueryAndRender = async () => { const waitForApolloQueryAndRender = async () => {
await waitForPromises(); await waitForPromises();
...@@ -93,7 +100,7 @@ describe('Group Settings App', () => { ...@@ -93,7 +100,7 @@ describe('Group Settings App', () => {
}; };
const emitSettingsUpdate = (override) => { const emitSettingsUpdate = (override) => {
findMavenSettings().vm.$emit('update', { findMavenDuplicatedSettings().vm.$emit('update', {
mavenDuplicateExceptionRegex: ')', mavenDuplicateExceptionRegex: ')',
...override, ...override,
}); });
...@@ -152,7 +159,7 @@ describe('Group Settings App', () => { ...@@ -152,7 +159,7 @@ describe('Group Settings App', () => {
it('assigns duplication allowness and exception props', async () => { it('assigns duplication allowness and exception props', async () => {
mountComponent(); mountComponent();
expect(findMavenSettings().props('loading')).toBe(true); expect(findMavenDuplicatedSettings().props('loading')).toBe(true);
await waitForApolloQueryAndRender(); await waitForApolloQueryAndRender();
...@@ -161,10 +168,10 @@ describe('Group Settings App', () => { ...@@ -161,10 +168,10 @@ describe('Group Settings App', () => {
mavenDuplicateExceptionRegex, mavenDuplicateExceptionRegex,
} = groupPackageSettingsMock.data.group.packageSettings; } = groupPackageSettingsMock.data.group.packageSettings;
expect(findMavenSettings().props()).toMatchObject({ expect(findMavenDuplicatedSettings().props()).toMatchObject({
mavenDuplicatesAllowed, duplicatesAllowed: mavenDuplicatesAllowed,
mavenDuplicateExceptionRegex, duplicateExceptionRegex: mavenDuplicateExceptionRegex,
mavenDuplicateExceptionRegexError: '', duplicateExceptionRegexError: '',
loading: false, loading: false,
}); });
}); });
...@@ -183,6 +190,49 @@ describe('Group Settings App', () => { ...@@ -183,6 +190,49 @@ describe('Group Settings App', () => {
}); });
}); });
describe('generic settings', () => {
it('exists', () => {
mountComponent();
expect(findGenericSettings().exists()).toBe(true);
});
it('assigns duplication allowness and exception props', async () => {
mountComponent();
expect(findGenericDuplicatedSettings().props('loading')).toBe(true);
await waitForApolloQueryAndRender();
const {
genericDuplicatesAllowed,
genericDuplicateExceptionRegex,
} = groupPackageSettingsMock.data.group.packageSettings;
expect(findGenericDuplicatedSettings().props()).toMatchObject({
duplicatesAllowed: genericDuplicatesAllowed,
duplicateExceptionRegex: genericDuplicateExceptionRegex,
duplicateExceptionRegexError: '',
loading: false,
});
});
it('on update event calls the mutation', async () => {
const mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationMock());
mountComponent({ mutationResolver });
await waitForApolloQueryAndRender();
findMavenDuplicatedSettings().vm.$emit('update', {
genericDuplicateExceptionRegex: ')',
});
expect(mutationResolver).toHaveBeenCalledWith({
input: { genericDuplicateExceptionRegex: ')', namespacePath: 'foo_group_path' },
});
});
});
describe('settings update', () => { describe('settings update', () => {
describe('success state', () => { describe('success state', () => {
it('shows a success alert', async () => { it('shows a success alert', async () => {
...@@ -205,21 +255,21 @@ describe('Group Settings App', () => { ...@@ -205,21 +255,21 @@ describe('Group Settings App', () => {
await waitForApolloQueryAndRender(); await waitForApolloQueryAndRender();
expect(findMavenSettings().props('mavenDuplicateExceptionRegex')).toBe(''); expect(findMavenDuplicatedSettings().props('duplicateExceptionRegex')).toBe('');
emitSettingsUpdate({ mavenDuplicateExceptionRegex }); emitSettingsUpdate({ mavenDuplicateExceptionRegex });
// wait for apollo to update the model with the optimistic response // wait for apollo to update the model with the optimistic response
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
expect(findMavenSettings().props('mavenDuplicateExceptionRegex')).toBe( expect(findMavenDuplicatedSettings().props('duplicateExceptionRegex')).toBe(
mavenDuplicateExceptionRegex, mavenDuplicateExceptionRegex,
); );
// wait for the call to resolve // wait for the call to resolve
await waitForPromises(); await waitForPromises();
expect(findMavenSettings().props('mavenDuplicateExceptionRegex')).toBe( expect(findMavenDuplicatedSettings().props('duplicateExceptionRegex')).toBe(
mavenDuplicateExceptionRegex, mavenDuplicateExceptionRegex,
); );
}); });
...@@ -245,7 +295,7 @@ describe('Group Settings App', () => { ...@@ -245,7 +295,7 @@ describe('Group Settings App', () => {
await waitForApolloQueryAndRender(); await waitForApolloQueryAndRender();
// errors are bound to the component // errors are bound to the component
expect(findMavenSettings().props('mavenDuplicateExceptionRegexError')).toBe( expect(findMavenDuplicatedSettings().props('duplicateExceptionRegexError')).toBe(
groupPackageSettingsMutationErrorMock.errors[0].extensions.problems[0].message, groupPackageSettingsMutationErrorMock.errors[0].extensions.problems[0].message,
); );
...@@ -258,7 +308,7 @@ describe('Group Settings App', () => { ...@@ -258,7 +308,7 @@ describe('Group Settings App', () => {
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
// errors are reset on mutation call // errors are reset on mutation call
expect(findMavenSettings().props('mavenDuplicateExceptionRegexError')).toBe(''); expect(findMavenDuplicatedSettings().props('duplicateExceptionRegexError')).toBe('');
}); });
it.each` it.each`
......
import { GlSprintf, GlToggle, GlFormGroup, GlFormInput } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import component from '~/packages_and_registries/settings/group/components/maven_settings.vue'; import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue';
import SettingsTitles from '~/packages_and_registries/settings/group/components/settings_titles.vue';
import { describe('maven_settings', () => {
MAVEN_TITLE,
MAVEN_SETTINGS_SUBTITLE,
MAVEN_DUPLICATES_ALLOWED_DISABLED,
MAVEN_DUPLICATES_ALLOWED_ENABLED,
MAVEN_SETTING_EXCEPTION_TITLE,
MAVEN_SETTINGS_EXCEPTION_LEGEND,
} from '~/packages_and_registries/settings/group/constants';
describe('Maven Settings', () => {
let wrapper; let wrapper;
const defaultProps = { const mountComponent = () => {
mavenDuplicatesAllowed: false, wrapper = shallowMount(MavenSettings, {
mavenDuplicateExceptionRegex: 'foo', scopedSlots: {
}; default: '<div data-testid="default-slot">{{props.modelNames}}</div>',
const mountComponent = (propsData = defaultProps) => {
wrapper = shallowMount(component, {
propsData,
stubs: {
GlSprintf,
}, },
}); });
}; };
const findSettingsTitle = () => wrapper.findComponent(SettingsTitles);
const findDefaultSlot = () => wrapper.find('[data-testid="default-slot"]');
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
}); });
const findTitle = () => wrapper.find('h5'); describe('title component', () => {
const findSubTitle = () => wrapper.find('p'); it('has a title component', () => {
const findToggle = () => wrapper.find(GlToggle);
const findToggleLabel = () => wrapper.find('[data-testid="toggle-label"');
const findInputGroup = () => wrapper.find(GlFormGroup);
const findInput = () => wrapper.find(GlFormInput);
it('has a title', () => {
mountComponent();
expect(findTitle().exists()).toBe(true);
expect(findTitle().text()).toBe(MAVEN_TITLE);
});
it('has a subtitle', () => {
mountComponent();
expect(findSubTitle().exists()).toBe(true);
expect(findSubTitle().text()).toBe(MAVEN_SETTINGS_SUBTITLE);
});
it('has a toggle', () => {
mountComponent();
expect(findToggle().exists()).toBe(true);
expect(findToggle().props()).toMatchObject({
label: component.i18n.MAVEN_TOGGLE_LABEL,
value: defaultProps.mavenDuplicatesAllowed,
});
});
it('toggle emits an update event', () => {
mountComponent();
findToggle().vm.$emit('change', false);
expect(wrapper.emitted('update')).toEqual([[{ mavenDuplicatesAllowed: false }]]);
});
describe('when the duplicates are disabled', () => {
it('the toggle has the disabled message', () => {
mountComponent(); mountComponent();
expect(findToggleLabel().exists()).toBe(true); expect(findSettingsTitle().exists()).toBe(true);
expect(findToggleLabel().text()).toMatchInterpolatedText(MAVEN_DUPLICATES_ALLOWED_DISABLED);
}); });
it('shows a form group with an input field', () => { it('passes the correct props', () => {
mountComponent(); mountComponent();
expect(findInputGroup().exists()).toBe(true); expect(findSettingsTitle().props()).toMatchObject({
title: 'Maven',
expect(findInputGroup().attributes()).toMatchObject({ subTitle: 'Settings for Maven packages',
'label-for': 'maven-duplicated-settings-regex-input',
label: MAVEN_SETTING_EXCEPTION_TITLE,
description: MAVEN_SETTINGS_EXCEPTION_LEGEND,
}); });
}); });
});
it('shows an input field', () => { describe('default slot', () => {
it('accept a default slots', () => {
mountComponent(); mountComponent();
expect(findInput().exists()).toBe(true); expect(findDefaultSlot().exists()).toBe(true);
expect(findInput().attributes()).toMatchObject({
id: 'maven-duplicated-settings-regex-input',
value: defaultProps.mavenDuplicateExceptionRegex,
});
}); });
it('input change event emits an update event', () => { it('binds model names', () => {
mountComponent(); mountComponent();
findInput().vm.$emit('change', 'bar'); expect(findDefaultSlot().text()).toContain('mavenDuplicatesAllowed');
expect(findDefaultSlot().text()).toContain('mavenDuplicateExceptionRegex');
expect(wrapper.emitted('update')).toEqual([[{ mavenDuplicateExceptionRegex: 'bar' }]]);
});
describe('valid state', () => {
it('form group has correct props', () => {
mountComponent();
expect(findInputGroup().attributes()).toMatchObject({
state: 'true',
'invalid-feedback': '',
});
});
});
describe('invalid state', () => {
it('form group has correct props', () => {
const propsWithError = {
...defaultProps,
mavenDuplicateExceptionRegexError: 'some error string',
};
mountComponent(propsWithError);
expect(findInputGroup().attributes()).toMatchObject({
'invalid-feedback': propsWithError.mavenDuplicateExceptionRegexError,
});
});
});
});
describe('when the duplicates are enabled', () => {
it('has the correct toggle label', () => {
mountComponent({ ...defaultProps, mavenDuplicatesAllowed: true });
expect(findToggleLabel().exists()).toBe(true);
expect(findToggleLabel().text()).toMatchInterpolatedText(MAVEN_DUPLICATES_ALLOWED_ENABLED);
});
it('hides the form input group', () => {
mountComponent({ ...defaultProps, mavenDuplicatesAllowed: true });
expect(findInputGroup().exists()).toBe(false);
}); });
}); });
}); });
import { shallowMount } from '@vue/test-utils';
import SettingsTitles from '~/packages_and_registries/settings/group/components/settings_titles.vue';
describe('settings_titles', () => {
let wrapper;
const mountComponent = () => {
wrapper = shallowMount(SettingsTitles, {
propsData: {
title: 'foo',
subTitle: 'bar',
},
});
};
afterEach(() => {
wrapper.destroy();
});
it('renders properly', () => {
mountComponent();
expect(wrapper.element).toMatchSnapshot();
});
});
...@@ -4,6 +4,8 @@ export const groupPackageSettingsMock = { ...@@ -4,6 +4,8 @@ export const groupPackageSettingsMock = {
packageSettings: { packageSettings: {
mavenDuplicatesAllowed: true, mavenDuplicatesAllowed: true,
mavenDuplicateExceptionRegex: '', mavenDuplicateExceptionRegex: '',
genericDuplicatesAllowed: true,
genericDuplicateExceptionRegex: '',
}, },
}, },
}, },
...@@ -15,6 +17,8 @@ export const groupPackageSettingsMutationMock = (override) => ({ ...@@ -15,6 +17,8 @@ export const groupPackageSettingsMutationMock = (override) => ({
packageSettings: { packageSettings: {
mavenDuplicatesAllowed: true, mavenDuplicatesAllowed: true,
mavenDuplicateExceptionRegex: 'latest[main]something', mavenDuplicateExceptionRegex: 'latest[main]something',
genericDuplicatesAllowed: true,
genericDuplicateExceptionRegex: 'latest[main]somethingGeneric',
}, },
errors: [], errors: [],
...override, ...override,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment