gitlab-org--gitlab-foss/spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js

297 lines
9.8 KiB
JavaScript

import Vue, { nextTick } from 'vue';
import { GlToggle } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import ExceptionsInput from '~/packages_and_registries/settings/group/components/exceptions_input.vue';
import component from '~/packages_and_registries/settings/group/components/packages_settings.vue';
import {
DUPLICATES_TOGGLE_LABEL,
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
} from '~/packages_and_registries/settings/group/constants';
import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql';
import getGroupPackagesSettingsQuery from '~/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql';
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
import { updateGroupPackagesSettingsOptimisticResponse } from '~/packages_and_registries/settings/group/graphql/utils/optimistic_responses';
import {
packageSettings,
groupPackageSettingsMock,
groupPackageSettingsMutationMock,
groupPackageSettingsMutationErrorMock,
} from '../mock_data';
jest.mock('~/flash');
jest.mock('~/packages_and_registries/settings/group/graphql/utils/optimistic_responses');
describe('Packages Settings', () => {
let wrapper;
let apolloProvider;
const defaultProvide = {
groupPath: 'foo_group_path',
};
const mountComponent = ({
mountFn = shallowMountExtended,
mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationMock()),
} = {}) => {
Vue.use(VueApollo);
const requestHandlers = [[updateNamespacePackageSettings, mutationResolver]];
apolloProvider = createMockApollo(requestHandlers);
wrapper = mountFn(component, {
apolloProvider,
provide: defaultProvide,
propsData: {
packageSettings: packageSettings(),
},
stubs: {
SettingsBlock,
},
});
};
afterEach(() => {
wrapper.destroy();
});
const findSettingsBlock = () => wrapper.findComponent(SettingsBlock);
const findDescription = () => wrapper.findByTestId('description');
const findMavenSettings = () => wrapper.findByTestId('maven-settings');
const findGenericSettings = () => wrapper.findByTestId('generic-settings');
const findMavenDuplicatedSettingsToggle = () => findMavenSettings().findComponent(GlToggle);
const findGenericDuplicatedSettingsToggle = () => findGenericSettings().findComponent(GlToggle);
const findMavenDuplicatedSettingsExceptionsInput = () =>
findMavenSettings().findComponent(ExceptionsInput);
const findGenericDuplicatedSettingsExceptionsInput = () =>
findGenericSettings().findComponent(ExceptionsInput);
const fillApolloCache = () => {
apolloProvider.defaultClient.cache.writeQuery({
query: getGroupPackagesSettingsQuery,
variables: {
fullPath: defaultProvide.groupPath,
},
...groupPackageSettingsMock,
});
};
const emitMavenSettingsUpdate = (override) => {
findGenericDuplicatedSettingsExceptionsInput().vm.$emit('update', {
mavenDuplicateExceptionRegex: ')',
...override,
});
};
it('renders a settings block', () => {
mountComponent();
expect(findSettingsBlock().exists()).toBe(true);
});
it('has the correct header text', () => {
mountComponent();
expect(wrapper.text()).toContain(PACKAGE_SETTINGS_HEADER);
});
it('has the correct description text', () => {
mountComponent();
expect(findDescription().text()).toMatchInterpolatedText(PACKAGE_SETTINGS_DESCRIPTION);
});
describe('maven settings', () => {
it('exists', () => {
mountComponent({ mountFn: mountExtended });
expect(findMavenSettings().find('td').text()).toBe('Maven');
});
it('renders toggle', () => {
mountComponent({ mountFn: mountExtended });
const { mavenDuplicatesAllowed } = packageSettings();
expect(findMavenDuplicatedSettingsToggle().exists()).toBe(true);
expect(findMavenDuplicatedSettingsToggle().props()).toMatchObject({
label: DUPLICATES_TOGGLE_LABEL,
value: mavenDuplicatesAllowed,
disabled: false,
labelPosition: 'hidden',
});
});
it('renders ExceptionsInput and assigns duplication allowness and exception props', () => {
mountComponent({ mountFn: mountExtended });
const { mavenDuplicatesAllowed, mavenDuplicateExceptionRegex } = packageSettings();
expect(findMavenDuplicatedSettingsExceptionsInput().exists()).toBe(true);
expect(findMavenDuplicatedSettingsExceptionsInput().props()).toMatchObject({
duplicatesAllowed: mavenDuplicatesAllowed,
duplicateExceptionRegex: mavenDuplicateExceptionRegex,
duplicateExceptionRegexError: '',
loading: false,
name: 'mavenDuplicateExceptionRegex',
id: 'maven-duplicated-settings-regex-input',
});
});
it('on update event calls the mutation', () => {
const mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationMock());
mountComponent({ mountFn: mountExtended, mutationResolver });
fillApolloCache();
emitMavenSettingsUpdate();
expect(mutationResolver).toHaveBeenCalledWith({
input: { mavenDuplicateExceptionRegex: ')', namespacePath: 'foo_group_path' },
});
});
});
describe('generic settings', () => {
it('exists', () => {
mountComponent({ mountFn: mountExtended });
expect(findGenericSettings().find('td').text()).toBe('Generic');
});
it('renders toggle', () => {
mountComponent({ mountFn: mountExtended });
const { genericDuplicatesAllowed } = packageSettings();
expect(findGenericDuplicatedSettingsToggle().exists()).toBe(true);
expect(findGenericDuplicatedSettingsToggle().props()).toMatchObject({
label: DUPLICATES_TOGGLE_LABEL,
value: genericDuplicatesAllowed,
disabled: false,
labelPosition: 'hidden',
});
});
it('renders ExceptionsInput and assigns duplication allowness and exception props', async () => {
mountComponent({ mountFn: mountExtended });
const { genericDuplicatesAllowed, genericDuplicateExceptionRegex } = packageSettings();
expect(findGenericDuplicatedSettingsExceptionsInput().props()).toMatchObject({
duplicatesAllowed: genericDuplicatesAllowed,
duplicateExceptionRegex: genericDuplicateExceptionRegex,
duplicateExceptionRegexError: '',
loading: false,
name: 'genericDuplicateExceptionRegex',
id: 'generic-duplicated-settings-regex-input',
});
});
it('on update event calls the mutation', async () => {
const mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationMock());
mountComponent({ mountFn: mountExtended, mutationResolver });
fillApolloCache();
findGenericDuplicatedSettingsExceptionsInput().vm.$emit('update', {
genericDuplicateExceptionRegex: ')',
});
expect(mutationResolver).toHaveBeenCalledWith({
input: { genericDuplicateExceptionRegex: ')', namespacePath: 'foo_group_path' },
});
});
});
describe('settings update', () => {
describe('success state', () => {
beforeEach(() => {
mountComponent({ mountFn: mountExtended });
});
it('emits a success event', async () => {
fillApolloCache();
emitMavenSettingsUpdate();
await waitForPromises();
expect(wrapper.emitted('success')).toEqual([[]]);
});
it('has an optimistic response', () => {
const mavenDuplicateExceptionRegex = 'latest[main]something';
fillApolloCache();
expect(
findGenericDuplicatedSettingsExceptionsInput().props('duplicateExceptionRegex'),
).toBe('');
emitMavenSettingsUpdate({ mavenDuplicateExceptionRegex });
expect(updateGroupPackagesSettingsOptimisticResponse).toHaveBeenCalledWith({
...packageSettings(),
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({ mountFn: mountExtended, mutationResolver });
fillApolloCache();
emitMavenSettingsUpdate();
await waitForPromises();
// errors are bound to the component
expect(
findMavenDuplicatedSettingsExceptionsInput().props('duplicateExceptionRegexError'),
).toBe(groupPackageSettingsMutationErrorMock.errors[0].extensions.problems[0].message);
// general error message is shown
expect(wrapper.emitted('error')).toEqual([[]]);
emitMavenSettingsUpdate();
await nextTick();
// errors are reset on mutation call
expect(
findMavenDuplicatedSettingsExceptionsInput().props('duplicateExceptionRegexError'),
).toBe('');
});
it.each`
type | mutationResolver
${'local'} | ${jest.fn().mockResolvedValue(groupPackageSettingsMutationMock({ errors: ['foo'] }))}
${'network'} | ${jest.fn().mockRejectedValue()}
`('mutation payload with $type error', async ({ mutationResolver }) => {
mountComponent({ mountFn: mountExtended, mutationResolver });
fillApolloCache();
emitMavenSettingsUpdate();
await waitForPromises();
expect(wrapper.emitted('error')).toEqual([[]]);
});
});
});
});