summaryrefslogtreecommitdiff
path: root/spec/frontend/packages_and_registries
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-04-20 10:00:54 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-04-20 10:00:54 +0000
commit3cccd102ba543e02725d247893729e5c73b38295 (patch)
treef36a04ec38517f5deaaacb5acc7d949688d1e187 /spec/frontend/packages_and_registries
parent205943281328046ef7b4528031b90fbda70c75ac (diff)
downloadgitlab-ce-3cccd102ba543e02725d247893729e5c73b38295.tar.gz
Add latest changes from gitlab-org/gitlab@14-10-stable-eev14.10.0-rc42
Diffstat (limited to 'spec/frontend/packages_and_registries')
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js67
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js10
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js10
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js2
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js31
-rw-r--r--spec/frontend/packages_and_registries/dependency_proxy/app_spec.js70
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_header_spec.js88
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_row_spec.js99
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js39
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/mock_data.js175
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/pages/index_spec.js24
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/pages/list_spec.js140
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js108
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap2
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js129
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js1
-rw-r--r--spec/frontend/packages_and_registries/package_registry/pages/__snapshots__/list_spec.js.snap2
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js24
-rw-r--r--spec/frontend/packages_and_registries/shared/components/__snapshots__/cleanup_policy_enabled_alert_spec.js.snap19
-rw-r--r--spec/frontend/packages_and_registries/shared/components/__snapshots__/registry_breadcrumb_spec.js.snap10
-rw-r--r--spec/frontend/packages_and_registries/shared/components/cleanup_policy_enabled_alert_spec.js49
-rw-r--r--spec/frontend/packages_and_registries/shared/components/registry_breadcrumb_spec.js8
22 files changed, 800 insertions, 307 deletions
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js
index 6d7bf528495..ad67128502a 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js
@@ -1,7 +1,7 @@
-import { GlButton } from '@gitlab/ui';
+import { GlButton, GlTooltip, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import component from '~/packages_and_registries/container_registry/explorer/components/delete_button.vue';
+import { LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION } from '~/packages_and_registries/container_registry/explorer/constants/list';
describe('delete_button', () => {
let wrapper;
@@ -12,6 +12,7 @@ describe('delete_button', () => {
};
const findButton = () => wrapper.find(GlButton);
+ const findTooltip = () => wrapper.find(GlTooltip);
const mountComponent = (props) => {
wrapper = shallowMount(component, {
@@ -19,8 +20,9 @@ describe('delete_button', () => {
...defaultProps,
...props,
},
- directives: {
- GlTooltip: createMockDirective(),
+ stubs: {
+ GlTooltip,
+ GlSprintf,
},
});
};
@@ -33,41 +35,50 @@ describe('delete_button', () => {
describe('tooltip', () => {
it('the title is controlled by tooltipTitle prop', () => {
mountComponent();
- const tooltip = getBinding(wrapper.element, 'gl-tooltip');
+ const tooltip = findTooltip();
expect(tooltip).toBeDefined();
- expect(tooltip.value.title).toBe(defaultProps.tooltipTitle);
+ expect(tooltip.text()).toBe(defaultProps.tooltipTitle);
});
it('is disabled when tooltipTitle is disabled', () => {
mountComponent({ tooltipDisabled: true });
- const tooltip = getBinding(wrapper.element, 'gl-tooltip');
- expect(tooltip.value.disabled).toBe(true);
+ expect(findTooltip().props('disabled')).toBe(true);
});
- describe('button', () => {
- it('exists', () => {
- mountComponent();
- expect(findButton().exists()).toBe(true);
+ it('works with a link', () => {
+ mountComponent({
+ tooltipTitle: LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION,
+ tooltipLink: 'foo',
});
+ expect(findTooltip().text()).toMatchInterpolatedText(
+ LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION,
+ );
+ });
+ });
- it('has the correct props/attributes bound', () => {
- mountComponent({ disabled: true });
- expect(findButton().attributes()).toMatchObject({
- 'aria-label': 'Foo title',
- icon: 'remove',
- title: 'Foo title',
- variant: 'danger',
- disabled: 'true',
- category: 'secondary',
- });
- });
+ describe('button', () => {
+ it('exists', () => {
+ mountComponent();
+ expect(findButton().exists()).toBe(true);
+ });
- it('emits a delete event', () => {
- mountComponent();
- expect(wrapper.emitted('delete')).toEqual(undefined);
- findButton().vm.$emit('click');
- expect(wrapper.emitted('delete')).toEqual([[]]);
+ it('has the correct props/attributes bound', () => {
+ mountComponent({ disabled: true });
+ expect(findButton().attributes()).toMatchObject({
+ 'aria-label': 'Foo title',
+ icon: 'remove',
+ title: 'Foo title',
+ variant: 'danger',
+ disabled: 'true',
+ category: 'secondary',
});
});
+
+ it('emits a delete event', () => {
+ mountComponent();
+ expect(wrapper.emitted('delete')).toEqual(undefined);
+ findButton().vm.$emit('click');
+ expect(wrapper.emitted('delete')).toEqual([[]]);
+ });
});
});
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 411bef54e40..690d827ec67 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
@@ -10,6 +10,7 @@ import {
LIST_DELETE_BUTTON_DISABLED,
REMOVE_REPOSITORY_LABEL,
IMAGE_DELETE_SCHEDULED_STATUS,
+ IMAGE_MIGRATING_STATE,
SCHEDULED_STATUS,
ROOT_IMAGE_TEXT,
} from '~/packages_and_registries/container_registry/explorer/constants';
@@ -41,6 +42,9 @@ describe('Image List Row', () => {
item,
...props,
},
+ provide: {
+ config: {},
+ },
directives: {
GlTooltip: createMockDirective(),
},
@@ -178,6 +182,12 @@ describe('Image List Row', () => {
expect(findDeleteBtn().props('disabled')).toBe(state);
},
);
+
+ it('is disabled when migrationState is importing', () => {
+ mountComponent({ item: { ...item, migrationState: IMAGE_MIGRATING_STATE } });
+
+ expect(findDeleteBtn().props('disabled')).toBe(true);
+ });
});
describe('tags count', () => {
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
index c91a9c0f0fb..7d09c09d03b 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
@@ -1,4 +1,4 @@
-import { GlSprintf } from '@gitlab/ui';
+import { GlSprintf, GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import Component from '~/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue';
@@ -6,6 +6,7 @@ import {
CONTAINER_REGISTRY_TITLE,
LIST_INTRO_TEXT,
EXPIRATION_POLICY_DISABLED_TEXT,
+ SET_UP_CLEANUP,
} from '~/packages_and_registries/container_registry/explorer/constants';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
@@ -21,6 +22,7 @@ describe('registry_header', () => {
const findCommandsSlot = () => wrapper.find('[data-testid="commands-slot"]');
const findImagesCountSubHeader = () => wrapper.find('[data-testid="images-count"]');
const findExpirationPolicySubHeader = () => wrapper.find('[data-testid="expiration-policy"]');
+ const findSetupCleanUpLink = () => wrapper.findComponent(GlLink);
const mountComponent = async (propsData, slots) => {
wrapper = shallowMount(Component, {
@@ -88,6 +90,7 @@ describe('registry_header', () => {
});
const text = findExpirationPolicySubHeader();
+
expect(text.exists()).toBe(true);
expect(text.props()).toMatchObject({
text: EXPIRATION_POLICY_DISABLED_TEXT,
@@ -100,12 +103,17 @@ describe('registry_header', () => {
await mountComponent({
expirationPolicy: { enabled: true },
expirationPolicyHelpPagePath: 'foo',
+ showCleanupPolicyLink: true,
imagesCount: 1,
});
const text = findExpirationPolicySubHeader();
+ const cleanupLink = findSetupCleanUpLink();
+
expect(text.exists()).toBe(true);
expect(text.props('text')).toBe('Expiration policy will run in ');
+ expect(cleanupLink.exists()).toBe(true);
+ expect(cleanupLink.text()).toBe(SET_UP_CLEANUP);
});
it('when the expiration policy is completely disabled', async () => {
await mountComponent({
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 fda1db4b7e1..7e6f88fe5bc 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
@@ -5,6 +5,7 @@ export const imagesListResponse = [
name: 'rails-12009',
path: 'gitlab-org/gitlab-test/rails-12009',
status: null,
+ migrationState: 'default',
location: '0.0.0.0:5000/gitlab-org/gitlab-test/rails-12009',
canDelete: true,
createdAt: '2020-11-03T13:29:21Z',
@@ -17,6 +18,7 @@ export const imagesListResponse = [
name: 'rails-20572',
path: 'gitlab-org/gitlab-test/rails-20572',
status: null,
+ migrationState: 'default',
location: '0.0.0.0:5000/gitlab-org/gitlab-test/rails-20572',
canDelete: true,
createdAt: '2020-09-21T06:57:43Z',
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
index da4bfcde217..79403d29d18 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
@@ -6,7 +6,6 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import getContainerRepositoriesQuery from 'shared_queries/container_registry/get_container_repositories.query.graphql';
-import CleanupPolicyEnabledAlert from '~/packages_and_registries/shared/components/cleanup_policy_enabled_alert.vue';
import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants';
import DeleteImage from '~/packages_and_registries/container_registry/explorer/components/delete_image.vue';
import CliCommands from '~/packages_and_registries/shared/components/cli_commands.vue';
@@ -58,7 +57,6 @@ describe('List Page', () => {
const findPersistedSearch = () => wrapper.findComponent(PersistedSearch);
const findEmptySearchMessage = () => wrapper.find('[data-testid="emptySearch"]');
const findDeleteImage = () => wrapper.findComponent(DeleteImage);
- const findCleanupAlert = () => wrapper.findComponent(CleanupPolicyEnabledAlert);
const fireFirstSortUpdate = () => {
findPersistedSearch().vm.$emit('update', { sort: 'UPDATED_DESC', filters: [] });
@@ -511,33 +509,4 @@ describe('List Page', () => {
testTrackingCall('confirm_delete');
});
});
-
- describe('cleanup is on alert', () => {
- it('exist when showCleanupPolicyOnAlert is true and has the correct props', async () => {
- mountComponent({
- config: {
- showCleanupPolicyOnAlert: true,
- projectPath: 'foo',
- isGroupPage: false,
- cleanupPoliciesSettingsPath: 'bar',
- },
- });
-
- await waitForApolloRequestRender();
-
- expect(findCleanupAlert().exists()).toBe(true);
- expect(findCleanupAlert().props()).toMatchObject({
- projectPath: 'foo',
- cleanupPoliciesSettingsPath: 'bar',
- });
- });
-
- it('is hidden when showCleanupPolicyOnAlert is false', async () => {
- mountComponent();
-
- await waitForApolloRequestRender();
-
- expect(findCleanupAlert().exists()).toBe(false);
- });
- });
});
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 79894e25889..dbe9793fb8c 100644
--- a/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
+++ b/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
@@ -1,19 +1,26 @@
import {
+ GlAlert,
+ GlDropdown,
+ GlDropdownItem,
GlFormInputGroup,
GlFormGroup,
+ GlModal,
GlSkeletonLoader,
GlSprintf,
GlEmptyState,
} from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
+import MockAdapter from 'axios-mock-adapter';
import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { stripTypenames } from 'helpers/graphql_helpers';
import waitForPromises from 'helpers/wait_for_promises';
import { GRAPHQL_PAGE_SIZE } from '~/packages_and_registries/dependency_proxy/constants';
+import axios from '~/lib/utils/axios_utils';
import DependencyProxyApp from '~/packages_and_registries/dependency_proxy/app.vue';
+import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import ManifestsList from '~/packages_and_registries/dependency_proxy/components/manifests_list.vue';
@@ -21,13 +28,25 @@ import getDependencyProxyDetailsQuery from '~/packages_and_registries/dependency
import { proxyDetailsQuery, proxyData, pagination, proxyManifests } from './mock_data';
+const dummyApiVersion = 'v3000';
+const dummyGrouptId = 1;
+const dummyUrlRoot = '/gitlab';
+const dummyGon = {
+ api_version: dummyApiVersion,
+ relative_url_root: dummyUrlRoot,
+};
+let originalGon;
+const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${dummyGrouptId}/dependency_proxy/cache`;
+
describe('DependencyProxyApp', () => {
let wrapper;
let apolloProvider;
let resolver;
+ let mock;
const provideDefaults = {
groupPath: 'gitlab-org',
+ groupId: dummyGrouptId,
dependencyProxyAvailable: true,
noManifestsIllustration: 'noManifestsIllustration',
};
@@ -43,9 +62,14 @@ describe('DependencyProxyApp', () => {
apolloProvider,
provide,
stubs: {
+ GlAlert,
+ GlDropdown,
+ GlDropdownItem,
GlFormInputGroup,
GlFormGroup,
+ GlModal,
GlSprintf,
+ TitleArea,
},
});
}
@@ -59,13 +83,24 @@ describe('DependencyProxyApp', () => {
const findProxyCountText = () => wrapper.findByTestId('proxy-count');
const findManifestList = () => wrapper.findComponent(ManifestsList);
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const findClearCacheDropdownList = () => wrapper.findComponent(GlDropdown);
+ const findClearCacheModal = () => wrapper.findComponent(GlModal);
+ const findClearCacheAlert = () => wrapper.findComponent(GlAlert);
beforeEach(() => {
resolver = jest.fn().mockResolvedValue(proxyDetailsQuery());
+
+ originalGon = window.gon;
+ window.gon = { ...dummyGon };
+
+ mock = new MockAdapter(axios);
+ mock.onDelete(expectedUrl).reply(202, {});
});
afterEach(() => {
wrapper.destroy();
+ window.gon = originalGon;
+ mock.restore();
});
describe('when the dependency proxy is not available', () => {
@@ -95,6 +130,12 @@ describe('DependencyProxyApp', () => {
expect(resolver).not.toHaveBeenCalled();
});
+
+ it('hides the clear cache dropdown list', () => {
+ createComponent(createComponentArguments);
+
+ expect(findClearCacheDropdownList().exists()).toBe(false);
+ });
});
describe('when the dependency proxy is available', () => {
@@ -165,6 +206,7 @@ describe('DependencyProxyApp', () => {
}),
);
createComponent();
+
return waitForPromises();
});
@@ -214,6 +256,34 @@ describe('DependencyProxyApp', () => {
fullPath: provideDefaults.groupPath,
});
});
+
+ it('shows the clear cache dropdown list', () => {
+ expect(findClearCacheDropdownList().exists()).toBe(true);
+
+ const clearCacheDropdownItem = findClearCacheDropdownList().findComponent(
+ GlDropdownItem,
+ );
+
+ expect(clearCacheDropdownItem.text()).toBe('Clear cache');
+ });
+
+ it('shows the clear cache confirmation modal', () => {
+ const modal = findClearCacheModal();
+
+ expect(modal.find('.modal-title').text()).toContain('Clear 2 images from cache?');
+ expect(modal.props('actionPrimary').text).toBe('Clear cache');
+ });
+
+ it('submits the clear cache request', async () => {
+ findClearCacheModal().vm.$emit('primary', { preventDefault: jest.fn() });
+
+ await waitForPromises();
+
+ expect(findClearCacheAlert().exists()).toBe(true);
+ expect(findClearCacheAlert().text()).toBe(
+ 'All items in the cache are scheduled for removal.',
+ );
+ });
});
});
});
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_header_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_header_spec.js
new file mode 100644
index 00000000000..636f3eeb04a
--- /dev/null
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_header_spec.js
@@ -0,0 +1,88 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlSprintf } from '@gitlab/ui';
+import { nextTick } from 'vue';
+import TitleArea from '~/vue_shared/components/registry/title_area.vue';
+import HarborListHeader from '~/packages_and_registries/harbor_registry/components/list/harbor_list_header.vue';
+import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
+import {
+ HARBOR_REGISTRY_TITLE,
+ LIST_INTRO_TEXT,
+} from '~/packages_and_registries/harbor_registry/constants/index';
+
+describe('harbor_list_header', () => {
+ let wrapper;
+
+ const findTitleArea = () => wrapper.find(TitleArea);
+ const findCommandsSlot = () => wrapper.find('[data-testid="commands-slot"]');
+ const findImagesMetaDataItem = () => wrapper.find(MetadataItem);
+
+ const mountComponent = async (propsData, slots) => {
+ wrapper = shallowMount(HarborListHeader, {
+ stubs: {
+ GlSprintf,
+ TitleArea,
+ },
+ propsData,
+ slots,
+ });
+ await nextTick();
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('header', () => {
+ it('has a title', () => {
+ mountComponent({ metadataLoading: true });
+
+ expect(findTitleArea().props()).toMatchObject({
+ title: HARBOR_REGISTRY_TITLE,
+ metadataLoading: true,
+ });
+ });
+
+ it('has a commands slot', () => {
+ mountComponent(null, { commands: '<div data-testid="commands-slot">baz</div>' });
+
+ expect(findCommandsSlot().text()).toBe('baz');
+ });
+
+ describe('sub header parts', () => {
+ describe('images count', () => {
+ it('exists', async () => {
+ await mountComponent({ imagesCount: 1 });
+
+ expect(findImagesMetaDataItem().exists()).toBe(true);
+ });
+
+ it('when there is one image', async () => {
+ await mountComponent({ imagesCount: 1 });
+
+ expect(findImagesMetaDataItem().props()).toMatchObject({
+ text: '1 Image repository',
+ icon: 'container-image',
+ });
+ });
+
+ it('when there is more than one image', async () => {
+ await mountComponent({ imagesCount: 3 });
+
+ expect(findImagesMetaDataItem().props('text')).toBe('3 Image repositories');
+ });
+ });
+ });
+ });
+
+ describe('info messages', () => {
+ describe('default message', () => {
+ it('is correctly bound to title_area props', () => {
+ mountComponent({ helpPagePath: 'foo' });
+
+ expect(findTitleArea().props('infoMessages')).toEqual([
+ { text: LIST_INTRO_TEXT, link: 'foo' },
+ ]);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_row_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_row_spec.js
new file mode 100644
index 00000000000..8560c4f78f7
--- /dev/null
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_row_spec.js
@@ -0,0 +1,99 @@
+import { shallowMount, RouterLinkStub as RouterLink } from '@vue/test-utils';
+import { GlIcon, GlSprintf, GlSkeletonLoader } from '@gitlab/ui';
+
+import HarborListRow from '~/packages_and_registries/harbor_registry/components/list/harbor_list_row.vue';
+import ListItem from '~/vue_shared/components/registry/list_item.vue';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import { harborListResponse } from '../../mock_data';
+
+describe('Harbor List Row', () => {
+ let wrapper;
+ const [item] = harborListResponse.repositories;
+
+ const findDetailsLink = () => wrapper.find(RouterLink);
+ const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
+ const findTagsCount = () => wrapper.find('[data-testid="tags-count"]');
+ const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
+
+ const mountComponent = (props) => {
+ wrapper = shallowMount(HarborListRow, {
+ stubs: {
+ RouterLink,
+ GlSprintf,
+ ListItem,
+ },
+ propsData: {
+ item,
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('image title and path', () => {
+ it('contains a link to the details page', () => {
+ mountComponent();
+
+ const link = findDetailsLink();
+ expect(link.text()).toBe(item.name);
+ expect(findDetailsLink().props('to')).toMatchObject({
+ name: 'details',
+ params: {
+ id: item.id,
+ },
+ });
+ });
+
+ it('contains a clipboard button', () => {
+ mountComponent();
+ const button = findClipboardButton();
+ expect(button.exists()).toBe(true);
+ expect(button.props('text')).toBe(item.location);
+ expect(button.props('title')).toBe(item.location);
+ });
+ });
+
+ describe('tags count', () => {
+ it('exists', () => {
+ mountComponent();
+ expect(findTagsCount().exists()).toBe(true);
+ });
+
+ it('contains a tag icon', () => {
+ mountComponent();
+ const icon = findTagsCount().find(GlIcon);
+ expect(icon.exists()).toBe(true);
+ expect(icon.props('name')).toBe('tag');
+ });
+
+ describe('loading state', () => {
+ it('shows a loader when metadataLoading is true', () => {
+ mountComponent({ metadataLoading: true });
+
+ expect(findSkeletonLoader().exists()).toBe(true);
+ });
+
+ it('hides the tags count while loading', () => {
+ mountComponent({ metadataLoading: true });
+
+ expect(findTagsCount().exists()).toBe(false);
+ });
+ });
+
+ describe('tags count text', () => {
+ it('with one tag in the image', () => {
+ mountComponent({ item: { ...item, artifactCount: 1 } });
+
+ expect(findTagsCount().text()).toMatchInterpolatedText('1 Tag');
+ });
+ it('with more than one tag in the image', () => {
+ mountComponent({ item: { ...item, artifactCount: 3 } });
+
+ expect(findTagsCount().text()).toMatchInterpolatedText('3 Tags');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js
new file mode 100644
index 00000000000..f018eff58c9
--- /dev/null
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js
@@ -0,0 +1,39 @@
+import { shallowMount } from '@vue/test-utils';
+import HarborList from '~/packages_and_registries/harbor_registry/components/list/harbor_list.vue';
+import HarborListRow from '~/packages_and_registries/harbor_registry/components/list/harbor_list_row.vue';
+import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue';
+import { harborListResponse } from '../../mock_data';
+
+describe('Harbor List', () => {
+ let wrapper;
+
+ const findHarborListRow = () => wrapper.findAll(HarborListRow);
+
+ const mountComponent = (props) => {
+ wrapper = shallowMount(HarborList, {
+ stubs: { RegistryList },
+ propsData: {
+ images: harborListResponse.repositories,
+ pageInfo: harborListResponse.pageInfo,
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('list', () => {
+ it('contains one list element for each image', () => {
+ mountComponent();
+
+ expect(findHarborListRow().length).toBe(harborListResponse.repositories.length);
+ });
+
+ it('passes down the metadataLoading prop', () => {
+ mountComponent({ metadataLoading: true });
+ expect(findHarborListRow().at(0).props('metadataLoading')).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/packages_and_registries/harbor_registry/mock_data.js b/spec/frontend/packages_and_registries/harbor_registry/mock_data.js
new file mode 100644
index 00000000000..85399c22e79
--- /dev/null
+++ b/spec/frontend/packages_and_registries/harbor_registry/mock_data.js
@@ -0,0 +1,175 @@
+export const harborListResponse = {
+ repositories: [
+ {
+ artifactCount: 1,
+ creationTime: '2022-03-02T06:35:53.205Z',
+ id: 25,
+ name: 'shao/flinkx',
+ projectId: 21,
+ pullCount: 0,
+ updateTime: '2022-03-02T06:35:53.205Z',
+ location: 'demo.harbor.com/gitlab-cn/build/cng-images/gitlab-kas',
+ },
+ {
+ artifactCount: 1,
+ creationTime: '2022-03-02T06:35:53.205Z',
+ id: 26,
+ name: 'shao/flinkx1',
+ projectId: 21,
+ pullCount: 0,
+ updateTime: '2022-03-02T06:35:53.205Z',
+ location: 'demo.harbor.com/gitlab-cn/build/cng-images/gitlab-kas',
+ },
+ {
+ artifactCount: 1,
+ creationTime: '2022-03-02T06:35:53.205Z',
+ id: 27,
+ name: 'shao/flinkx2',
+ projectId: 21,
+ pullCount: 0,
+ updateTime: '2022-03-02T06:35:53.205Z',
+ location: 'demo.harbor.com/gitlab-cn/build/cng-images/gitlab-kas',
+ },
+ ],
+ totalCount: 3,
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ },
+};
+
+export const harborTagsResponse = {
+ tags: [
+ {
+ digest: 'sha256:7f386a1844faf341353e1c20f2f39f11f397604fedc475435d13f756eeb235d1',
+ location:
+ 'registry.gitlab.com/gitlab-org/gitlab/gitlab-ee-qa/cache:02310e655103823920157bc4410ea361dc638bc2cda59667d2cb1f2a988e264c',
+ path:
+ 'gitlab-org/gitlab/gitlab-ee-qa/cache:02310e655103823920157bc4410ea361dc638bc2cda59667d2cb1f2a988e264c',
+ name: '02310e655103823920157bc4410ea361dc638bc2cda59667d2cb1f2a988e264c',
+ revision: 'f53bde3d44699e04e11cf15fb415046a0913e2623d878d89bc21adb2cbda5255',
+ shortRevision: 'f53bde3d4',
+ createdAt: '2022-03-02T23:59:05+00:00',
+ totalSize: '6623124',
+ },
+ {
+ digest: 'sha256:4554416b84c4568fe93086620b637064ed029737aabe7308b96d50e3d9d92ed7',
+ location:
+ 'registry.gitlab.com/gitlab-org/gitlab/gitlab-ee-qa/cache:02deb4dddf177212b50e883d5e4f6c03731fad1a18cd27261736cd9dbba79160',
+ path:
+ 'gitlab-org/gitlab/gitlab-ee-qa/cache:02deb4dddf177212b50e883d5e4f6c03731fad1a18cd27261736cd9dbba79160',
+ name: '02deb4dddf177212b50e883d5e4f6c03731fad1a18cd27261736cd9dbba79160',
+ revision: 'e1fe52d8bab66d71bd54a6b8784d3b9edbc68adbd6ea87f5fa44d9974144ef9e',
+ shortRevision: 'e1fe52d8b',
+ createdAt: '2022-02-10T01:09:56+00:00',
+ totalSize: '920760',
+ },
+ {
+ digest: 'sha256:14f37b60e52b9ce0e9f8f7094b311d265384798592f783487c30aaa3d58e6345',
+ location:
+ 'registry.gitlab.com/gitlab-org/gitlab/gitlab-ee-qa/cache:03bc5971bab1e849ba52a20a31e7273053f22b2ddb1d04bd6b77d53a2635727a',
+ path:
+ 'gitlab-org/gitlab/gitlab-ee-qa/cache:03bc5971bab1e849ba52a20a31e7273053f22b2ddb1d04bd6b77d53a2635727a',
+ name: '03bc5971bab1e849ba52a20a31e7273053f22b2ddb1d04bd6b77d53a2635727a',
+ revision: 'c72770c6eb93c421bc496964b4bffc742b1ec2e642cdab876be7afda1856029f',
+ shortRevision: 'c72770c6e',
+ createdAt: '2021-12-22T04:48:48+00:00',
+ totalSize: '48609053',
+ },
+ {
+ digest: 'sha256:e925e3b8277ea23f387ed5fba5e78280cfac7cfb261a78cf046becf7b6a3faae',
+ location:
+ 'registry.gitlab.com/gitlab-org/gitlab/gitlab-ee-qa/cache:03f495bc5714bff78bb14293320d336afdf47fd47ddff0c3c5f09f8da86d5d19',
+ path:
+ 'gitlab-org/gitlab/gitlab-ee-qa/cache:03f495bc5714bff78bb14293320d336afdf47fd47ddff0c3c5f09f8da86d5d19',
+ name: '03f495bc5714bff78bb14293320d336afdf47fd47ddff0c3c5f09f8da86d5d19',
+ revision: '1ac2a43194f4e15166abdf3f26e6ec92215240490b9cac834d63de1a3d87494a',
+ shortRevision: '1ac2a4319',
+ createdAt: '2022-03-09T11:02:27+00:00',
+ totalSize: '35141894',
+ },
+ {
+ digest: 'sha256:7d8303fd5c077787a8c879f8f66b69e2b5605f48ccd3f286e236fb0749fcc1ca',
+ location:
+ 'registry.gitlab.com/gitlab-org/gitlab/gitlab-ee-qa/cache:05a4e58231e54b70aab2d6f22ba4fbe10e48aa4ddcbfef11c5662241c2ae4fda',
+ path:
+ 'gitlab-org/gitlab/gitlab-ee-qa/cache:05a4e58231e54b70aab2d6f22ba4fbe10e48aa4ddcbfef11c5662241c2ae4fda',
+ name: '05a4e58231e54b70aab2d6f22ba4fbe10e48aa4ddcbfef11c5662241c2ae4fda',
+ revision: 'cf8fee086701016e1a84e6824f0c896951fef4cce9d4745459558b87eec3232c',
+ shortRevision: 'cf8fee086',
+ createdAt: '2022-01-21T11:31:43+00:00',
+ totalSize: '48716070',
+ },
+ {
+ digest: 'sha256:b33611cefe20e4a41a6e0dce356a5d7ef3c177ea7536a58652f5b3a4f2f83549',
+ location:
+ 'registry.gitlab.com/gitlab-org/gitlab/gitlab-ee-qa/cache:093d2746876997723541aec8b88687a4cdb3b5bbb0279c5089b7891317741a9a',
+ path:
+ 'gitlab-org/gitlab/gitlab-ee-qa/cache:093d2746876997723541aec8b88687a4cdb3b5bbb0279c5089b7891317741a9a',
+ name: '093d2746876997723541aec8b88687a4cdb3b5bbb0279c5089b7891317741a9a',
+ revision: '1a4b48198b13d55242c5164e64d41c4e9f75b5d9506bc6e0efc1534dd0dd1f15',
+ shortRevision: '1a4b48198',
+ createdAt: '2022-01-21T11:31:51+00:00',
+ totalSize: '6623127',
+ },
+ {
+ digest: 'sha256:d25c3c020e2dbd4711a67b9fe308f4cbb7b0bb21815e722a02f91c570dc5d519',
+ location:
+ 'registry.gitlab.com/gitlab-org/gitlab/gitlab-ee-qa/cache:09698b3fae81dfd6e02554dbc82930f304a6356c8f541c80e8598a42aed985f7',
+ path:
+ 'gitlab-org/gitlab/gitlab-ee-qa/cache:09698b3fae81dfd6e02554dbc82930f304a6356c8f541c80e8598a42aed985f7',
+ name: '09698b3fae81dfd6e02554dbc82930f304a6356c8f541c80e8598a42aed985f7',
+ revision: '03e2e2777dde01c30469ee8c710973dd08a7a4f70494d7dc1583c24b525d7f61',
+ shortRevision: '03e2e2777',
+ createdAt: '2022-03-02T23:58:20+00:00',
+ totalSize: '911377',
+ },
+ {
+ digest: 'sha256:fb760e4d2184e9e8e39d6917534d4610fe01009734698a5653b2de1391ba28f4',
+ location:
+ 'registry.gitlab.com/gitlab-org/gitlab/gitlab-ee-qa/cache:09b830c3eaf80d547f3b523d8e242a2c411085c349dab86c520f36c7b7644f95',
+ path:
+ 'gitlab-org/gitlab/gitlab-ee-qa/cache:09b830c3eaf80d547f3b523d8e242a2c411085c349dab86c520f36c7b7644f95',
+ name: '09b830c3eaf80d547f3b523d8e242a2c411085c349dab86c520f36c7b7644f95',
+ revision: '350e78d60646bf6967244448c6aaa14d21ecb9a0c6cf87e9ff0361cbe59b9012',
+ shortRevision: '350e78d60',
+ createdAt: '2022-01-19T13:49:14+00:00',
+ totalSize: '48710241',
+ },
+ {
+ digest: 'sha256:407250f380cea92729cbc038c420e74900f53b852e11edc6404fe75a0fd2c402',
+ location:
+ 'registry.gitlab.com/gitlab-org/gitlab/gitlab-ee-qa/cache:0d03504a17b467eafc8c96bde70af26c74bd459a32b7eb2dd189dd6b3c121557',
+ path:
+ 'gitlab-org/gitlab/gitlab-ee-qa/cache:0d03504a17b467eafc8c96bde70af26c74bd459a32b7eb2dd189dd6b3c121557',
+ name: '0d03504a17b467eafc8c96bde70af26c74bd459a32b7eb2dd189dd6b3c121557',
+ revision: '76038370b7f3904364891457c4a6a234897255e6b9f45d0a852bf3a7e5257e18',
+ shortRevision: '76038370b',
+ createdAt: '2022-01-24T12:56:22+00:00',
+ totalSize: '280065',
+ },
+ {
+ digest: 'sha256:ada87f25218542951ce6720c27f3d0758e90c2540bd129f5cfb9e15b31e07b07',
+ location:
+ 'registry.gitlab.com/gitlab-org/gitlab/gitlab-ee-qa/cache:0eb20a4a7cac2ebea821d420b3279654fe550fd8502f1785c1927aa84e5949eb',
+ path:
+ 'gitlab-org/gitlab/gitlab-ee-qa/cache:0eb20a4a7cac2ebea821d420b3279654fe550fd8502f1785c1927aa84e5949eb',
+ name: '0eb20a4a7cac2ebea821d420b3279654fe550fd8502f1785c1927aa84e5949eb',
+ revision: '3d4b49a7bbb36c48bb721f4d0e76e7950bec3878ee29cdfdd6da39f575d6d37f',
+ shortRevision: '3d4b49a7b',
+ createdAt: '2022-02-17T17:37:52+00:00',
+ totalSize: '48655767',
+ },
+ ],
+ totalCount: 100,
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ },
+};
+
+export const dockerCommands = {
+ dockerBuildCommand: 'foofoo',
+ dockerPushCommand: 'barbar',
+ dockerLoginCommand: 'bazbaz',
+};
diff --git a/spec/frontend/packages_and_registries/harbor_registry/pages/index_spec.js b/spec/frontend/packages_and_registries/harbor_registry/pages/index_spec.js
new file mode 100644
index 00000000000..55fc8066f65
--- /dev/null
+++ b/spec/frontend/packages_and_registries/harbor_registry/pages/index_spec.js
@@ -0,0 +1,24 @@
+import { shallowMount } from '@vue/test-utils';
+import component from '~/packages_and_registries/harbor_registry/pages/index.vue';
+
+describe('List Page', () => {
+ let wrapper;
+
+ const findRouterView = () => wrapper.find({ ref: 'router-view' });
+
+ const mountComponent = () => {
+ wrapper = shallowMount(component, {
+ stubs: {
+ RouterView: true,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('has a router view', () => {
+ expect(findRouterView().exists()).toBe(true);
+ });
+});
diff --git a/spec/frontend/packages_and_registries/harbor_registry/pages/list_spec.js b/spec/frontend/packages_and_registries/harbor_registry/pages/list_spec.js
new file mode 100644
index 00000000000..61ee36a2794
--- /dev/null
+++ b/spec/frontend/packages_and_registries/harbor_registry/pages/list_spec.js
@@ -0,0 +1,140 @@
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import { GlSkeletonLoader } from '@gitlab/ui';
+import HarborListHeader from '~/packages_and_registries/harbor_registry/components/list/harbor_list_header.vue';
+import HarborRegistryList from '~/packages_and_registries/harbor_registry/pages/list.vue';
+import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
+import waitForPromises from 'helpers/wait_for_promises';
+// import { harborListResponse } from '~/packages_and_registries/harbor_registry/mock_api.js';
+import HarborList from '~/packages_and_registries/harbor_registry/components/list/harbor_list.vue';
+import CliCommands from '~/packages_and_registries/shared/components/cli_commands.vue';
+import { SORT_FIELDS } from '~/packages_and_registries/harbor_registry/constants/index';
+import { harborListResponse, dockerCommands } from '../mock_data';
+
+let mockHarborListResponse;
+jest.mock('~/packages_and_registries/harbor_registry/mock_api.js', () => ({
+ harborListResponse: () => mockHarborListResponse,
+}));
+
+describe('Harbor List Page', () => {
+ let wrapper;
+
+ const waitForHarborPageRequest = async () => {
+ await waitForPromises();
+ await nextTick();
+ };
+
+ beforeEach(() => {
+ mockHarborListResponse = Promise.resolve(harborListResponse);
+ });
+
+ const findHarborListHeader = () => wrapper.findComponent(HarborListHeader);
+ const findPersistedSearch = () => wrapper.findComponent(PersistedSearch);
+ const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
+ const findHarborList = () => wrapper.findComponent(HarborList);
+ const findCliCommands = () => wrapper.findComponent(CliCommands);
+
+ const fireFirstSortUpdate = () => {
+ findPersistedSearch().vm.$emit('update', { sort: 'UPDATED_DESC', filters: [] });
+ };
+
+ const mountComponent = ({ config = { isGroupPage: false } } = {}) => {
+ wrapper = shallowMount(HarborRegistryList, {
+ stubs: {
+ HarborListHeader,
+ },
+ provide() {
+ return {
+ config,
+ ...dockerCommands,
+ };
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('contains harbor registry header', async () => {
+ mountComponent();
+ fireFirstSortUpdate();
+ await waitForHarborPageRequest();
+ await nextTick();
+
+ expect(findHarborListHeader().exists()).toBe(true);
+ expect(findHarborListHeader().props()).toMatchObject({
+ imagesCount: 3,
+ metadataLoading: false,
+ });
+ });
+
+ describe('isLoading is true', () => {
+ it('shows the skeleton loader', async () => {
+ mountComponent();
+ fireFirstSortUpdate();
+
+ expect(findSkeletonLoader().exists()).toBe(true);
+ });
+
+ it('harborList is not visible', () => {
+ mountComponent();
+
+ expect(findHarborList().exists()).toBe(false);
+ });
+
+ it('cli commands is not visible', () => {
+ mountComponent();
+
+ expect(findCliCommands().exists()).toBe(false);
+ });
+
+ it('title has the metadataLoading props set to true', async () => {
+ mountComponent();
+ fireFirstSortUpdate();
+
+ expect(findHarborListHeader().props('metadataLoading')).toBe(true);
+ });
+ });
+
+ describe('list is not empty', () => {
+ describe('unfiltered state', () => {
+ it('quick start is visible', async () => {
+ mountComponent();
+ fireFirstSortUpdate();
+
+ await waitForHarborPageRequest();
+ await nextTick();
+
+ expect(findCliCommands().exists()).toBe(true);
+ });
+
+ it('list component is visible', async () => {
+ mountComponent();
+ fireFirstSortUpdate();
+
+ await waitForHarborPageRequest();
+ await nextTick();
+
+ expect(findHarborList().exists()).toBe(true);
+ });
+ });
+
+ describe('search and sorting', () => {
+ it('has a persisted search box element', async () => {
+ mountComponent();
+ fireFirstSortUpdate();
+ await waitForHarborPageRequest();
+ await nextTick();
+
+ const harborRegistrySearch = findPersistedSearch();
+ expect(harborRegistrySearch.exists()).toBe(true);
+ expect(harborRegistrySearch.props()).toMatchObject({
+ defaultOrder: 'UPDATED',
+ defaultSort: 'desc',
+ sortableFields: SORT_FIELDS,
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js
index b9383d6c38c..31ab108558c 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js
@@ -20,10 +20,10 @@ jest.mock('~/api.js');
describe('Actions Package details store', () => {
describe('fetchPackageVersions', () => {
- it('should fetch the package versions', (done) => {
+ it('should fetch the package versions', async () => {
Api.projectPackage = jest.fn().mockResolvedValue({ data: packageEntity });
- testAction(
+ await testAction(
fetchPackageVersions,
undefined,
{ packageEntity },
@@ -33,20 +33,14 @@ describe('Actions Package details store', () => {
{ type: types.SET_LOADING, payload: false },
],
[],
- () => {
- expect(Api.projectPackage).toHaveBeenCalledWith(
- packageEntity.project_id,
- packageEntity.id,
- );
- done();
- },
);
+ expect(Api.projectPackage).toHaveBeenCalledWith(packageEntity.project_id, packageEntity.id);
});
- it("does not set the versions if they don't exist", (done) => {
+ it("does not set the versions if they don't exist", async () => {
Api.projectPackage = jest.fn().mockResolvedValue({ data: { packageEntity, versions: null } });
- testAction(
+ await testAction(
fetchPackageVersions,
undefined,
{ packageEntity },
@@ -55,20 +49,14 @@ describe('Actions Package details store', () => {
{ type: types.SET_LOADING, payload: false },
],
[],
- () => {
- expect(Api.projectPackage).toHaveBeenCalledWith(
- packageEntity.project_id,
- packageEntity.id,
- );
- done();
- },
);
+ expect(Api.projectPackage).toHaveBeenCalledWith(packageEntity.project_id, packageEntity.id);
});
- it('should create flash on API error', (done) => {
+ it('should create flash on API error', async () => {
Api.projectPackage = jest.fn().mockRejectedValue();
- testAction(
+ await testAction(
fetchPackageVersions,
undefined,
{ packageEntity },
@@ -77,41 +65,31 @@ describe('Actions Package details store', () => {
{ type: types.SET_LOADING, payload: false },
],
[],
- () => {
- expect(Api.projectPackage).toHaveBeenCalledWith(
- packageEntity.project_id,
- packageEntity.id,
- );
- expect(createFlash).toHaveBeenCalledWith({
- message: FETCH_PACKAGE_VERSIONS_ERROR,
- type: 'warning',
- });
- done();
- },
);
+ expect(Api.projectPackage).toHaveBeenCalledWith(packageEntity.project_id, packageEntity.id);
+ expect(createFlash).toHaveBeenCalledWith({
+ message: FETCH_PACKAGE_VERSIONS_ERROR,
+ type: 'warning',
+ });
});
});
describe('deletePackage', () => {
- it('should call Api.deleteProjectPackage', (done) => {
+ it('should call Api.deleteProjectPackage', async () => {
Api.deleteProjectPackage = jest.fn().mockResolvedValue();
- testAction(deletePackage, undefined, { packageEntity }, [], [], () => {
- expect(Api.deleteProjectPackage).toHaveBeenCalledWith(
- packageEntity.project_id,
- packageEntity.id,
- );
- done();
- });
+ await testAction(deletePackage, undefined, { packageEntity }, [], []);
+ expect(Api.deleteProjectPackage).toHaveBeenCalledWith(
+ packageEntity.project_id,
+ packageEntity.id,
+ );
});
- it('should create flash on API error', (done) => {
+ it('should create flash on API error', async () => {
Api.deleteProjectPackage = jest.fn().mockRejectedValue();
- testAction(deletePackage, undefined, { packageEntity }, [], [], () => {
- expect(createFlash).toHaveBeenCalledWith({
- message: DELETE_PACKAGE_ERROR_MESSAGE,
- type: 'warning',
- });
- done();
+ await testAction(deletePackage, undefined, { packageEntity }, [], []);
+ expect(createFlash).toHaveBeenCalledWith({
+ message: DELETE_PACKAGE_ERROR_MESSAGE,
+ type: 'warning',
});
});
});
@@ -119,37 +97,33 @@ describe('Actions Package details store', () => {
describe('deletePackageFile', () => {
const fileId = 'a_file_id';
- it('should call Api.deleteProjectPackageFile and commit the right data', (done) => {
+ it('should call Api.deleteProjectPackageFile and commit the right data', async () => {
const packageFiles = [{ id: 'foo' }, { id: fileId }];
Api.deleteProjectPackageFile = jest.fn().mockResolvedValue();
- testAction(
+ await testAction(
deletePackageFile,
fileId,
{ packageEntity, packageFiles },
[{ type: types.UPDATE_PACKAGE_FILES, payload: [{ id: 'foo' }] }],
[],
- () => {
- expect(Api.deleteProjectPackageFile).toHaveBeenCalledWith(
- packageEntity.project_id,
- packageEntity.id,
- fileId,
- );
- expect(createFlash).toHaveBeenCalledWith({
- message: DELETE_PACKAGE_FILE_SUCCESS_MESSAGE,
- type: 'success',
- });
- done();
- },
);
+ expect(Api.deleteProjectPackageFile).toHaveBeenCalledWith(
+ packageEntity.project_id,
+ packageEntity.id,
+ fileId,
+ );
+ expect(createFlash).toHaveBeenCalledWith({
+ message: DELETE_PACKAGE_FILE_SUCCESS_MESSAGE,
+ type: 'success',
+ });
});
- it('should create flash on API error', (done) => {
+
+ it('should create flash on API error', async () => {
Api.deleteProjectPackageFile = jest.fn().mockRejectedValue();
- testAction(deletePackageFile, fileId, { packageEntity }, [], [], () => {
- expect(createFlash).toHaveBeenCalledWith({
- message: DELETE_PACKAGE_FILE_ERROR_MESSAGE,
- type: 'warning',
- });
- done();
+ await testAction(deletePackageFile, fileId, { packageEntity }, [], []);
+ expect(createFlash).toHaveBeenCalledWith({
+ message: DELETE_PACKAGE_FILE_ERROR_MESSAGE,
+ type: 'warning',
});
});
});
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap
index d82af8f9e63..a33528d2d91 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap
@@ -21,7 +21,7 @@ exports[`packages_list_app renders 1`] = `
>
<img
alt=""
- class="gl-max-w-full"
+ class="gl-max-w-full gl-dark-invert-keep-hue"
role="img"
src="helpSvg"
/>
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js
index 3fbfe1060dc..d596f2dae33 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js
@@ -32,8 +32,8 @@ describe('Actions Package list store', () => {
};
const filter = [];
- it('should fetch the project packages list when isGroupPage is false', (done) => {
- testAction(
+ it('should fetch the project packages list when isGroupPage is false', async () => {
+ await testAction(
actions.requestPackagesList,
undefined,
{ config: { isGroupPage: false, resourceId: 1 }, sorting, filter },
@@ -43,17 +43,14 @@ describe('Actions Package list store', () => {
{ type: 'receivePackagesListSuccess', payload: { data: 'foo', headers } },
{ type: 'setLoading', payload: false },
],
- () => {
- expect(Api.projectPackages).toHaveBeenCalledWith(1, {
- params: { page: 1, per_page: 20, sort: sorting.sort, order_by: sorting.orderBy },
- });
- done();
- },
);
+ expect(Api.projectPackages).toHaveBeenCalledWith(1, {
+ params: { page: 1, per_page: 20, sort: sorting.sort, order_by: sorting.orderBy },
+ });
});
- it('should fetch the group packages list when isGroupPage is true', (done) => {
- testAction(
+ it('should fetch the group packages list when isGroupPage is true', async () => {
+ await testAction(
actions.requestPackagesList,
undefined,
{ config: { isGroupPage: true, resourceId: 2 }, sorting, filter },
@@ -63,19 +60,16 @@ describe('Actions Package list store', () => {
{ type: 'receivePackagesListSuccess', payload: { data: 'baz', headers } },
{ type: 'setLoading', payload: false },
],
- () => {
- expect(Api.groupPackages).toHaveBeenCalledWith(2, {
- params: { page: 1, per_page: 20, sort: sorting.sort, order_by: sorting.orderBy },
- });
- done();
- },
);
+ expect(Api.groupPackages).toHaveBeenCalledWith(2, {
+ params: { page: 1, per_page: 20, sort: sorting.sort, order_by: sorting.orderBy },
+ });
});
- it('should fetch packages of a certain type when a filter with a type is present', (done) => {
+ it('should fetch packages of a certain type when a filter with a type is present', async () => {
const packageType = 'maven';
- testAction(
+ await testAction(
actions.requestPackagesList,
undefined,
{
@@ -89,24 +83,21 @@ describe('Actions Package list store', () => {
{ type: 'receivePackagesListSuccess', payload: { data: 'foo', headers } },
{ type: 'setLoading', payload: false },
],
- () => {
- expect(Api.projectPackages).toHaveBeenCalledWith(1, {
- params: {
- page: 1,
- per_page: 20,
- sort: sorting.sort,
- order_by: sorting.orderBy,
- package_type: packageType,
- },
- });
- done();
- },
);
+ expect(Api.projectPackages).toHaveBeenCalledWith(1, {
+ params: {
+ page: 1,
+ per_page: 20,
+ sort: sorting.sort,
+ order_by: sorting.orderBy,
+ package_type: packageType,
+ },
+ });
});
- it('should create flash on API error', (done) => {
+ it('should create flash on API error', async () => {
Api.projectPackages = jest.fn().mockRejectedValue();
- testAction(
+ await testAction(
actions.requestPackagesList,
undefined,
{ config: { isGroupPage: false, resourceId: 2 }, sorting, filter },
@@ -115,15 +106,12 @@ describe('Actions Package list store', () => {
{ type: 'setLoading', payload: true },
{ type: 'setLoading', payload: false },
],
- () => {
- expect(createFlash).toHaveBeenCalled();
- done();
- },
);
+ expect(createFlash).toHaveBeenCalled();
});
- it('should force the terraform_module type when forceTerraform is true', (done) => {
- testAction(
+ it('should force the terraform_module type when forceTerraform is true', async () => {
+ await testAction(
actions.requestPackagesList,
undefined,
{ config: { isGroupPage: false, resourceId: 1, forceTerraform: true }, sorting, filter },
@@ -133,27 +121,24 @@ describe('Actions Package list store', () => {
{ type: 'receivePackagesListSuccess', payload: { data: 'foo', headers } },
{ type: 'setLoading', payload: false },
],
- () => {
- expect(Api.projectPackages).toHaveBeenCalledWith(1, {
- params: {
- page: 1,
- per_page: 20,
- sort: sorting.sort,
- order_by: sorting.orderBy,
- package_type: 'terraform_module',
- },
- });
- done();
- },
);
+ expect(Api.projectPackages).toHaveBeenCalledWith(1, {
+ params: {
+ page: 1,
+ per_page: 20,
+ sort: sorting.sort,
+ order_by: sorting.orderBy,
+ package_type: 'terraform_module',
+ },
+ });
});
});
describe('receivePackagesListSuccess', () => {
- it('should set received packages', (done) => {
+ it('should set received packages', () => {
const data = 'foo';
- testAction(
+ return testAction(
actions.receivePackagesListSuccess,
{ data, headers },
null,
@@ -162,33 +147,30 @@ describe('Actions Package list store', () => {
{ type: types.SET_PAGINATION, payload: headers },
],
[],
- done,
);
});
});
describe('setInitialState', () => {
- it('should commit setInitialState', (done) => {
- testAction(
+ it('should commit setInitialState', () => {
+ return testAction(
actions.setInitialState,
'1',
null,
[{ type: types.SET_INITIAL_STATE, payload: '1' }],
[],
- done,
);
});
});
describe('setLoading', () => {
- it('should commit set main loading', (done) => {
- testAction(
+ it('should commit set main loading', () => {
+ return testAction(
actions.setLoading,
true,
null,
[{ type: types.SET_MAIN_LOADING, payload: true }],
[],
- done,
);
});
});
@@ -199,11 +181,11 @@ describe('Actions Package list store', () => {
delete_api_path: 'foo',
},
};
- it('should perform a delete operation on _links.delete_api_path', (done) => {
+ it('should perform a delete operation on _links.delete_api_path', () => {
mock.onDelete(payload._links.delete_api_path).replyOnce(200);
Api.projectPackages = jest.fn().mockResolvedValue({ data: 'foo' });
- testAction(
+ return testAction(
actions.requestDeletePackage,
payload,
{ pagination: { page: 1 } },
@@ -212,13 +194,12 @@ describe('Actions Package list store', () => {
{ type: 'setLoading', payload: true },
{ type: 'requestPackagesList', payload: { page: 1 } },
],
- done,
);
});
- it('should stop the loading and call create flash on api error', (done) => {
+ it('should stop the loading and call create flash on api error', async () => {
mock.onDelete(payload._links.delete_api_path).replyOnce(400);
- testAction(
+ await testAction(
actions.requestDeletePackage,
payload,
null,
@@ -227,50 +208,44 @@ describe('Actions Package list store', () => {
{ type: 'setLoading', payload: true },
{ type: 'setLoading', payload: false },
],
- () => {
- expect(createFlash).toHaveBeenCalled();
- done();
- },
);
+ expect(createFlash).toHaveBeenCalled();
});
it.each`
property | actionPayload
${'_links'} | ${{}}
${'delete_api_path'} | ${{ _links: {} }}
- `('should reject and createFlash when $property is missing', ({ actionPayload }, done) => {
- testAction(actions.requestDeletePackage, actionPayload, null, [], []).catch((e) => {
+ `('should reject and createFlash when $property is missing', ({ actionPayload }) => {
+ return testAction(actions.requestDeletePackage, actionPayload, null, [], []).catch((e) => {
expect(e).toEqual(new Error(MISSING_DELETE_PATH_ERROR));
expect(createFlash).toHaveBeenCalledWith({
message: DELETE_PACKAGE_ERROR_MESSAGE,
});
- done();
});
});
});
describe('setSorting', () => {
- it('should commit SET_SORTING', (done) => {
- testAction(
+ it('should commit SET_SORTING', () => {
+ return testAction(
actions.setSorting,
'foo',
null,
[{ type: types.SET_SORTING, payload: 'foo' }],
[],
- done,
);
});
});
describe('setFilter', () => {
- it('should commit SET_FILTER', (done) => {
- testAction(
+ it('should commit SET_FILTER', () => {
+ return testAction(
actions.setFilter,
'foo',
null,
[{ type: types.SET_FILTER, payload: 'foo' }],
[],
- done,
);
});
});
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js
index 9e91b15bc6e..3670cfca8ea 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js
@@ -73,7 +73,6 @@ describe('Package Search', () => {
mountComponent();
expect(findLocalStorageSync().props()).toMatchObject({
- asJson: true,
storageKey: 'package_registry_list_sorting',
value: {
orderBy: LIST_KEY_CREATED_AT,
diff --git a/spec/frontend/packages_and_registries/package_registry/pages/__snapshots__/list_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/pages/__snapshots__/list_spec.js.snap
index 0154486e224..17905a8db2d 100644
--- a/spec/frontend/packages_and_registries/package_registry/pages/__snapshots__/list_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/pages/__snapshots__/list_spec.js.snap
@@ -21,7 +21,7 @@ exports[`PackagesListApp renders 1`] = `
>
<img
alt=""
- class="gl-max-w-full"
+ class="gl-max-w-full gl-dark-invert-keep-hue"
role="img"
src="emptyListIllustration"
/>
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 a6c929844b1..0a72f0269ee 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
@@ -12,7 +12,6 @@ import {
UNAVAILABLE_USER_FEATURE_TEXT,
} from '~/packages_and_registries/settings/project/constants';
import expirationPolicyQuery from '~/packages_and_registries/settings/project/graphql/queries/get_expiration_policy.query.graphql';
-import CleanupPolicyEnabledAlert from '~/packages_and_registries/shared/components/cleanup_policy_enabled_alert.vue';
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
import {
@@ -31,12 +30,11 @@ describe('Registry Settings App', () => {
adminSettingsPath: 'settingsPath',
enableHistoricEntries: false,
helpPagePath: 'helpPagePath',
- showCleanupPolicyOnAlert: false,
+ showCleanupPolicyLink: false,
};
const findSettingsComponent = () => wrapper.find(SettingsForm);
const findAlert = () => wrapper.find(GlAlert);
- const findCleanupAlert = () => wrapper.findComponent(CleanupPolicyEnabledAlert);
const mountComponent = (provide = defaultProvidedValues, config) => {
wrapper = shallowMount(component, {
@@ -69,26 +67,6 @@ describe('Registry Settings App', () => {
wrapper.destroy();
});
- describe('cleanup is on alert', () => {
- it('exist when showCleanupPolicyOnAlert is true and has the correct props', () => {
- mountComponent({
- ...defaultProvidedValues,
- showCleanupPolicyOnAlert: true,
- });
-
- expect(findCleanupAlert().exists()).toBe(true);
- expect(findCleanupAlert().props()).toMatchObject({
- projectPath: 'path',
- });
- });
-
- it('is hidden when showCleanupPolicyOnAlert is false', async () => {
- mountComponent();
-
- expect(findCleanupAlert().exists()).toBe(false);
- });
- });
-
describe('isEdited status', () => {
it.each`
description | apiResponse | workingCopy | result
diff --git a/spec/frontend/packages_and_registries/shared/components/__snapshots__/cleanup_policy_enabled_alert_spec.js.snap b/spec/frontend/packages_and_registries/shared/components/__snapshots__/cleanup_policy_enabled_alert_spec.js.snap
deleted file mode 100644
index 2cded2ead2e..00000000000
--- a/spec/frontend/packages_and_registries/shared/components/__snapshots__/cleanup_policy_enabled_alert_spec.js.snap
+++ /dev/null
@@ -1,19 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`CleanupPolicyEnabledAlert renders 1`] = `
-<gl-alert-stub
- class="gl-mt-2"
- dismissible="true"
- dismisslabel="Dismiss"
- primarybuttonlink=""
- primarybuttontext=""
- secondarybuttonlink=""
- secondarybuttontext=""
- title=""
- variant="info"
->
- <gl-sprintf-stub
- message="Cleanup policies are now available for this project. %{linkStart}Click here to get started.%{linkEnd}"
- />
-</gl-alert-stub>
-`;
diff --git a/spec/frontend/packages_and_registries/shared/components/__snapshots__/registry_breadcrumb_spec.js.snap b/spec/frontend/packages_and_registries/shared/components/__snapshots__/registry_breadcrumb_spec.js.snap
index ceae8eebaef..3dd6023140f 100644
--- a/spec/frontend/packages_and_registries/shared/components/__snapshots__/registry_breadcrumb_spec.js.snap
+++ b/spec/frontend/packages_and_registries/shared/components/__snapshots__/registry_breadcrumb_spec.js.snap
@@ -10,11 +10,10 @@ exports[`Registry Breadcrumb when is not rootRoute renders 1`] = `
class="breadcrumb gl-breadcrumb-list"
>
<li
- class="breadcrumb-item gl-breadcrumb-item"
+ class="gl-breadcrumb-item"
>
<a
class=""
- href="/"
target="_self"
>
<span>
@@ -45,9 +44,10 @@ exports[`Registry Breadcrumb when is not rootRoute renders 1`] = `
<!---->
<li
- class="breadcrumb-item gl-breadcrumb-item"
+ class="gl-breadcrumb-item"
>
<a
+ aria-current="page"
class=""
href="#"
target="_self"
@@ -75,11 +75,11 @@ exports[`Registry Breadcrumb when is rootRoute renders 1`] = `
class="breadcrumb gl-breadcrumb-list"
>
<li
- class="breadcrumb-item gl-breadcrumb-item"
+ class="gl-breadcrumb-item"
>
<a
+ aria-current="page"
class=""
- href="/"
target="_self"
>
<span>
diff --git a/spec/frontend/packages_and_registries/shared/components/cleanup_policy_enabled_alert_spec.js b/spec/frontend/packages_and_registries/shared/components/cleanup_policy_enabled_alert_spec.js
deleted file mode 100644
index 269e087f5ac..00000000000
--- a/spec/frontend/packages_and_registries/shared/components/cleanup_policy_enabled_alert_spec.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import { GlAlert } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import component from '~/packages_and_registries/shared/components/cleanup_policy_enabled_alert.vue';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-
-describe('CleanupPolicyEnabledAlert', () => {
- let wrapper;
-
- const defaultProps = {
- projectPath: 'foo',
- cleanupPoliciesSettingsPath: 'label-bar',
- };
-
- const findAlert = () => wrapper.findComponent(GlAlert);
-
- const mountComponent = (props) => {
- wrapper = shallowMount(component, {
- stubs: {
- LocalStorageSync,
- },
- propsData: {
- ...defaultProps,
- ...props,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders', () => {
- mountComponent();
-
- expect(wrapper.element).toMatchSnapshot();
- });
-
- it('when dismissed is not visible', async () => {
- mountComponent();
-
- expect(findAlert().exists()).toBe(true);
- findAlert().vm.$emit('dismiss');
-
- await nextTick();
-
- expect(findAlert().exists()).toBe(false);
- });
-});
diff --git a/spec/frontend/packages_and_registries/shared/components/registry_breadcrumb_spec.js b/spec/frontend/packages_and_registries/shared/components/registry_breadcrumb_spec.js
index 6dfe116c285..15db454ac68 100644
--- a/spec/frontend/packages_and_registries/shared/components/registry_breadcrumb_spec.js
+++ b/spec/frontend/packages_and_registries/shared/components/registry_breadcrumb_spec.js
@@ -1,4 +1,4 @@
-import { mount } from '@vue/test-utils';
+import { mount, RouterLinkStub } from '@vue/test-utils';
import component from '~/packages_and_registries/shared/components/registry_breadcrumb.vue';
@@ -21,6 +21,9 @@ describe('Registry Breadcrumb', () => {
},
},
},
+ stubs: {
+ RouterLink: RouterLinkStub,
+ },
});
};
@@ -30,7 +33,6 @@ describe('Registry Breadcrumb', () => {
afterEach(() => {
wrapper.destroy();
- wrapper = null;
});
describe('when is rootRoute', () => {
@@ -46,7 +48,6 @@ describe('Registry Breadcrumb', () => {
const links = wrapper.findAll('a');
expect(links).toHaveLength(1);
- expect(links.at(0).attributes('href')).toBe('/');
});
it('the link text is calculated by nameGenerator', () => {
@@ -67,7 +68,6 @@ describe('Registry Breadcrumb', () => {
const links = wrapper.findAll('a');
expect(links).toHaveLength(2);
- expect(links.at(0).attributes('href')).toBe('/');
expect(links.at(1).attributes('href')).toBe('#');
});