Commit 0f2bfab8 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera Committed by Savas Vedova

Wire mutation and optimistic response

- group settings app
- update optimist response signature
parent c43395da
<script>
import { GlSprintf, GlLink } from '@gitlab/ui';
import createFlash from '~/flash';
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue';
import {
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
PACKAGES_DOCS_PATH,
} from '../constants';
import getGroupPackagesSettingsQuery from '../graphql/queries/get_group_packages_settings.query.graphql';
ERROR_UPDATING_SETTINGS,
SUCCESS_UPDATING_SETTINGS,
} from '~/packages_and_registries/settings/group/constants';
import { updateGroupPackageSettings } from '~/packages_and_registries/settings/group/graphql/utils/cache_update';
import { updateGroupPackagesSettingsOptimisticResponse } from '~/packages_and_registries/settings/group/graphql/utils/optimistic_responses';
import getGroupPackagesSettingsQuery from '~/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql';
import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql';
export default {
name: 'GroupSettingsApp',
......@@ -22,18 +29,9 @@ export default {
GlSprintf,
GlLink,
SettingsBlock,
MavenSettings,
},
inject: {
defaultExpanded: {
type: Boolean,
default: false,
required: true,
},
groupPath: {
type: String,
required: true,
},
},
inject: ['defaultExpanded', 'groupPath'],
apollo: {
packageSettings: {
query: getGroupPackagesSettingsQuery,
......@@ -50,8 +48,55 @@ export default {
data() {
return {
packageSettings: {},
errors: {},
};
},
computed: {
isLoading() {
return this.$apollo.queries.packageSettings.loading;
},
},
methods: {
updateSettings(payload) {
this.errors = {};
return this.$apollo
.mutate({
mutation: updateNamespacePackageSettings,
variables: {
input: {
namespacePath: this.groupPath,
...payload,
},
},
update: updateGroupPackageSettings(this.groupPath),
optimisticResponse: updateGroupPackagesSettingsOptimisticResponse({
...this.packageSettings,
...payload,
}),
})
.then(({ data }) => {
if (data.updateNamespacePackageSettings?.errors?.length > 0) {
createFlash({ message: ERROR_UPDATING_SETTINGS, type: 'warning' });
} else {
createFlash({ message: SUCCESS_UPDATING_SETTINGS, type: 'success' });
}
})
.catch((e) => {
if (e.graphQLErrors) {
e.graphQLErrors.forEach((error) => {
const [
{
path: [key],
message,
},
] = error.extensions.problems;
this.errors = { ...this.errors, [key]: message };
});
}
createFlash({ message: ERROR_UPDATING_SETTINGS, type: 'warning' });
});
},
},
};
</script>
......@@ -70,6 +115,15 @@ export default {
</gl-sprintf>
</span>
</template>
<template #default>
<maven-settings
:maven-duplicates-allowed="packageSettings.mavenDuplicatesAllowed"
:maven-duplicate-exception-regex="packageSettings.mavenDuplicateExceptionRegex"
:maven-duplicate-exception-regex-error="errors.mavenDuplicateExceptionRegex"
:loading="isLoading"
@update="updateSettings"
/>
</template>
</settings-block>
</div>
</template>
<script>
import { GlSprintf, GlToggle, GlFormGroup, GlFormInput } from '@gitlab/ui';
import {
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 {
name: 'MavenSettings',
i18n: {
MAVEN_TITLE,
MAVEN_SETTINGS_SUBTITLE,
MAVEN_SETTING_EXCEPTION_TITLE,
MAVEN_SETTINGS_EXCEPTION_LEGEND,
},
modelNames: {
MAVEN_DUPLICATES_ALLOWED,
MAVEN_DUPLICATE_EXCEPTION_REGEX,
},
components: {
GlSprintf,
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: {
enabledButtonLabel() {
return this.mavenDuplicatesAllowed
? MAVEN_DUPLICATES_ALLOWED_ENABLED
: MAVEN_DUPLICATES_ALLOWED_DISABLED;
},
isMavenDuplicateExceptionRegexValid() {
return !this.mavenDuplicateExceptionRegexError;
},
},
methods: {
update(type, value) {
this.$emit('update', { [type]: value });
},
},
};
</script>
<template>
<div>
<h5 class="gl-border-b-solid gl-border-b-1 gl-border-gray-200">
{{ $options.i18n.MAVEN_TITLE }}
</h5>
<p>{{ $options.i18n.MAVEN_SETTINGS_SUBTITLE }}</p>
<form>
<div class="gl-display-flex">
<gl-toggle
:value="mavenDuplicatesAllowed"
@change="update($options.modelNames.MAVEN_DUPLICATES_ALLOWED, $event)"
/>
<div class="gl-ml-5">
<div data-testid="toggle-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>
</template>
import { s__ } from '~/locale';
import { s__, __ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
export const PACKAGE_SETTINGS_HEADER = s__('PackageRegistry|Package Registry');
......@@ -6,4 +6,26 @@ 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}',
);
export const MAVEN_TITLE = s__('PackageRegistry|Maven');
export const MAVEN_SETTINGS_SUBTITLE = s__('PackageRegistry|Settings for Maven packages');
export const MAVEN_DUPLICATES_ALLOWED_DISABLED = s__(
'PackageRegistry|%{boldStart}Do not allow duplicates%{boldEnd} - Packages with the same name and version are rejected.',
);
export const MAVEN_DUPLICATES_ALLOWED_ENABLED = s__(
'PackageRegistry|%{boldStart}Allow duplicates%{boldEnd} - Packages with the same name and version are accepted.',
);
export const MAVEN_SETTING_EXCEPTION_TITLE = __('Exceptions');
export const MAVEN_SETTINGS_EXCEPTION_LEGEND = s__(
'PackageRegistry|Packages can be published if their name or version matches this regex',
);
export const SUCCESS_UPDATING_SETTINGS = s__('PackageRegistry|Settings saved successfully');
export const ERROR_UPDATING_SETTINGS = s__(
'PackageRegistry|An error occurred while saving the settings',
);
// Parameters
export const PACKAGES_DOCS_PATH = helpPagePath('user/packages');
export const MAVEN_DUPLICATES_ALLOWED = 'mavenDuplicatesAllowed';
export const MAVEN_DUPLICATE_EXCEPTION_REGEX = 'mavenDuplicateExceptionRegex';
import { produce } from 'immer';
import getGroupPackagesSettingsQuery from '../queries/get_group_packages_settings.query.graphql';
export const updateGroupPackageSettings = (fullPath) => (client, { data: updatedData }) => {
const queryAndParams = {
query: getGroupPackagesSettingsQuery,
variables: { fullPath },
};
const sourceData = client.readQuery(queryAndParams);
const data = produce(sourceData, (draftState) => {
// eslint-disable-next-line no-param-reassign
draftState.group.packageSettings = {
...updatedData.updateNamespacePackageSettings.packageSettings,
};
});
client.writeQuery({
...queryAndParams,
data,
});
};
export const updateGroupPackagesSettingsOptimisticResponse = (changes) => ({
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename: 'Mutation',
updateNamespacePackageSettings: {
__typename: 'UpdateNamespacePackageSettingsPayload',
errors: [],
packageSettings: {
...changes,
},
},
});
......@@ -11828,6 +11828,9 @@ msgstr ""
msgid "Except policy:"
msgstr ""
msgid "Exceptions"
msgstr ""
msgid "Excess storage"
msgstr ""
......@@ -20795,6 +20798,12 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
msgid "PackageRegistry|%{boldStart}Allow duplicates%{boldEnd} - Packages with the same name and version are accepted."
msgstr ""
msgid "PackageRegistry|%{boldStart}Do not allow duplicates%{boldEnd} - Packages with the same name and version are rejected."
msgstr ""
msgid "PackageRegistry|%{name} version %{version} was first created %{datetime}"
msgstr ""
......@@ -20807,6 +20816,9 @@ msgstr ""
msgid "PackageRegistry|Add composer registry"
msgstr ""
msgid "PackageRegistry|An error occurred while saving the settings"
msgstr ""
msgid "PackageRegistry|App group: %{group}"
msgstr ""
......@@ -20951,6 +20963,9 @@ msgstr ""
msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, built by pipeline %{pipeline}, and published to the registry %{datetime}"
msgstr ""
msgid "PackageRegistry|Packages can be published if their name or version matches this regex"
msgstr ""
msgid "PackageRegistry|Pip Command"
msgstr ""
......@@ -20969,6 +20984,12 @@ msgstr ""
msgid "PackageRegistry|Remove package"
msgstr ""
msgid "PackageRegistry|Settings for Maven packages"
msgstr ""
msgid "PackageRegistry|Settings saved successfully"
msgstr ""
msgid "PackageRegistry|Sorry, your filter produced no results"
msgstr ""
......
......@@ -54,6 +54,37 @@ RSpec.describe 'Group Packages & Registries settings' do
expect(page).to have_content('Package Registry')
expect(page).to have_button('Collapse')
end
it 'automatically saves changes to the server', :js do
visit_settings_page
expect(page).to have_content('Allow duplicates')
find('.gl-toggle').click
expect(page).to have_content('Do not allow duplicates')
visit_settings_page
expect(page).to have_content('Do not allow duplicates')
end
it 'shows an error on wrong regex', :js do
visit_settings_page
expect(page).to have_content('Allow duplicates')
find('.gl-toggle').click
expect(page).to have_content('Do not allow duplicates')
fill_in 'Exceptions', with: ')'
# simulate blur event
find('body').click
expect(page).to have_content('is an invalid regexp')
end
end
def find_settings_menu
......
......@@ -2,16 +2,28 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlSprintf, GlLink } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import component from '~/packages_and_registries/settings/group/components/group_settings_app.vue';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import SettingsBlock from '~/vue_shared/components/settings/settings_block.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 {
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
PACKAGES_DOCS_PATH,
ERROR_UPDATING_SETTINGS,
SUCCESS_UPDATING_SETTINGS,
} from '~/packages_and_registries/settings/group/constants';
import getGroupPackagesSettingsQuery from '~/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql';
import { groupPackageSettingsMock } from '../mock_data';
import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql';
import {
groupPackageSettingsMock,
groupPackageSettingsMutationMock,
groupPackageSettingsMutationErrorMock,
} from '../mock_data';
jest.mock('~/flash');
const localVue = createLocalVue();
......@@ -27,10 +39,14 @@ describe('Group Settings App', () => {
const mountComponent = ({
provide = defaultProvide,
resolver = jest.fn().mockResolvedValue(groupPackageSettingsMock),
mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationMock()),
} = {}) => {
localVue.use(VueApollo);
const requestHandlers = [[getGroupPackagesSettingsQuery, resolver]];
const requestHandlers = [
[getGroupPackagesSettingsQuery, resolver],
[updateNamespacePackageSettings, mutationResolver],
];
apolloProvider = createMockApollo(requestHandlers);
......@@ -53,6 +69,19 @@ describe('Group Settings App', () => {
const findSettingsBlock = () => wrapper.find(SettingsBlock);
const findDescription = () => wrapper.find('[data-testid="description"');
const findLink = () => wrapper.find(GlLink);
const findMavenSettings = () => wrapper.find(MavenSettings);
const waitForApolloQueryAndRender = async () => {
await waitForPromises();
await wrapper.vm.$nextTick();
};
const emitSettingsUpdate = (override) => {
findMavenSettings().vm.$emit('update', {
mavenDuplicateExceptionRegex: ')',
...override,
});
};
it('renders a settings block', () => {
mountComponent();
......@@ -96,4 +125,157 @@ describe('Group Settings App', () => {
fullPath: defaultProvide.groupPath,
});
});
describe('maven settings', () => {
it('exists', () => {
mountComponent();
expect(findMavenSettings().exists()).toBe(true);
});
it('assigns duplication allowness and exception props', async () => {
mountComponent();
expect(findMavenSettings().props('loading')).toBe(true);
await waitForApolloQueryAndRender();
const {
mavenDuplicatesAllowed,
mavenDuplicateExceptionRegex,
} = groupPackageSettingsMock.data.group.packageSettings;
expect(findMavenSettings().props()).toMatchObject({
mavenDuplicatesAllowed,
mavenDuplicateExceptionRegex,
mavenDuplicateExceptionRegexError: '',
loading: false,
});
});
it('on update event calls the mutation', async () => {
const mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationMock());
mountComponent({ mutationResolver });
await waitForApolloQueryAndRender();
emitSettingsUpdate();
expect(mutationResolver).toHaveBeenCalledWith({
input: { mavenDuplicateExceptionRegex: ')', namespacePath: 'foo_group_path' },
});
});
});
describe('settings update', () => {
describe('success state', () => {
it('shows a success alert', async () => {
mountComponent();
await waitForApolloQueryAndRender();
emitSettingsUpdate();
await waitForPromises();
expect(createFlash).toHaveBeenCalledWith({
message: SUCCESS_UPDATING_SETTINGS,
type: 'success',
});
});
it('has an optimistic response', async () => {
const mavenDuplicateExceptionRegex = 'latest[master]something';
mountComponent();
await waitForApolloQueryAndRender();
expect(findMavenSettings().props('mavenDuplicateExceptionRegex')).toBe('');
emitSettingsUpdate({ mavenDuplicateExceptionRegex });
// wait for apollo to update the model with the optimistic response
await wrapper.vm.$nextTick();
expect(findMavenSettings().props('mavenDuplicateExceptionRegex')).toBe(
mavenDuplicateExceptionRegex,
);
// wait for the call to resolve
await waitForPromises();
expect(findMavenSettings().props('mavenDuplicateExceptionRegex')).toBe(
mavenDuplicateExceptionRegex,
);
});
});
describe('errors', () => {
it('mutation payload with root level errors', async () => {
// note this is a complex test that covers all the path around errors that are shown in the form
// it's one single it case, due to the expensive preparation and execution
const mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationErrorMock);
mountComponent({ mutationResolver });
await waitForApolloQueryAndRender();
emitSettingsUpdate();
await waitForApolloQueryAndRender();
// errors are bound to the component
expect(findMavenSettings().props('mavenDuplicateExceptionRegexError')).toBe(
groupPackageSettingsMutationErrorMock.errors[0].extensions.problems[0].message,
);
// general error message is shown
expect(createFlash).toHaveBeenCalledWith({
message: ERROR_UPDATING_SETTINGS,
type: 'warning',
});
emitSettingsUpdate();
await wrapper.vm.$nextTick();
// errors are reset on mutation call
expect(findMavenSettings().props('mavenDuplicateExceptionRegexError')).toBe('');
});
it('mutation payload with local errors', async () => {
const mutationResolver = jest
.fn()
.mockResolvedValue(groupPackageSettingsMutationMock({ errors: ['foo'] }));
mountComponent({ mutationResolver });
await waitForApolloQueryAndRender();
emitSettingsUpdate();
await waitForPromises();
expect(createFlash).toHaveBeenCalledWith({
message: ERROR_UPDATING_SETTINGS,
type: 'warning',
});
});
it('shows an error in case of network error', async () => {
const mutationResolver = jest.fn().mockRejectedValue();
mountComponent({ mutationResolver });
await waitForApolloQueryAndRender();
emitSettingsUpdate();
await waitForPromises();
expect(createFlash).toHaveBeenCalledWith({
message: ERROR_UPDATING_SETTINGS,
type: 'warning',
});
});
});
});
});
import { shallowMount } from '@vue/test-utils';
import { GlSprintf, GlToggle, GlFormGroup, GlFormInput } from '@gitlab/ui';
import component from '~/packages_and_registries/settings/group/components/maven_settings.vue';
import {
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;
const defaultProps = {
mavenDuplicatesAllowed: false,
mavenDuplicateExceptionRegex: 'foo',
};
const mountComponent = (propsData = defaultProps) => {
wrapper = shallowMount(component, {
propsData,
stubs: {
GlSprintf,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const findTitle = () => wrapper.find('h5');
const findSubTitle = () => wrapper.find('p');
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('value')).toBe(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();
expect(findToggleLabel().exists()).toBe(true);
expect(findToggleLabel().text()).toMatchInterpolatedText(MAVEN_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: MAVEN_SETTING_EXCEPTION_TITLE,
description: MAVEN_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.mavenDuplicateExceptionRegex,
});
});
it('input change event emits an update event', () => {
mountComponent();
findInput().vm.$emit('change', 'bar');
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 { updateGroupPackageSettings } from '~/packages_and_registries/settings/group/graphql/utils/cache_update';
import expirationPolicyQuery from '~/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql';
describe('Package and Registries settings group cache updates', () => {
let client;
const payload = {
data: {
updateNamespacePackageSettings: {
packageSettings: {
mavenDuplicatesAllowed: false,
mavenDuplicateExceptionRegex: 'latest[master]something',
},
},
},
};
const cacheMock = {
group: {
packageSettings: {
mavenDuplicatesAllowed: true,
mavenDuplicateExceptionRegex: '',
},
},
};
const queryAndVariables = {
query: expirationPolicyQuery,
variables: { fullPath: 'foo' },
};
beforeEach(() => {
client = {
readQuery: jest.fn().mockReturnValue(cacheMock),
writeQuery: jest.fn(),
};
});
describe('updateGroupPackageSettings', () => {
it('calls readQuery', () => {
updateGroupPackageSettings('foo')(client, payload);
expect(client.readQuery).toHaveBeenCalledWith(queryAndVariables);
});
it('writes the correct result in the cache', () => {
updateGroupPackageSettings('foo')(client, payload);
expect(client.writeQuery).toHaveBeenCalledWith({
...queryAndVariables,
data: {
group: {
...payload.data.updateNamespacePackageSettings,
},
},
});
});
});
});
import { updateGroupPackagesSettingsOptimisticResponse } from '~/packages_and_registries/settings/group/graphql/utils/optimistic_responses';
describe('Optimistic responses', () => {
describe('updateGroupPackagesSettingsOptimisticResponse', () => {
it('returns the correct structure', () => {
expect(updateGroupPackagesSettingsOptimisticResponse({ foo: 'bar' })).toMatchInlineSnapshot(`
Object {
"__typename": "Mutation",
"updateNamespacePackageSettings": Object {
"__typename": "UpdateNamespacePackageSettingsPayload",
"errors": Array [],
"packageSettings": Object {
"foo": "bar",
},
},
}
`);
});
});
});
......@@ -4,9 +4,45 @@ export const groupPackageSettingsMock = {
packageSettings: {
mavenDuplicatesAllowed: true,
mavenDuplicateExceptionRegex: '',
__typename: 'PackageSettings',
},
__typename: 'Group',
},
},
};
export const groupPackageSettingsMutationMock = (override) => ({
data: {
updateNamespacePackageSettings: {
packageSettings: {
mavenDuplicatesAllowed: true,
mavenDuplicateExceptionRegex: 'latest[master]something',
},
errors: [],
...override,
},
},
});
export const groupPackageSettingsMutationErrorMock = {
errors: [
{
message:
'Variable $input of type UpdateNamespacePackageSettingsInput! was provided invalid value for mavenDuplicateExceptionRegex (latest[master]somethingj)) is an invalid regexp: unexpected ): latest[master]somethingj)))',
locations: [{ line: 1, column: 41 }],
extensions: {
value: {
namespacePath: 'gitlab-org',
mavenDuplicateExceptionRegex: 'latest[master]something))',
},
problems: [
{
path: ['mavenDuplicateExceptionRegex'],
explanation:
'latest[master]somethingj)) is an invalid regexp: unexpected ): latest[master]something))',
message:
'latest[master]somethingj)) is an invalid regexp: unexpected ): latest[master]something))',
},
],
},
},
],
};
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