summaryrefslogtreecommitdiff
path: root/spec/frontend/packages_and_registries
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/packages_and_registries')
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js6
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js12
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js44
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js8
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/dependency_proxy/app_spec.js27
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/dependency_proxy_settings_spec.js25
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/duplicates_settings_spec.js21
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js1
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js21
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap3
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js7
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js9
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_form_spec.js267
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_spec.js81
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js30
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/mock_data.js30
-rw-r--r--spec/frontend/packages_and_registries/shared/components/settings_block_spec.js43
18 files changed, 548 insertions, 92 deletions
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js
index ca666e38291..9982286c625 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js
@@ -18,7 +18,6 @@ import {
CLEANUP_SCHEDULED_TOOLTIP,
CLEANUP_ONGOING_TOOLTIP,
CLEANUP_UNFINISHED_TOOLTIP,
- ROOT_IMAGE_TEXT,
ROOT_IMAGE_TOOLTIP,
} from '~/packages_and_registries/container_registry/explorer/constants';
import getContainerRepositoryMetadata from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_metadata.query.graphql';
@@ -35,6 +34,7 @@ describe('Details Header', () => {
canDelete: true,
project: {
visibility: 'public',
+ path: 'path',
containerExpirationPolicy: {
enabled: false,
},
@@ -98,8 +98,8 @@ describe('Details Header', () => {
return waitForPromises();
});
- it('root image ', () => {
- expect(findTitle().text()).toBe(ROOT_IMAGE_TEXT);
+ it('root image shows project path name', () => {
+ expect(findTitle().text()).toBe('path');
});
it('has an icon', () => {
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
index 0581a40b6a2..a5b2b1d7cf8 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
@@ -109,5 +109,17 @@ describe('cleanup_status', () => {
expect(findPopover().findComponent(GlLink).exists()).toBe(true);
expect(findPopover().findComponent(GlLink).attributes('href')).toBe(cleanupPolicyHelpPage);
});
+
+ it('id matches popover target attribute', () => {
+ mountComponent({
+ status: UNFINISHED_STATUS,
+ next_run_at: '2063-04-08T01:44:03Z',
+ });
+
+ const id = findExtraInfoIcon().attributes('id');
+
+ expect(id).toMatch(/status-info-[0-9]+/);
+ expect(findPopover().props('target')).toEqual(id);
+ });
});
});
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js
index 979e1500d7d..d12933526bc 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js
@@ -1,6 +1,7 @@
-import { GlIcon, GlSprintf, GlSkeletonLoader } from '@gitlab/ui';
+import { GlIcon, GlSprintf, GlSkeletonLoader, GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { mockTracking } from 'helpers/tracking_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import DeleteButton from '~/packages_and_registries/container_registry/explorer/components/delete_button.vue';
import CleanupStatus from '~/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue';
@@ -12,7 +13,6 @@ import {
IMAGE_DELETE_SCHEDULED_STATUS,
IMAGE_MIGRATING_STATE,
SCHEDULED_STATUS,
- ROOT_IMAGE_TEXT,
COPY_IMAGE_PATH_TITLE,
} from '~/packages_and_registries/container_registry/explorer/constants';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
@@ -31,13 +31,15 @@ describe('Image List Row', () => {
const findCleanupStatus = () => wrapper.findComponent(CleanupStatus);
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
const findListItemComponent = () => wrapper.findComponent(ListItem);
+ const findShowFullPathButton = () => wrapper.findComponent(GlButton);
- const mountComponent = (props) => {
+ const mountComponent = (props, features = {}) => {
wrapper = shallowMount(Component, {
stubs: {
RouterLink,
GlSprintf,
ListItem,
+ GlButton,
},
propsData: {
item,
@@ -45,6 +47,9 @@ describe('Image List Row', () => {
},
provide: {
config: {},
+ glFeatures: {
+ ...features,
+ },
},
directives: {
GlTooltip: createMockDirective(),
@@ -96,10 +101,10 @@ describe('Image List Row', () => {
});
});
- it(`when the image has no name appends ${ROOT_IMAGE_TEXT} to the path`, () => {
+ it('when the image has no name lists the path', () => {
mountComponent({ item: { ...item, name: '' } });
- expect(findDetailsLink().text()).toBe(`${item.path}/ ${ROOT_IMAGE_TEXT}`);
+ expect(findDetailsLink().text()).toBe(item.path);
});
it('contains a clipboard button', () => {
@@ -144,6 +149,35 @@ describe('Image List Row', () => {
expect(findClipboardButton().attributes('disabled')).toBe('true');
});
});
+
+ describe('when containerRegistryShowShortenedPath feature enabled', () => {
+ let trackingSpy;
+
+ beforeEach(() => {
+ mountComponent({}, { containerRegistryShowShortenedPath: true });
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ it('renders shortened name of image', () => {
+ expect(findShowFullPathButton().exists()).toBe(true);
+ expect(findDetailsLink().text()).toBe('gitlab-test/rails-12009');
+ });
+
+ it('clicking on shortened name of image hides the button & shows full path', async () => {
+ const btn = findShowFullPathButton();
+ const mockFocusFn = jest.fn();
+ wrapper.vm.$refs.imageName.$el.focus = mockFocusFn;
+
+ await btn.trigger('click');
+
+ expect(findShowFullPathButton().exists()).toBe(false);
+ expect(findDetailsLink().text()).toBe(item.path);
+ expect(mockFocusFn).toHaveBeenCalled();
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_show_full_path', {
+ label: 'registry_image_list',
+ });
+ });
+ });
});
describe('delete button', () => {
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js
index 7e6f88fe5bc..f9739509ef9 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js
@@ -11,6 +11,10 @@ export const imagesListResponse = [
createdAt: '2020-11-03T13:29:21Z',
expirationPolicyStartedAt: null,
expirationPolicyCleanupStatus: 'UNSCHEDULED',
+ project: {
+ id: 'gid://gitlab/Project/22',
+ path: 'gitlab-test',
+ },
},
{
__typename: 'ContainerRepository',
@@ -24,6 +28,10 @@ export const imagesListResponse = [
createdAt: '2020-09-21T06:57:43Z',
expirationPolicyStartedAt: null,
expirationPolicyCleanupStatus: 'UNSCHEDULED',
+ project: {
+ id: 'gid://gitlab/Project/22',
+ path: 'gitlab-test',
+ },
},
];
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js
index 59ca47bee50..1d161888a4d 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js
@@ -20,7 +20,6 @@ import {
ALERT_DANGER_IMAGE,
ALERT_DANGER_IMPORTING,
MISSING_OR_DELETED_IMAGE_BREADCRUMB,
- ROOT_IMAGE_TEXT,
MISSING_OR_DELETED_IMAGE_TITLE,
MISSING_OR_DELETED_IMAGE_MESSAGE,
} from '~/packages_and_registries/container_registry/explorer/constants';
@@ -482,7 +481,7 @@ describe('Details Page', () => {
expect(breadCrumbState.updateName).toHaveBeenCalledWith(MISSING_OR_DELETED_IMAGE_BREADCRUMB);
});
- it(`when the image has no name set the breadcrumb to ${ROOT_IMAGE_TEXT}`, async () => {
+ it(`when the image has no name set the breadcrumb to project name`, async () => {
mountComponent({
resolver: jest
.fn()
@@ -491,7 +490,7 @@ describe('Details Page', () => {
await waitForApolloRequestRender();
- expect(breadCrumbState.updateName).toHaveBeenCalledWith(ROOT_IMAGE_TEXT);
+ expect(breadCrumbState.updateName).toHaveBeenCalledWith('gitlab-test');
});
});
diff --git a/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js b/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
index fe4a2c06f1c..f2901148e17 100644
--- a/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
+++ b/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
@@ -38,6 +38,8 @@ const dummyGon = {
let originalGon;
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${dummyGrouptId}/dependency_proxy/cache`;
+Vue.use(VueApollo);
+
describe('DependencyProxyApp', () => {
let wrapper;
let apolloProvider;
@@ -51,8 +53,6 @@ describe('DependencyProxyApp', () => {
};
function createComponent({ provide = provideDefaults } = {}) {
- Vue.use(VueApollo);
-
const requestHandlers = [[getDependencyProxyDetailsQuery, resolver]];
apolloProvider = createMockApollo(requestHandlers);
@@ -103,19 +103,21 @@ describe('DependencyProxyApp', () => {
describe('when the dependency proxy is available', () => {
describe('when is loading', () => {
- beforeEach(() => {
+ it('renders the skeleton loader', () => {
createComponent();
- });
- it('renders the skeleton loader', () => {
expect(findSkeletonLoader().exists()).toBe(true);
});
it('does not render a form group with label', () => {
+ createComponent();
+
expect(findFormGroup().exists()).toBe(false);
});
it('does not show the main section', () => {
+ createComponent();
+
expect(findMainArea().exists()).toBe(false);
});
});
@@ -215,23 +217,26 @@ describe('DependencyProxyApp', () => {
});
describe('triggering page event on list', () => {
- beforeEach(async () => {
+ it('re-renders the skeleton loader', async () => {
findManifestList().vm.$emit('next-page');
-
await nextTick();
- });
- it('re-renders the skeleton loader', () => {
expect(findSkeletonLoader().exists()).toBe(true);
});
- it('renders form group with label', () => {
+ it('renders form group with label', async () => {
+ findManifestList().vm.$emit('next-page');
+ await nextTick();
+
expect(findFormGroup().attributes('label')).toEqual(
expect.stringMatching(DependencyProxyApp.i18n.proxyImagePrefix),
);
});
- it('does not show the main section', () => {
+ it('does not show the main section', async () => {
+ findManifestList().vm.$emit('next-page');
+ await nextTick();
+
expect(findMainArea().exists()).toBe(false);
});
});
diff --git a/spec/frontend/packages_and_registries/settings/group/components/dependency_proxy_settings_spec.js b/spec/frontend/packages_and_registries/settings/group/components/dependency_proxy_settings_spec.js
index e60989b0949..9d4c7f4737b 100644
--- a/spec/frontend/packages_and_registries/settings/group/components/dependency_proxy_settings_spec.js
+++ b/spec/frontend/packages_and_registries/settings/group/components/dependency_proxy_settings_spec.js
@@ -6,13 +6,15 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import component from '~/packages_and_registries/settings/group/components/dependency_proxy_settings.vue';
-import { DEPENDENCY_PROXY_HEADER } from '~/packages_and_registries/settings/group/constants';
+import {
+ DEPENDENCY_PROXY_HEADER,
+ DEPENDENCY_PROXY_DESCRIPTION,
+} from '~/packages_and_registries/settings/group/constants';
import updateDependencyProxySettings from '~/packages_and_registries/settings/group/graphql/mutations/update_dependency_proxy_settings.mutation.graphql';
import updateDependencyProxyImageTtlGroupPolicy from '~/packages_and_registries/settings/group/graphql/mutations/update_dependency_proxy_image_ttl_group_policy.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 SettingsTitles from '~/packages_and_registries/settings/group/components/settings_titles.vue';
import {
updateGroupDependencyProxySettingsOptimisticResponse,
updateDependencyProxyImageTtlGroupPolicyOptimisticResponse,
@@ -36,7 +38,6 @@ describe('DependencyProxySettings', () => {
let updateTtlPoliciesMutationResolver;
const defaultProvide = {
- defaultExpanded: false,
groupPath: 'foo_group_path',
groupDependencyProxyPath: 'group_dependency_proxy_path',
};
@@ -86,7 +87,6 @@ describe('DependencyProxySettings', () => {
});
const findSettingsBlock = () => wrapper.findComponent(SettingsBlock);
- const findSettingsTitles = () => wrapper.findComponent(SettingsTitles);
const findEnableProxyToggle = () => wrapper.findByTestId('dependency-proxy-setting-toggle');
const findEnableTtlPoliciesToggle = () =>
wrapper.findByTestId('dependency-proxy-ttl-policies-toggle');
@@ -108,16 +108,11 @@ describe('DependencyProxySettings', () => {
expect(findSettingsBlock().exists()).toBe(true);
});
- it('passes the correct props to settings block', () => {
- mountComponent();
-
- expect(findSettingsBlock().props('defaultExpanded')).toBe(false);
- });
-
- it('has the correct header text', () => {
+ it('has the correct header text and description', () => {
mountComponent();
expect(wrapper.text()).toContain(DEPENDENCY_PROXY_HEADER);
+ expect(wrapper.text()).toContain(DEPENDENCY_PROXY_DESCRIPTION);
});
describe('enable toggle', () => {
@@ -158,14 +153,6 @@ describe('DependencyProxySettings', () => {
});
describe('storage settings', () => {
- it('the component has the settings title', () => {
- mountComponent();
-
- expect(findSettingsTitles().props()).toMatchObject({
- title: component.i18n.storageSettingsTitle,
- });
- });
-
describe('enable proxy ttl policies', () => {
it('exists', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/settings/group/components/duplicates_settings_spec.js b/spec/frontend/packages_and_registries/settings/group/components/duplicates_settings_spec.js
index 79c2f811c08..3eecdeb5b1f 100644
--- a/spec/frontend/packages_and_registries/settings/group/components/duplicates_settings_spec.js
+++ b/spec/frontend/packages_and_registries/settings/group/components/duplicates_settings_spec.js
@@ -4,8 +4,6 @@ import component from '~/packages_and_registries/settings/group/components/dupli
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';
@@ -36,7 +34,6 @@ describe('Duplicates Settings', () => {
});
const findToggle = () => wrapper.findComponent(GlToggle);
- const findToggleLabel = () => wrapper.find('[data-testid="toggle-label"');
const findInputGroup = () => wrapper.findComponent(GlFormGroup);
const findInput = () => wrapper.findComponent(GlFormInput);
@@ -47,7 +44,7 @@ describe('Duplicates Settings', () => {
expect(findToggle().exists()).toBe(true);
expect(findToggle().props()).toMatchObject({
label: DUPLICATES_TOGGLE_LABEL,
- value: defaultProps.duplicatesAllowed,
+ value: !defaultProps.duplicatesAllowed,
});
});
@@ -57,18 +54,11 @@ describe('Duplicates Settings', () => {
findToggle().vm.$emit('change', false);
expect(wrapper.emitted('update')).toStrictEqual([
- [{ [defaultProps.modelNames.allowed]: false }],
+ [{ [defaultProps.modelNames.allowed]: true }],
]);
});
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();
@@ -130,13 +120,6 @@ describe('Duplicates Settings', () => {
});
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 });
diff --git a/spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js b/spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js
index 635195ff0a4..31fc3ad419c 100644
--- a/spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js
+++ b/spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js
@@ -26,7 +26,6 @@ describe('Group Settings App', () => {
let show;
const defaultProvide = {
- defaultExpanded: false,
groupPath: 'foo_group_path',
};
diff --git a/spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js b/spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js
index d92d42e7834..274930ce668 100644
--- a/spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js
+++ b/spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js
@@ -1,4 +1,3 @@
-import { GlSprintf, GlLink } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
@@ -11,7 +10,6 @@ import MavenSettings from '~/packages_and_registries/settings/group/components/m
import {
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
- PACKAGES_DOCS_PATH,
} from '~/packages_and_registries/settings/group/constants';
import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql';
@@ -33,7 +31,6 @@ describe('Packages Settings', () => {
let apolloProvider;
const defaultProvide = {
- defaultExpanded: false,
groupPath: 'foo_group_path',
};
@@ -53,7 +50,6 @@ describe('Packages Settings', () => {
packageSettings: packageSettings(),
},
stubs: {
- GlSprintf,
SettingsBlock,
MavenSettings,
GenericSettings,
@@ -67,7 +63,6 @@ describe('Packages Settings', () => {
const findSettingsBlock = () => wrapper.findComponent(SettingsBlock);
const findDescription = () => wrapper.findByTestId('description');
- const findLink = () => wrapper.findComponent(GlLink);
const findMavenSettings = () => wrapper.findComponent(MavenSettings);
const findMavenDuplicatedSettings = () => findMavenSettings().findComponent(DuplicatesSettings);
const findGenericSettings = () => wrapper.findComponent(GenericSettings);
@@ -97,12 +92,6 @@ describe('Packages Settings', () => {
expect(findSettingsBlock().exists()).toBe(true);
});
- it('passes the correct props to settings block', () => {
- mountComponent();
-
- expect(findSettingsBlock().props('defaultExpanded')).toBe(false);
- });
-
it('has the correct header text', () => {
mountComponent();
@@ -115,16 +104,6 @@ describe('Packages Settings', () => {
expect(findDescription().text()).toMatchInterpolatedText(PACKAGE_SETTINGS_DESCRIPTION);
});
- it('has the correct link', () => {
- mountComponent();
-
- expect(findLink().attributes()).toMatchObject({
- href: PACKAGES_DOCS_PATH,
- target: '_blank',
- });
- expect(findLink().text()).toBe('Learn more.');
- });
-
describe('maven settings', () => {
it('exists', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap b/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap
index faa313118f3..108d9478788 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap
@@ -4,6 +4,7 @@ exports[`Container Expiration Policy Settings Form Cadence matches snapshot 1`]
<expiration-dropdown-stub
class="gl-mr-7 gl-mb-0!"
data-testid="cadence-dropdown"
+ description=""
formoptions="[object Object],[object Object],[object Object],[object Object],[object Object]"
label="Run cleanup:"
name="cadence"
@@ -22,6 +23,7 @@ exports[`Container Expiration Policy Settings Form Enable matches snapshot 1`] =
exports[`Container Expiration Policy Settings Form Keep N matches snapshot 1`] = `
<expiration-dropdown-stub
data-testid="keep-n-dropdown"
+ description=""
formoptions="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]"
label="Keep the most recent:"
name="keep-n"
@@ -44,6 +46,7 @@ exports[`Container Expiration Policy Settings Form Keep Regex matches snapshot 1
exports[`Container Expiration Policy Settings Form OlderThan matches snapshot 1`] = `
<expiration-dropdown-stub
data-testid="older-than-dropdown"
+ description=""
formoptions="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]"
label="Remove tags older than:"
name="older-than"
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js
index aa3506771fa..d83c717da6a 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js
@@ -43,11 +43,6 @@ describe('Container expiration policy project settings', () => {
GlSprintf,
SettingsBlock,
},
- mocks: {
- $toast: {
- show: jest.fn(),
- },
- },
provide,
...config,
});
@@ -98,7 +93,7 @@ describe('Container expiration policy project settings', () => {
await waitForPromises();
expect(findFormComponent().exists()).toBe(true);
- expect(findSettingsBlock().props('collapsible')).toBe(false);
+ expect(findSettingsBlock().exists()).toBe(true);
});
describe('the form is disabled', () => {
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js
index 5c9ade7f785..8b99ac6b06c 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js
@@ -16,6 +16,7 @@ describe('ExpirationDropdown', () => {
const findFormSelect = () => wrapper.find(GlFormSelect);
const findFormGroup = () => wrapper.find(GlFormGroup);
+ const findDescription = () => wrapper.find('[data-testid="description"]');
const findOptions = () => wrapper.findAll('[data-testid="option"]');
const mountComponent = (props) => {
@@ -47,6 +48,14 @@ describe('ExpirationDropdown', () => {
expect(findOptions()).toHaveLength(defaultProps.formOptions.length);
});
+
+ it('renders the description if passed', () => {
+ mountComponent({
+ description: 'test description',
+ });
+
+ expect(findDescription().html()).toContain('test description');
+ });
});
describe('model', () => {
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_form_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_form_spec.js
new file mode 100644
index 00000000000..86f45d78bae
--- /dev/null
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_form_spec.js
@@ -0,0 +1,267 @@
+import VueApollo from 'vue-apollo';
+import Vue from 'vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { GlLoadingIcon } from 'jest/packages_and_registries/shared/stubs';
+import component from '~/packages_and_registries/settings/project/components/packages_cleanup_policy_form.vue';
+import {
+ UPDATE_SETTINGS_ERROR_MESSAGE,
+ UPDATE_SETTINGS_SUCCESS_MESSAGE,
+ KEEP_N_DUPLICATED_PACKAGE_FILES_LABEL,
+ KEEP_N_DUPLICATED_PACKAGE_FILES_DESCRIPTION,
+} from '~/packages_and_registries/settings/project/constants';
+import updatePackagesCleanupPolicyMutation from '~/packages_and_registries/settings/project/graphql/mutations/update_packages_cleanup_policy.mutation.graphql';
+import Tracking from '~/tracking';
+import { packagesCleanupPolicyPayload, packagesCleanupPolicyMutationPayload } from '../mock_data';
+
+Vue.use(VueApollo);
+
+describe('Packages Cleanup Policy Settings Form', () => {
+ let wrapper;
+ let fakeApollo;
+
+ const defaultProvidedValues = {
+ projectPath: 'path',
+ };
+
+ const {
+ data: {
+ project: { packagesCleanupPolicy },
+ },
+ } = packagesCleanupPolicyPayload();
+
+ const defaultProps = {
+ value: { ...packagesCleanupPolicy },
+ };
+
+ const trackingPayload = {
+ label: 'packages_cleanup_policies',
+ };
+
+ const findForm = () => wrapper.find({ ref: 'form-element' });
+ const findSaveButton = () => wrapper.findByTestId('save-button');
+ const findKeepNDuplicatedPackageFilesDropdown = () =>
+ wrapper.findByTestId('keep-n-duplicated-package-files-dropdown');
+
+ const submitForm = async () => {
+ findForm().trigger('submit');
+ return waitForPromises();
+ };
+
+ const mountComponent = ({
+ props = defaultProps,
+ data,
+ config,
+ provide = defaultProvidedValues,
+ } = {}) => {
+ wrapper = shallowMountExtended(component, {
+ stubs: {
+ GlLoadingIcon,
+ },
+ propsData: { ...props },
+ provide,
+ data() {
+ return {
+ ...data,
+ };
+ },
+ mocks: {
+ $toast: {
+ show: jest.fn(),
+ },
+ },
+ ...config,
+ });
+ };
+
+ const mountComponentWithApollo = ({
+ provide = defaultProvidedValues,
+ mutationResolver,
+ queryPayload = packagesCleanupPolicyPayload(),
+ } = {}) => {
+ const requestHandlers = [[updatePackagesCleanupPolicyMutation, mutationResolver]];
+
+ fakeApollo = createMockApollo(requestHandlers);
+
+ const {
+ data: {
+ project: { packagesCleanupPolicy: value },
+ },
+ } = queryPayload;
+
+ mountComponent({
+ provide,
+ props: {
+ ...defaultProps,
+ value,
+ },
+ config: {
+ apolloProvider: fakeApollo,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event');
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ fakeApollo = null;
+ });
+
+ describe('keepNDuplicatedPackageFiles', () => {
+ it('renders dropdown', () => {
+ mountComponent();
+
+ const element = findKeepNDuplicatedPackageFilesDropdown();
+
+ expect(element.exists()).toBe(true);
+ expect(element.props('label')).toMatchInterpolatedText(KEEP_N_DUPLICATED_PACKAGE_FILES_LABEL);
+ expect(element.props('description')).toEqual(KEEP_N_DUPLICATED_PACKAGE_FILES_DESCRIPTION);
+ });
+
+ it('input event triggers a model update', () => {
+ mountComponent();
+
+ findKeepNDuplicatedPackageFilesDropdown().vm.$emit('input', 'foo');
+ expect(wrapper.emitted('input')[0][0]).toMatchObject({
+ keepNDuplicatedPackageFiles: 'foo',
+ });
+ });
+
+ it('shows the default option when none are selected', () => {
+ mountComponent({ props: { value: {} } });
+ expect(findKeepNDuplicatedPackageFilesDropdown().props('value')).toEqual('ALL_PACKAGE_FILES');
+ });
+
+ it.each`
+ isLoading | mutationLoading
+ ${true} | ${false}
+ ${true} | ${true}
+ ${false} | ${true}
+ `(
+ 'is disabled when is loading is $isLoading and mutationLoading is $mutationLoading',
+ ({ isLoading, mutationLoading }) => {
+ mountComponent({
+ props: { isLoading, value: {} },
+ data: { mutationLoading },
+ });
+ expect(findKeepNDuplicatedPackageFilesDropdown().props('disabled')).toEqual(true);
+ },
+ );
+
+ it('has the correct formOptions', () => {
+ mountComponent();
+ expect(findKeepNDuplicatedPackageFilesDropdown().props('formOptions')).toEqual(
+ wrapper.vm.$options.formOptions.keepNDuplicatedPackageFiles,
+ );
+ });
+ });
+
+ describe('form', () => {
+ describe('actions', () => {
+ describe('submit button', () => {
+ it('has type submit', () => {
+ mountComponent();
+
+ expect(findSaveButton().attributes('type')).toBe('submit');
+ });
+
+ it.each`
+ isLoading | mutationLoading | disabled
+ ${true} | ${true} | ${true}
+ ${true} | ${false} | ${true}
+ ${false} | ${true} | ${true}
+ ${false} | ${false} | ${false}
+ `(
+ 'when isLoading is $isLoading and mutationLoading is $mutationLoading is disabled',
+ ({ isLoading, mutationLoading, disabled }) => {
+ mountComponent({
+ props: { ...defaultProps, isLoading },
+ data: { mutationLoading },
+ });
+
+ expect(findSaveButton().props('disabled')).toBe(disabled);
+ expect(findKeepNDuplicatedPackageFilesDropdown().props('disabled')).toBe(disabled);
+ },
+ );
+
+ it.each`
+ isLoading | mutationLoading | showLoading
+ ${true} | ${true} | ${true}
+ ${true} | ${false} | ${true}
+ ${false} | ${true} | ${true}
+ ${false} | ${false} | ${false}
+ `(
+ 'when isLoading is $isLoading and mutationLoading is $mutationLoading is $showLoading that the loading icon is shown',
+ ({ isLoading, mutationLoading, showLoading }) => {
+ mountComponent({
+ props: { ...defaultProps, isLoading },
+ data: { mutationLoading },
+ });
+
+ expect(findSaveButton().props('loading')).toBe(showLoading);
+ },
+ );
+ });
+ });
+
+ describe('form submit event', () => {
+ it('dispatches the correct apollo mutation', () => {
+ const mutationResolver = jest
+ .fn()
+ .mockResolvedValue(packagesCleanupPolicyMutationPayload());
+ mountComponentWithApollo({
+ mutationResolver,
+ });
+
+ findForm().trigger('submit');
+
+ expect(mutationResolver).toHaveBeenCalledWith({
+ input: {
+ keepNDuplicatedPackageFiles: 'ALL_PACKAGE_FILES',
+ projectPath: 'path',
+ },
+ });
+ });
+
+ it('tracks the submit event', () => {
+ mountComponentWithApollo({
+ mutationResolver: jest.fn().mockResolvedValue(packagesCleanupPolicyMutationPayload()),
+ });
+
+ findForm().trigger('submit');
+
+ expect(Tracking.event).toHaveBeenCalledWith(
+ undefined,
+ 'submit_packages_cleanup_form',
+ trackingPayload,
+ );
+ });
+
+ it('show a success toast when submit succeed', async () => {
+ mountComponentWithApollo({
+ mutationResolver: jest.fn().mockResolvedValue(packagesCleanupPolicyMutationPayload()),
+ });
+
+ await submitForm();
+
+ expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_SUCCESS_MESSAGE);
+ });
+
+ describe('when submit fails', () => {
+ it('shows an error', async () => {
+ mountComponentWithApollo({
+ mutationResolver: jest.fn().mockRejectedValue(packagesCleanupPolicyMutationPayload()),
+ });
+
+ await submitForm();
+
+ expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_ERROR_MESSAGE);
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_spec.js
new file mode 100644
index 00000000000..6dfeeca6862
--- /dev/null
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_spec.js
@@ -0,0 +1,81 @@
+import { GlAlert, GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import component from '~/packages_and_registries/settings/project/components/packages_cleanup_policy.vue';
+import PackagesCleanupPolicyForm from '~/packages_and_registries/settings/project/components/packages_cleanup_policy_form.vue';
+import { FETCH_SETTINGS_ERROR_MESSAGE } from '~/packages_and_registries/settings/project/constants';
+import packagesCleanupPolicyQuery from '~/packages_and_registries/settings/project/graphql/queries/get_packages_cleanup_policy.query.graphql';
+import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
+
+import { packagesCleanupPolicyPayload, packagesCleanupPolicyData } from '../mock_data';
+
+Vue.use(VueApollo);
+
+describe('Packages cleanup policy project settings', () => {
+ let wrapper;
+ let fakeApollo;
+
+ const defaultProvidedValues = {
+ projectPath: 'path',
+ };
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findFormComponent = () => wrapper.findComponent(PackagesCleanupPolicyForm);
+ const findSettingsBlock = () => wrapper.findComponent(SettingsBlock);
+
+ const mountComponent = (provide = defaultProvidedValues, config) => {
+ wrapper = shallowMount(component, {
+ stubs: {
+ GlSprintf,
+ SettingsBlock,
+ },
+ provide,
+ ...config,
+ });
+ };
+
+ const mountComponentWithApollo = ({ provide = defaultProvidedValues, resolver } = {}) => {
+ const requestHandlers = [[packagesCleanupPolicyQuery, resolver]];
+
+ fakeApollo = createMockApollo(requestHandlers);
+ mountComponent(provide, {
+ apolloProvider: fakeApollo,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ fakeApollo = null;
+ });
+
+ it('renders the setting form', async () => {
+ mountComponentWithApollo({
+ resolver: jest.fn().mockResolvedValue(packagesCleanupPolicyPayload()),
+ });
+ await waitForPromises();
+
+ expect(findFormComponent().exists()).toBe(true);
+ expect(findFormComponent().props('value')).toEqual(packagesCleanupPolicyData);
+ expect(findSettingsBlock().exists()).toBe(true);
+ });
+
+ describe('fetchSettingsError', () => {
+ beforeEach(async () => {
+ mountComponentWithApollo({
+ resolver: jest.fn().mockRejectedValue(new Error('GraphQL error')),
+ });
+ await waitForPromises();
+ });
+
+ it('the form is hidden', () => {
+ expect(findFormComponent().exists()).toBe(false);
+ });
+
+ it('shows an alert', () => {
+ expect(findAlert().html()).toContain(FETCH_SETTINGS_ERROR_MESSAGE);
+ });
+ });
+});
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js
index 337991dfae0..f576bc79eae 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js
@@ -1,19 +1,41 @@
import { shallowMount } from '@vue/test-utils';
import component from '~/packages_and_registries/settings/project/components/registry_settings_app.vue';
import ContainerExpirationPolicy from '~/packages_and_registries/settings/project/components/container_expiration_policy.vue';
+import PackagesCleanupPolicy from '~/packages_and_registries/settings/project/components/packages_cleanup_policy.vue';
describe('Registry Settings app', () => {
let wrapper;
+
const findContainerExpirationPolicy = () => wrapper.find(ContainerExpirationPolicy);
+ const findPackagesCleanupPolicy = () => wrapper.find(PackagesCleanupPolicy);
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
- it('renders container expiration policy component', () => {
- wrapper = shallowMount(component);
+ const mountComponent = (provide) => {
+ wrapper = shallowMount(component, {
+ provide,
+ });
+ };
- expect(findContainerExpirationPolicy().exists()).toBe(true);
- });
+ it.each`
+ showContainerRegistrySettings | showPackageRegistrySettings
+ ${true} | ${false}
+ ${true} | ${true}
+ ${false} | ${true}
+ ${false} | ${false}
+ `(
+ 'container expiration policy $showContainerRegistrySettings and package cleanup policy is $showPackageRegistrySettings',
+ ({ showContainerRegistrySettings, showPackageRegistrySettings }) => {
+ mountComponent({
+ showContainerRegistrySettings,
+ showPackageRegistrySettings,
+ });
+
+ expect(findContainerExpirationPolicy().exists()).toBe(showContainerRegistrySettings);
+ expect(findPackagesCleanupPolicy().exists()).toBe(showPackageRegistrySettings);
+ },
+ );
});
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js b/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js
index 33406c98f4b..d4b6c66ddeb 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js
@@ -40,3 +40,33 @@ export const expirationPolicyMutationPayload = ({ override, errors = [] } = {})
},
},
});
+
+export const packagesCleanupPolicyData = {
+ keepNDuplicatedPackageFiles: 'ALL_PACKAGE_FILES',
+ nextRunAt: '2020-11-19T07:37:03.941Z',
+};
+
+export const packagesCleanupPolicyPayload = (override) => ({
+ data: {
+ project: {
+ id: '1',
+ packagesCleanupPolicy: {
+ __typename: 'PackagesCleanupPolicy',
+ ...packagesCleanupPolicyData,
+ ...override,
+ },
+ },
+ },
+});
+
+export const packagesCleanupPolicyMutationPayload = ({ override, errors = [] } = {}) => ({
+ data: {
+ updatePackagesCleanupPolicy: {
+ packagesCleanupPolicy: {
+ ...packagesCleanupPolicyData,
+ ...override,
+ },
+ errors,
+ },
+ },
+});
diff --git a/spec/frontend/packages_and_registries/shared/components/settings_block_spec.js b/spec/frontend/packages_and_registries/shared/components/settings_block_spec.js
new file mode 100644
index 00000000000..a4c1b989dac
--- /dev/null
+++ b/spec/frontend/packages_and_registries/shared/components/settings_block_spec.js
@@ -0,0 +1,43 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue';
+
+describe('SettingsBlock', () => {
+ let wrapper;
+
+ const mountComponent = (propsData) => {
+ wrapper = shallowMountExtended(SettingsBlock, {
+ propsData,
+ slots: {
+ title: '<div data-testid="title-slot"></div>',
+ description: '<div data-testid="description-slot"></div>',
+ default: '<div data-testid="default-slot"></div>',
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findDefaultSlot = () => wrapper.findByTestId('default-slot');
+ const findTitleSlot = () => wrapper.findByTestId('title-slot');
+ const findDescriptionSlot = () => wrapper.findByTestId('description-slot');
+
+ it('has a default slot', () => {
+ mountComponent();
+
+ expect(findDefaultSlot().exists()).toBe(true);
+ });
+
+ it('has a title slot', () => {
+ mountComponent();
+
+ expect(findTitleSlot().exists()).toBe(true);
+ });
+
+ it('has a description slot', () => {
+ mountComponent();
+
+ expect(findDescriptionSlot().exists()).toBe(true);
+ });
+});