From 36a59d088eca61b834191dacea009677a96c052f Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 19 May 2022 07:33:21 +0000 Subject: Add latest changes from gitlab-org/gitlab@15-0-stable-ee --- .../components/details_page/details_header_spec.js | 27 ++----- .../components/list_page/cleanup_status_spec.js | 38 ++++++---- .../components/list_page/registry_header_spec.js | 5 +- .../container_registry/explorer/utils_spec.js | 21 ++++++ .../dependency_proxy/app_spec.js | 83 ++++++++-------------- .../components/manifest_row_spec.js | 66 ++++++++++++----- .../dependency_proxy/mock_data.js | 14 +++- .../__snapshots__/package_title_spec.js.snap | 12 ---- .../components/details/package_title_spec.js | 9 +-- .../__snapshots__/package_list_row_spec.js.snap | 39 +++++++--- .../components/list/package_list_row_spec.js | 29 ++++---- .../components/list/packages_list_spec.js | 41 ++++++++++- .../components/list/packages_title_spec.js | 2 +- .../list/tokens/package_type_token_spec.js | 5 +- .../components/dependency_proxy_settings_spec.js | 23 +----- .../group/components/group_settings_app_spec.js | 12 ---- .../settings/components/settings_form_spec.js | 19 +++-- 17 files changed, 239 insertions(+), 206 deletions(-) create mode 100644 spec/frontend/packages_and_registries/container_registry/explorer/utils_spec.js (limited to 'spec/frontend/packages_and_registries') 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 a8d0d15007c..ca666e38291 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 @@ -1,7 +1,7 @@ import { GlDropdownItem, GlIcon, GlDropdown } from '@gitlab/ui'; -import { shallowMount, createLocalVue } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; import VueApollo from 'vue-apollo'; -import { nextTick } from 'vue'; +import Vue, { nextTick } from 'vue'; import { numberToHumanSize } from '~/lib/utils/number_utils'; import { useFakeDate } from 'helpers/fake_date'; import createMockApollo from 'helpers/mock_apollo_helper'; @@ -28,7 +28,6 @@ import { imageTagsCountMock } from '../../mock_data'; describe('Details Header', () => { let wrapper; let apolloProvider; - let localVue; const defaultImage = { name: 'foo', @@ -64,28 +63,18 @@ describe('Details Header', () => { const mountComponent = ({ propsData = { image: defaultImage }, resolver = jest.fn().mockResolvedValue(imageTagsCountMock()), - $apollo = undefined, } = {}) => { - const mocks = {}; + Vue.use(VueApollo); - if ($apollo) { - mocks.$apollo = $apollo; - } else { - localVue = createLocalVue(); - localVue.use(VueApollo); - - const requestHandlers = [[getContainerRepositoryMetadata, resolver]]; - apolloProvider = createMockApollo(requestHandlers); - } + const requestHandlers = [[getContainerRepositoryMetadata, resolver]]; + apolloProvider = createMockApollo(requestHandlers); wrapper = shallowMount(component, { - localVue, apolloProvider, propsData, directives: { GlTooltip: createMockDirective(), }, - mocks, stubs: { TitleArea, GlDropdown, @@ -98,7 +87,6 @@ describe('Details Header', () => { // if we want to mix createMockApollo and manual mocks we need to reset everything wrapper.destroy(); apolloProvider = undefined; - localVue = undefined; wrapper = null; }); @@ -194,10 +182,7 @@ describe('Details Header', () => { describe('metadata items', () => { describe('tags count', () => { it('displays "-- tags" while loading', async () => { - // here we are forced to mock apollo because `waitForMetadataItems` waits - // for two ticks, de facto allowing the promise to resolve, so there is - // no way to catch the component as both rendered and in loading state - mountComponent({ $apollo: { queries: { containerRepository: { loading: true } } } }); + mountComponent(); await waitForMetadataItems(); 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 e8ddad2d8ca..af5723267f4 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 @@ -1,8 +1,8 @@ -import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import { GlLink, GlPopover, GlSprintf } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { helpPagePath } from '~/helpers/help_page_helper'; import CleanupStatus from '~/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue'; import { - CLEANUP_TIMED_OUT_ERROR_MESSAGE, CLEANUP_STATUS_SCHEDULED, CLEANUP_STATUS_ONGOING, CLEANUP_STATUS_UNFINISHED, @@ -17,12 +17,20 @@ describe('cleanup_status', () => { const findMainIcon = () => wrapper.findByTestId('main-icon'); const findExtraInfoIcon = () => wrapper.findByTestId('extra-info'); + const findPopover = () => wrapper.findComponent(GlPopover); + + const cleanupPolicyHelpPage = helpPagePath( + 'user/packages/container_registry/reduce_container_registry_storage.html', + { anchor: 'how-the-cleanup-policy-works' }, + ); const mountComponent = (propsData = { status: SCHEDULED_STATUS }) => { wrapper = shallowMountExtended(CleanupStatus, { propsData, - directives: { - GlTooltip: createMockDirective(), + stubs: { + GlLink, + GlPopover, + GlSprintf, }, }); }; @@ -43,7 +51,7 @@ describe('cleanup_status', () => { mountComponent({ status }); expect(findMainIcon().exists()).toBe(visible); - expect(wrapper.text()).toBe(text); + expect(wrapper.text()).toContain(text); }, ); @@ -53,12 +61,6 @@ describe('cleanup_status', () => { expect(findMainIcon().exists()).toBe(true); }); - - it(`has the orange class when the status is ${UNFINISHED_STATUS}`, () => { - mountComponent({ status: UNFINISHED_STATUS }); - - expect(findMainIcon().classes('gl-text-orange-500')).toBe(true); - }); }); describe('extra info icon', () => { @@ -76,12 +78,18 @@ describe('cleanup_status', () => { }, ); - it(`has a tooltip`, () => { - mountComponent({ status: UNFINISHED_STATUS }); + it(`has a popover with a learn more link and a time frame for the next run`, () => { + jest.spyOn(Date, 'now').mockImplementation(() => new Date('2063-04-04T00:42:00Z').getTime()); - const tooltip = getBinding(findExtraInfoIcon().element, 'gl-tooltip'); + mountComponent({ + status: UNFINISHED_STATUS, + expirationPolicy: { next_run: '2063-04-08T01:44:03Z' }, + }); - expect(tooltip.value.title).toBe(CLEANUP_TIMED_OUT_ERROR_MESSAGE); + expect(findPopover().exists()).toBe(true); + expect(findPopover().text()).toContain('The cleanup will continue within 4 days. Learn more'); + expect(findPopover().findComponent(GlLink).exists()).toBe(true); + expect(findPopover().findComponent(GlLink).attributes('href')).toBe(cleanupPolicyHelpPage); }); }); }); 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 7d09c09d03b..f811468550d 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 @@ -4,7 +4,6 @@ import { nextTick } from 'vue'; import Component from '~/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue'; import { CONTAINER_REGISTRY_TITLE, - LIST_INTRO_TEXT, EXPIRATION_POLICY_DISABLED_TEXT, SET_UP_CLEANUP, } from '~/packages_and_registries/container_registry/explorer/constants'; @@ -135,9 +134,7 @@ describe('registry_header', () => { it('is correctly bound to title_area props', () => { mountComponent({ helpPagePath: 'foo' }); - expect(findTitleArea().props('infoMessages')).toEqual([ - { text: LIST_INTRO_TEXT, link: 'foo' }, - ]); + expect(findTitleArea().props('infoMessages')).toEqual([]); }); }); }); diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/utils_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/utils_spec.js new file mode 100644 index 00000000000..5063759a620 --- /dev/null +++ b/spec/frontend/packages_and_registries/container_registry/explorer/utils_spec.js @@ -0,0 +1,21 @@ +import { timeTilRun } from '~/packages_and_registries/container_registry/explorer/utils'; + +describe('Container registry utilities', () => { + describe('timeTilRun', () => { + beforeEach(() => { + jest.spyOn(Date, 'now').mockImplementation(() => new Date('2063-04-04T00:42:00Z').getTime()); + }); + + it('should return a human readable time', () => { + const result = timeTilRun('2063-04-08T01:44:03Z'); + + expect(result).toBe('4 days'); + }); + + it('should return an empty string with null times', () => { + const result = timeTilRun(null); + + expect(result).toBe(''); + }); + }); +}); 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 dbe9793fb8c..fe4a2c06f1c 100644 --- a/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js +++ b/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js @@ -9,7 +9,7 @@ import { GlSprintf, GlEmptyState, } from '@gitlab/ui'; -import Vue from 'vue'; +import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; import MockAdapter from 'axios-mock-adapter'; import createMockApollo from 'helpers/mock_apollo_helper'; @@ -47,7 +47,6 @@ describe('DependencyProxyApp', () => { const provideDefaults = { groupPath: 'gitlab-org', groupId: dummyGrouptId, - dependencyProxyAvailable: true, noManifestsIllustration: 'noManifestsIllustration', }; @@ -74,7 +73,6 @@ describe('DependencyProxyApp', () => { }); } - const findProxyNotAvailableAlert = () => wrapper.findByTestId('proxy-not-available'); const findClipBoardButton = () => wrapper.findComponent(ClipboardButton); const findFormGroup = () => wrapper.findComponent(GlFormGroup); const findFormInputGroup = () => wrapper.findComponent(GlFormInputGroup); @@ -103,59 +101,22 @@ describe('DependencyProxyApp', () => { mock.restore(); }); - describe('when the dependency proxy is not available', () => { - const createComponentArguments = { - provide: { ...provideDefaults, dependencyProxyAvailable: false }, - }; - - it('renders an info alert', () => { - createComponent(createComponentArguments); - - expect(findProxyNotAvailableAlert().text()).toBe( - DependencyProxyApp.i18n.proxyNotAvailableText, - ); - }); - - it('does not render the main area', () => { - createComponent(createComponentArguments); - - expect(findMainArea().exists()).toBe(false); - }); - - it('does not call the graphql endpoint', async () => { - resolver = jest.fn().mockResolvedValue(proxyDetailsQuery()); - createComponent({ ...createComponentArguments }); - - await waitForPromises(); - - 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', () => { describe('when is loading', () => { - it('renders the skeleton loader', () => { + beforeEach(() => { createComponent(); + }); + it('renders the skeleton loader', () => { expect(findSkeletonLoader().exists()).toBe(true); }); - it('does not show the main section', () => { - createComponent(); - - expect(findMainArea().exists()).toBe(false); + it('does not render a form group with label', () => { + expect(findFormGroup().exists()).toBe(false); }); - it('does not render the info alert', () => { - createComponent(); - - expect(findProxyNotAvailableAlert().exists()).toBe(false); + it('does not show the main section', () => { + expect(findMainArea().exists()).toBe(false); }); }); @@ -166,10 +127,6 @@ describe('DependencyProxyApp', () => { return waitForPromises(); }); - it('does not render the info alert', () => { - expect(findProxyNotAvailableAlert().exists()).toBe(false); - }); - it('renders the main area', () => { expect(findMainArea().exists()).toBe(true); }); @@ -193,7 +150,7 @@ describe('DependencyProxyApp', () => { }); }); - it('from group has a description with proxy count', () => { + it('form group has a description with proxy count', () => { expect(findProxyCountText().text()).toBe('Contains 2 blobs of images (1024 Bytes)'); }); @@ -257,6 +214,28 @@ describe('DependencyProxyApp', () => { }); }); + describe('triggering page event on list', () => { + beforeEach(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', () => { + expect(findFormGroup().attributes('label')).toEqual( + expect.stringMatching(DependencyProxyApp.i18n.proxyImagePrefix), + ); + }); + + it('does not show the main section', () => { + expect(findMainArea().exists()).toBe(false); + }); + }); + it('shows the clear cache dropdown list', () => { expect(findClearCacheDropdownList().exists()).toBe(true); diff --git a/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_row_spec.js b/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_row_spec.js index b7cbd875497..be3236d1f9c 100644 --- a/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_row_spec.js +++ b/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_row_spec.js @@ -3,6 +3,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ListItem from '~/vue_shared/components/registry/list_item.vue'; import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import Component from '~/packages_and_registries/dependency_proxy/components/manifest_row.vue'; +import { MANIFEST_PENDING_DESTRUCTION_STATUS } from '~/packages_and_registries/dependency_proxy/constants'; import { proxyManifests } from 'jest/packages_and_registries/dependency_proxy/mock_data'; describe('Manifest Row', () => { @@ -26,34 +27,63 @@ describe('Manifest Row', () => { const findListItem = () => wrapper.findComponent(ListItem); const findCachedMessages = () => wrapper.findByTestId('cached-message'); const findTimeAgoTooltip = () => wrapper.findComponent(TimeagoTooltip); - - beforeEach(() => { - createComponent(); - }); + const findStatus = () => wrapper.findByTestId('status'); afterEach(() => { wrapper.destroy(); }); - it('has a list item', () => { - expect(findListItem().exists()).toBe(true); - }); + describe('With a manifest on the DEFAULT status', () => { + beforeEach(() => { + createComponent(); + }); - it('displays the name', () => { - expect(wrapper.text()).toContain('alpine'); - }); + it('has a list item', () => { + expect(findListItem().exists()).toBe(true); + }); - it('displays the version', () => { - expect(wrapper.text()).toContain('latest'); - }); + it('displays the name', () => { + expect(wrapper.text()).toContain('alpine'); + }); - it('displays the cached time', () => { - expect(findCachedMessages().text()).toContain('Cached'); + it('displays the version', () => { + expect(wrapper.text()).toContain('latest'); + }); + + it('displays the cached time', () => { + expect(findCachedMessages().text()).toContain('Cached'); + }); + + it('has a time ago tooltip component', () => { + expect(findTimeAgoTooltip().props()).toMatchObject({ + time: defaultProps.manifest.createdAt, + }); + }); + + it('does not have a status element displayed', () => { + expect(findStatus().exists()).toBe(false); + }); }); - it('has a time ago tooltip component', () => { - expect(findTimeAgoTooltip().props()).toMatchObject({ - time: defaultProps.manifest.createdAt, + describe('With a manifest on the PENDING_DESTRUCTION_STATUS', () => { + const pendingDestructionManifest = { + manifest: { + ...defaultProps.manifest, + status: MANIFEST_PENDING_DESTRUCTION_STATUS, + }, + }; + + beforeEach(() => { + createComponent(pendingDestructionManifest); + }); + + it('has a list item', () => { + expect(findListItem().exists()).toBe(true); + }); + + it('has a status element displayed', () => { + expect(findStatus().exists()).toBe(true); + expect(findStatus().text()).toBe('Scheduled for deletion'); }); }); }); diff --git a/spec/frontend/packages_and_registries/dependency_proxy/mock_data.js b/spec/frontend/packages_and_registries/dependency_proxy/mock_data.js index 2aa427bc6af..37c8eb669ba 100644 --- a/spec/frontend/packages_and_registries/dependency_proxy/mock_data.js +++ b/spec/frontend/packages_and_registries/dependency_proxy/mock_data.js @@ -8,8 +8,18 @@ export const proxyData = () => ({ export const proxySettings = (extend = {}) => ({ enabled: true, ...extend }); export const proxyManifests = () => [ - { id: 'proxy-1', createdAt: '2021-09-22T09:45:28Z', imageName: 'alpine:latest' }, - { id: 'proxy-2', createdAt: '2021-09-21T09:45:28Z', imageName: 'alpine:stable' }, + { + id: 'proxy-1', + createdAt: '2021-09-22T09:45:28Z', + imageName: 'alpine:latest', + status: 'DEFAULT', + }, + { + id: 'proxy-2', + createdAt: '2021-09-21T09:45:28Z', + imageName: 'alpine:stable', + status: 'DEFAULT', + }, ]; export const pagination = (extend) => ({ diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/package_title_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/package_title_spec.js.snap index 519014bb9cf..fdddc131412 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/package_title_spec.js.snap +++ b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/package_title_spec.js.snap @@ -29,12 +29,6 @@ exports[`PackageTitle renders with tags 1`] = `
- - @@ -127,12 +121,6 @@ exports[`PackageTitle renders without tags 1`] = `
- - diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js index 5da9cfffaae..d306f7834f0 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js @@ -1,4 +1,4 @@ -import { GlIcon, GlSprintf } from '@gitlab/ui'; +import { GlSprintf } from '@gitlab/ui'; import { GlBreakpointInstance } from '@gitlab/ui/dist/utils'; import { nextTick } from 'vue'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; @@ -46,7 +46,6 @@ describe('PackageTitle', () => { const findPackageRef = () => wrapper.findByTestId('package-ref'); const findPackageTags = () => wrapper.findComponent(PackageTags); const findPackageBadges = () => wrapper.findAllByTestId('tag-badge'); - const findSubHeaderIcon = () => wrapper.findComponent(GlIcon); const findSubHeaderText = () => wrapper.findByTestId('sub-header'); const findSubHeaderTimeAgo = () => wrapper.findComponent(TimeAgoTooltip); @@ -120,12 +119,6 @@ describe('PackageTitle', () => { }); describe('sub-header', () => { - it('has the eye icon', async () => { - await createComponent(); - - expect(findSubHeaderIcon().props('name')).toBe('eye'); - }); - it('has a text showing version', async () => { await createComponent(); diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap index 18a99f70756..031afa62890 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap +++ b/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap @@ -38,8 +38,6 @@ exports[`packages_list_row renders 1`] = ` - -
@@ -98,16 +96,35 @@ exports[`packages_list_row renders 1`] = `
- + text="More actions" + textsronly="true" + variant="default" + > + + Delete package + +
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js index 12a3eaa3873..c16c09b5326 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js @@ -28,12 +28,12 @@ describe('packages_list_row', () => { const packageWithoutTags = { ...packageData(), project: packageProject() }; const packageWithTags = { ...packageWithoutTags, tags: { nodes: packageTags() } }; + const packageCannotDestroy = { ...packageData(), canDestroy: false }; const findPackageTags = () => wrapper.find(PackageTags); const findPackagePath = () => wrapper.find(PackagePath); - const findDeleteButton = () => wrapper.findByTestId('action-delete'); + const findDeleteDropdown = () => wrapper.findByTestId('action-delete'); const findPackageIconAndName = () => wrapper.find(PackageIconAndName); - const findListItem = () => wrapper.findComponent(ListItem); const findPackageLink = () => wrapper.findByTestId('details-link'); const findWarningIcon = () => wrapper.findByTestId('warning-icon'); const findLeftSecondaryInfos = () => wrapper.findByTestId('left-secondary-infos'); @@ -102,22 +102,25 @@ describe('packages_list_row', () => { }); describe('delete button', () => { + it('does not exist when package cannot be destroyed', () => { + mountComponent({ packageEntity: packageCannotDestroy }); + + expect(findDeleteDropdown().exists()).toBe(false); + }); + it('exists and has the correct props', () => { mountComponent({ packageEntity: packageWithoutTags }); - expect(findDeleteButton().exists()).toBe(true); - expect(findDeleteButton().attributes()).toMatchObject({ - icon: 'remove', - category: 'secondary', + expect(findDeleteDropdown().exists()).toBe(true); + expect(findDeleteDropdown().attributes()).toMatchObject({ variant: 'danger', - title: 'Remove package', }); }); it('emits the packageToDelete event when the delete button is clicked', async () => { mountComponent({ packageEntity: packageWithoutTags }); - findDeleteButton().vm.$emit('click'); + findDeleteDropdown().vm.$emit('click'); await nextTick(); expect(wrapper.emitted('packageToDelete')).toBeTruthy(); @@ -130,10 +133,6 @@ describe('packages_list_row', () => { mountComponent({ packageEntity: { ...packageWithoutTags, status: PACKAGE_ERROR_STATUS } }); }); - it('list item has a disabled prop', () => { - expect(findListItem().props('disabled')).toBe(true); - }); - it('details link is disabled', () => { expect(findPackageLink().props('event')).toBe(''); }); @@ -141,14 +140,14 @@ describe('packages_list_row', () => { it('has a warning icon', () => { const icon = findWarningIcon(); const tooltip = getBinding(icon.element, 'gl-tooltip'); - expect(icon.props('icon')).toBe('warning'); + expect(icon.props('name')).toBe('warning'); expect(tooltip.value).toMatchObject({ title: 'Invalid Package: failed metadata extraction', }); }); - it('delete button does not exist', () => { - expect(findDeleteButton().exists()).toBe(false); + it('has a delete dropdown', () => { + expect(findDeleteDropdown().exists()).toBe(true); }); }); diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js index 97978dee909..660f00a2b31 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js @@ -1,4 +1,4 @@ -import { GlKeysetPagination, GlModal, GlSprintf } from '@gitlab/ui'; +import { GlAlert, GlKeysetPagination, GlModal, GlSprintf } from '@gitlab/ui'; import { nextTick } from 'vue'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import PackagesListRow from '~/packages_and_registries/package_registry/components/list/package_list_row.vue'; @@ -21,6 +21,12 @@ describe('packages_list', () => { id: 'gid://gitlab/Packages::Package/112', name: 'second-package', }; + const errorPackage = { + ...packageData(), + id: 'gid://gitlab/Packages::Package/121', + status: 'ERROR', + name: 'error package', + }; const defaultProps = { list: [firstPackage, secondPackage], @@ -40,6 +46,7 @@ describe('packages_list', () => { const findPackageListDeleteModal = () => wrapper.findComponent(GlModalStub); const findEmptySlot = () => wrapper.findComponent(EmptySlotStub); const findPackagesListRow = () => wrapper.findComponent(PackagesListRow); + const findErrorPackageAlert = () => wrapper.findComponent(GlAlert); const mountComponent = (props) => { wrapper = shallowMountExtended(PackagesList, { @@ -109,6 +116,12 @@ describe('packages_list', () => { expect(findPackageListDeleteModal().exists()).toBe(true); }); + + it('does not have an error alert displayed', () => { + mountComponent(); + + expect(findErrorPackageAlert().exists()).toBe(false); + }); }); describe('when the user can destroy the package', () => { @@ -140,6 +153,32 @@ describe('packages_list', () => { }); }); + describe('when an error package is present', () => { + beforeEach(() => { + mountComponent({ list: [firstPackage, errorPackage] }); + + return nextTick(); + }); + + it('should display an alert message', () => { + expect(findErrorPackageAlert().exists()).toBe(true); + expect(findErrorPackageAlert().props('title')).toBe( + 'There was an error publishing a error package package', + ); + expect(findErrorPackageAlert().text()).toBe( + 'There was a timeout and the package was not published. Delete this package and try again.', + ); + }); + + it('should display the deletion modal when clicked on the confirm button', async () => { + findErrorPackageAlert().vm.$emit('primaryAction'); + + await nextTick(); + + expect(findPackageListDeleteModal().text()).toContain(errorPackage.name); + }); + }); + describe('when the list is empty', () => { beforeEach(() => { mountComponent({ list: [] }); diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/packages_title_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/packages_title_spec.js index e992ba12faa..23e5c7330d5 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/list/packages_title_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/list/packages_title_spec.js @@ -37,7 +37,7 @@ describe('PackageTitle', () => { expect(findTitleArea().props()).toMatchObject({ title: PackageTitle.i18n.LIST_TITLE_TEXT, - infoMessages: [{ text: PackageTitle.i18n.LIST_INTRO_TEXT, link: 'foo' }], + infoMessages: [], }); }); }); diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js index 26b2f3b359f..d0c111bae2d 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js @@ -11,7 +11,10 @@ describe('packages_filter', () => { const mountComponent = ({ attrs, listeners } = {}) => { wrapper = shallowMount(component, { - attrs, + attrs: { + cursorPosition: 'start', + ...attrs, + }, listeners, }); }; 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 94f56e5c979..22754d31f93 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,11 +6,7 @@ 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, - DEPENDENCY_PROXY_SETTINGS_DESCRIPTION, - DEPENDENCY_PROXY_DOCS_PATH, -} from '~/packages_and_registries/settings/group/constants'; +import { DEPENDENCY_PROXY_HEADER } 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'; @@ -91,8 +87,6 @@ describe('DependencyProxySettings', () => { const findSettingsBlock = () => wrapper.findComponent(SettingsBlock); const findSettingsTitles = () => wrapper.findComponent(SettingsTitles); - const findDescription = () => wrapper.findByTestId('description'); - const findDescriptionLink = () => wrapper.findByTestId('description-link'); const findEnableProxyToggle = () => wrapper.findByTestId('dependency-proxy-setting-toggle'); const findEnableTtlPoliciesToggle = () => wrapper.findByTestId('dependency-proxy-ttl-policies-toggle'); @@ -126,21 +120,6 @@ describe('DependencyProxySettings', () => { expect(wrapper.text()).toContain(DEPENDENCY_PROXY_HEADER); }); - it('has the correct description text', () => { - mountComponent(); - - expect(findDescription().text()).toMatchInterpolatedText(DEPENDENCY_PROXY_SETTINGS_DESCRIPTION); - }); - - it('has the correct link', () => { - mountComponent(); - - expect(findDescriptionLink().attributes()).toMatchObject({ - href: DEPENDENCY_PROXY_DOCS_PATH, - }); - expect(findDescriptionLink().text()).toBe('Learn more'); - }); - describe('enable toggle', () => { it('exists', () => { mountComponent(); 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 5c30074a6af..635195ff0a4 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 @@ -28,7 +28,6 @@ describe('Group Settings App', () => { const defaultProvide = { defaultExpanded: false, groupPath: 'foo_group_path', - dependencyProxyAvailable: true, }; const mountComponent = ({ @@ -140,15 +139,4 @@ describe('Group Settings App', () => { }); }); }); - - describe('when the dependency proxy is not available', () => { - beforeEach(() => { - mountComponent({ provide: { ...defaultProvide, dependencyProxyAvailable: false } }); - return waitForApolloQueryAndRender(); - }); - - it('the setting block is hidden', () => { - expect(findDependencyProxySettings().exists()).toBe(false); - }); - }); }); diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js index 266f953c3e0..465e6dc73e2 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js @@ -1,6 +1,6 @@ -import { shallowMount, createLocalVue } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; import VueApollo from 'vue-apollo'; -import { nextTick } from 'vue'; +import Vue, { nextTick } from 'vue'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { GlCard, GlLoadingIcon } from 'jest/packages_and_registries/shared/stubs'; @@ -14,8 +14,6 @@ import expirationPolicyQuery from '~/packages_and_registries/settings/project/gr import Tracking from '~/tracking'; import { expirationPolicyPayload, expirationPolicyMutationPayload } from '../mock_data'; -const localVue = createLocalVue(); - describe('Settings Form', () => { let wrapper; let fakeApollo; @@ -59,7 +57,6 @@ describe('Settings Form', () => { data, config, provide = defaultProvidedValues, - mocks, } = {}) => { wrapper = shallowMount(component, { stubs: { @@ -77,7 +74,6 @@ describe('Settings Form', () => { $toast: { show: jest.fn(), }, - ...mocks, }, ...config, }); @@ -88,7 +84,7 @@ describe('Settings Form', () => { mutationResolver, queryPayload = expirationPolicyPayload(), } = {}) => { - localVue.use(VueApollo); + Vue.use(VueApollo); const requestHandlers = [ [updateContainerExpirationPolicyMutation, mutationResolver], @@ -120,7 +116,6 @@ describe('Settings Form', () => { value, }, config: { - localVue, apolloProvider: fakeApollo, }, }); @@ -356,8 +351,8 @@ describe('Settings Form', () => { }); it('parses the error messages', async () => { - const mutate = jest.fn().mockRejectedValue({ - graphQLErrors: [ + const mutate = jest.fn().mockResolvedValue({ + errors: [ { extensions: { problems: [{ path: ['nameRegexKeep'], message: 'baz' }], @@ -365,7 +360,9 @@ describe('Settings Form', () => { }, ], }); - mountComponent({ mocks: { $apollo: { mutate } } }); + mountComponentWithApollo({ + mutationResolver: mutate, + }); await submitForm(); -- cgit v1.2.3