diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-20 14:10:13 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-20 14:10:13 +0300 |
commit | 0ea3fcec397b69815975647f5e2aa5fe944a8486 (patch) | |
tree | 7979381b89d26011bcf9bdc989a40fcc2f1ed4ff /spec/frontend/packages_and_registries | |
parent | 72123183a20411a36d607d70b12d57c484394c8e (diff) |
Add latest changes from gitlab-org/gitlab@15-1-stable-eev15.1.0-rc42
Diffstat (limited to 'spec/frontend/packages_and_registries')
24 files changed, 478 insertions, 269 deletions
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js index 057312828ff..84f01f10f21 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js @@ -10,6 +10,7 @@ import { MISSING_MANIFEST_WARNING_TOOLTIP, NOT_AVAILABLE_TEXT, NOT_AVAILABLE_SIZE, + COPY_IMAGE_PATH_TITLE, } from '~/packages_and_registries/container_registry/explorer/constants/index'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; @@ -150,7 +151,7 @@ describe('tags list row', () => { expect(findClipboardButton().attributes()).toMatchObject({ text: tag.location, - title: tag.location, + title: COPY_IMAGE_PATH_TITLE, }); }); 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 af5723267f4..0581a40b6a2 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,4 +1,4 @@ -import { GlLink, GlPopover, GlSprintf } from '@gitlab/ui'; +import { GlIcon, 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'; @@ -16,6 +16,7 @@ describe('cleanup_status', () => { let wrapper; const findMainIcon = () => wrapper.findByTestId('main-icon'); + const findMainIconName = () => wrapper.findByTestId('main-icon').find(GlIcon); const findExtraInfoIcon = () => wrapper.findByTestId('extra-info'); const findPopover = () => wrapper.findComponent(GlPopover); @@ -61,6 +62,23 @@ describe('cleanup_status', () => { expect(findMainIcon().exists()).toBe(true); }); + + it.each` + status | visible | iconName + ${UNFINISHED_STATUS} | ${true} | ${'expire'} + ${SCHEDULED_STATUS} | ${true} | ${'clock'} + ${ONGOING_STATUS} | ${true} | ${'clock'} + ${UNSCHEDULED_STATUS} | ${false} | ${''} + `('matches "$iconName" when the status is "$status"', ({ status, visible, iconName }) => { + mountComponent({ status }); + + expect(findMainIcon().exists()).toBe(visible); + if (visible) { + const actualIcon = findMainIconName(); + expect(actualIcon.exists()).toBe(true); + expect(actualIcon.props('name')).toBe(iconName); + } + }); }); describe('extra info icon', () => { 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 690d827ec67..979e1500d7d 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 @@ -13,6 +13,7 @@ import { IMAGE_MIGRATING_STATE, SCHEDULED_STATUS, ROOT_IMAGE_TEXT, + COPY_IMAGE_PATH_TITLE, } from '~/packages_and_registries/container_registry/explorer/constants'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ListItem from '~/vue_shared/components/registry/list_item.vue'; @@ -106,7 +107,7 @@ describe('Image List Row', () => { const button = findClipboardButton(); expect(button.exists()).toBe(true); expect(button.props('text')).toBe(item.location); - expect(button.props('title')).toBe(item.location); + expect(button.props('title')).toBe(COPY_IMAGE_PATH_TITLE); }); describe('cleanup status component', () => { 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 f811468550d..a006de9f00c 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 @@ -93,7 +93,7 @@ describe('registry_header', () => { expect(text.exists()).toBe(true); expect(text.props()).toMatchObject({ text: EXPIRATION_POLICY_DISABLED_TEXT, - icon: 'expire', + icon: 'clock', size: 'xl', }); }); diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_files_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_files_spec.js index 6b6c33b7561..95de2f0bb0b 100644 --- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_files_spec.js +++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_files_spec.js @@ -206,19 +206,19 @@ describe('Package Files', () => { it('toggles the details row', async () => { createComponent(); - expect(findFirstToggleDetailsButton().props('icon')).toBe('angle-down'); + expect(findFirstToggleDetailsButton().props('icon')).toBe('chevron-lg-down'); findFirstToggleDetailsButton().vm.$emit('click'); await nextTick(); expect(findFirstRowShaComponent('sha-256').exists()).toBe(true); - expect(findFirstToggleDetailsButton().props('icon')).toBe('angle-up'); + expect(findFirstToggleDetailsButton().props('icon')).toBe('chevron-lg-up'); findFirstToggleDetailsButton().vm.$emit('click'); await nextTick(); expect(findFirstRowShaComponent('sha-256').exists()).toBe(false); - expect(findFirstToggleDetailsButton().props('icon')).toBe('angle-down'); + expect(findFirstToggleDetailsButton().props('icon')).toBe('chevron-lg-down'); }); }); diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_search_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_search_spec.js index e5230417c78..a086c20a5e7 100644 --- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_search_spec.js +++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_search_spec.js @@ -65,7 +65,7 @@ describe('Infrastructure Search', () => { expect(findRegistrySearch().exists()).toBe(true); expect(findRegistrySearch().props()).toMatchObject({ - filter: store.state.filter, + filters: store.state.filter, sorting: store.state.sorting, tokens: [], sortableFields: sortableFields(), @@ -80,7 +80,7 @@ describe('Infrastructure Search', () => { mountComponent(isGroupPage); expect(findRegistrySearch().props()).toMatchObject({ - filter: store.state.filter, + filters: store.state.filter, sorting: store.state.sorting, tokens: [], sortableFields: fields, diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js index 7a71a1cea0f..4f3d780b149 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js @@ -1,4 +1,9 @@ +import Vue, { nextTick } from 'vue'; +import VueApollo from 'vue-apollo'; +import { GlAlert } from '@gitlab/ui'; +import * as Sentry from '@sentry/browser'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import createMockApollo from 'helpers/mock_apollo_helper'; import { conanMetadata, mavenMetadata, @@ -6,9 +11,11 @@ import { packageData, composerMetadata, pypiMetadata, + packageMetadataQuery, } from 'jest/packages_and_registries/package_registry/mock_data'; import component from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue'; import { + FETCH_PACKAGE_METADATA_ERROR_MESSAGE, PACKAGE_TYPE_NUGET, PACKAGE_TYPE_CONAN, PACKAGE_TYPE_MAVEN, @@ -16,6 +23,9 @@ import { PACKAGE_TYPE_COMPOSER, PACKAGE_TYPE_PYPI, } from '~/packages_and_registries/package_registry/constants'; +import AdditionalMetadataLoader from '~/packages_and_registries/package_registry/components/details/additional_metadata_loader.vue'; +import waitForPromises from 'helpers/wait_for_promises'; +import getPackageMetadata from '~/packages_and_registries/package_registry/graphql/queries/get_package_metadata.query.graphql'; const mavenPackage = { packageType: PACKAGE_TYPE_MAVEN, metadata: mavenMetadata() }; const conanPackage = { packageType: PACKAGE_TYPE_CONAN, metadata: conanMetadata() }; @@ -24,16 +34,26 @@ const composerPackage = { packageType: PACKAGE_TYPE_COMPOSER, metadata: composer const pypiPackage = { packageType: PACKAGE_TYPE_PYPI, metadata: pypiMetadata() }; const npmPackage = { packageType: PACKAGE_TYPE_NPM, metadata: {} }; -describe('Package Additional Metadata', () => { +Vue.use(VueApollo); + +describe('Package Additional metadata', () => { let wrapper; + let apolloProvider; + const defaultProps = { - packageEntity: { - ...packageData(mavenPackage), - }, + packageId: packageData().id, + packageType: PACKAGE_TYPE_MAVEN, }; - const mountComponent = (props) => { + const mountComponent = ({ + props = {}, + resolver = jest.fn().mockResolvedValue(packageMetadataQuery(mavenPackage)), + } = {}) => { + const requestHandlers = [[getPackageMetadata, resolver]]; + apolloProvider = createMockApollo(requestHandlers); + wrapper = shallowMountExtended(component, { + apolloProvider, propsData: { ...defaultProps, ...props }, stubs: { component: { template: '<div data-testid="component-is"></div>' }, @@ -41,6 +61,10 @@ describe('Package Additional Metadata', () => { }); }; + beforeEach(() => { + jest.spyOn(Sentry, 'captureException').mockImplementation(); + }); + afterEach(() => { wrapper.destroy(); wrapper = null; @@ -49,6 +73,22 @@ describe('Package Additional Metadata', () => { const findTitle = () => wrapper.findByTestId('title'); const findMainArea = () => wrapper.findByTestId('main'); const findComponentIs = () => wrapper.findByTestId('component-is'); + const findAdditionalMetadataLoader = () => wrapper.findComponent(AdditionalMetadataLoader); + const findPackageMetadataAlert = () => wrapper.findComponent(GlAlert); + + it('renders the loading container when loading', () => { + mountComponent(); + + expect(findAdditionalMetadataLoader().exists()).toBe(true); + }); + + it('does not render the loading container once resolved', async () => { + mountComponent(); + await waitForPromises(); + + expect(findAdditionalMetadataLoader().exists()).toBe(false); + expect(Sentry.captureException).not.toHaveBeenCalled(); + }); it('has the correct title', () => { mountComponent(); @@ -56,7 +96,25 @@ describe('Package Additional Metadata', () => { const title = findTitle(); expect(title.exists()).toBe(true); - expect(title.text()).toBe('Additional Metadata'); + expect(title.text()).toMatchInterpolatedText(component.i18n.componentTitle); + }); + + it('does not render gl-alert', () => { + mountComponent(); + + expect(findPackageMetadataAlert().exists()).toBe(false); + }); + + it('renders gl-alert if load fails', async () => { + mountComponent({ resolver: jest.fn().mockRejectedValue() }); + + await waitForPromises(); + + expect(findPackageMetadataAlert().exists()).toBe(true); + expect(findPackageMetadataAlert().text()).toMatchInterpolatedText( + FETCH_PACKAGE_METADATA_ERROR_MESSAGE, + ); + expect(Sentry.captureException).toHaveBeenCalled(); }); it.each` @@ -68,16 +126,22 @@ describe('Package Additional Metadata', () => { ${pypiPackage} | ${true} | ${PACKAGE_TYPE_PYPI} ${npmPackage} | ${false} | ${PACKAGE_TYPE_NPM} `( - `It is $visible that the component is visible when the package is $packageType`, - ({ packageEntity, visible }) => { - mountComponent({ packageEntity }); + `component visibility is $visible when the package is $packageType`, + async ({ packageEntity, visible, packageType }) => { + const resolved = packageMetadataQuery(packageType); + const resolver = jest.fn().mockResolvedValue(resolved); + + mountComponent({ props: { packageType }, resolver }); + + await waitForPromises(); + await nextTick(); expect(findTitle().exists()).toBe(visible); expect(findMainArea().exists()).toBe(visible); expect(findComponentIs().exists()).toBe(visible); if (visible) { - expect(findComponentIs().props('packageEntity')).toEqual(packageEntity); + expect(findComponentIs().props('packageMetadata')).toEqual(packageEntity.metadata); } }, ); diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/composer_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/composer_spec.js index e744680cb9a..bb6846d354f 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/composer_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/composer_spec.js @@ -1,22 +1,16 @@ import { GlSprintf } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import { - packageData, - composerMetadata, -} from 'jest/packages_and_registries/package_registry/mock_data'; +import { composerMetadata } from 'jest/packages_and_registries/package_registry/mock_data'; import component from '~/packages_and_registries/package_registry/components/details/metadata/composer.vue'; -import { PACKAGE_TYPE_COMPOSER } from '~/packages_and_registries/package_registry/constants'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; -const composerPackage = { packageType: PACKAGE_TYPE_COMPOSER, metadata: composerMetadata() }; - describe('Composer Metadata', () => { let wrapper; const mountComponent = () => { wrapper = shallowMountExtended(component, { - propsData: { packageEntity: packageData(composerPackage) }, + propsData: { packageMetadata: composerMetadata() }, stubs: { DetailsRow, GlSprintf, diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/conan_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/conan_spec.js index 46593047f1f..e7e47401aa1 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/conan_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/conan_spec.js @@ -1,22 +1,16 @@ import { GlSprintf } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import { - conanMetadata, - packageData, -} from 'jest/packages_and_registries/package_registry/mock_data'; +import { conanMetadata } from 'jest/packages_and_registries/package_registry/mock_data'; import component from '~/packages_and_registries/package_registry/components/details/metadata/conan.vue'; -import { PACKAGE_TYPE_CONAN } from '~/packages_and_registries/package_registry/constants'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; -const conanPackage = { packageType: PACKAGE_TYPE_CONAN, metadata: conanMetadata() }; - describe('Conan Metadata', () => { let wrapper; const mountComponent = () => { wrapper = shallowMountExtended(component, { propsData: { - packageEntity: packageData(conanPackage), + packageMetadata: conanMetadata(), }, stubs: { DetailsRow, diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/maven_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/maven_spec.js index bc54cf1cb98..8680d983042 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/maven_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/maven_spec.js @@ -1,24 +1,16 @@ import { GlSprintf } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import { - mavenMetadata, - packageData, -} from 'jest/packages_and_registries/package_registry/mock_data'; +import { mavenMetadata } from 'jest/packages_and_registries/package_registry/mock_data'; import component from '~/packages_and_registries/package_registry/components/details/metadata/maven.vue'; -import { PACKAGE_TYPE_MAVEN } from '~/packages_and_registries/package_registry/constants'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; -const mavenPackage = { packageType: PACKAGE_TYPE_MAVEN, metadata: mavenMetadata() }; - describe('Maven Metadata', () => { let wrapper; const mountComponent = () => { wrapper = shallowMountExtended(component, { propsData: { - packageEntity: { - ...packageData(mavenPackage), - }, + packageMetadata: mavenMetadata(), }, stubs: { DetailsRow, diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/nuget_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/nuget_spec.js index f759fe7a81c..af3692023f0 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/nuget_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/nuget_spec.js @@ -1,25 +1,17 @@ import { GlLink, GlSprintf } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import { - nugetMetadata, - packageData, -} from 'jest/packages_and_registries/package_registry/mock_data'; +import { nugetMetadata } from 'jest/packages_and_registries/package_registry/mock_data'; import component from '~/packages_and_registries/package_registry/components/details/metadata/nuget.vue'; -import { PACKAGE_TYPE_NUGET } from '~/packages_and_registries/package_registry/constants'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; describe('Nuget Metadata', () => { - let nugetPackage = { packageType: PACKAGE_TYPE_NUGET, metadata: nugetMetadata() }; + let nugetPackageMetadata = { ...nugetMetadata() }; let wrapper; - const mountComponent = () => { + const mountComponent = (props) => { wrapper = shallowMountExtended(component, { - propsData: { - packageEntity: { - ...packageData(nugetPackage), - }, - }, + propsData: { ...props }, stubs: { DetailsRow, GlSprintf, @@ -37,7 +29,7 @@ describe('Nuget Metadata', () => { const findElementLink = (container) => container.findComponent(GlLink); beforeEach(() => { - mountComponent({ packageEntity: nugetPackage }); + mountComponent({ packageMetadata: nugetPackageMetadata }); }); it.each` @@ -49,14 +41,14 @@ describe('Nuget Metadata', () => { expect(element.exists()).toBe(true); expect(element.text()).toBe(text); expect(element.props('icon')).toBe(icon); - expect(findElementLink(element).attributes('href')).toBe(nugetPackage.metadata[link]); + expect(findElementLink(element).attributes('href')).toBe(nugetPackageMetadata[link]); }); describe('without source', () => { beforeAll(() => { - nugetPackage = { - packageType: PACKAGE_TYPE_NUGET, - metadata: { iconUrl: 'iconUrl', licenseUrl: 'licenseUrl' }, + nugetPackageMetadata = { + iconUrl: 'iconUrl', + licenseUrl: 'licenseUrl', }; }); @@ -67,9 +59,9 @@ describe('Nuget Metadata', () => { describe('without license', () => { beforeAll(() => { - nugetPackage = { - packageType: PACKAGE_TYPE_NUGET, - metadata: { iconUrl: 'iconUrl', projectUrl: 'projectUrl' }, + nugetPackageMetadata = { + iconUrl: 'iconUrl', + projectUrl: 'projectUrl', }; }); diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/pypi_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/pypi_spec.js index c4481c3f20b..d7c6ea8379d 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/pypi_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/pypi_spec.js @@ -1,22 +1,17 @@ import { GlSprintf } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import { packageData, pypiMetadata } from 'jest/packages_and_registries/package_registry/mock_data'; +import { pypiMetadata } from 'jest/packages_and_registries/package_registry/mock_data'; import component from '~/packages_and_registries/package_registry/components/details/metadata/pypi.vue'; -import { PACKAGE_TYPE_PYPI } from '~/packages_and_registries/package_registry/constants'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; -const pypiPackage = { packageType: PACKAGE_TYPE_PYPI, metadata: pypiMetadata() }; - describe('Package Additional Metadata', () => { let wrapper; const mountComponent = () => { wrapper = shallowMountExtended(component, { propsData: { - packageEntity: { - ...packageData(pypiPackage), - }, + packageMetadata: pypiMetadata(), }, stubs: { DetailsRow, diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js index f8a4ba8f3bc..0447ead0830 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js @@ -34,7 +34,7 @@ describe('Package Files', () => { }, stubs: { ...stubChildren(PackageFiles), - GlTable: false, + GlTableLite: false, }, }); }; @@ -219,19 +219,19 @@ describe('Package Files', () => { it('toggles the details row', async () => { createComponent(); - expect(findFirstToggleDetailsButton().props('icon')).toBe('angle-down'); + expect(findFirstToggleDetailsButton().props('icon')).toBe('chevron-down'); findFirstToggleDetailsButton().vm.$emit('click'); await nextTick(); expect(findFirstRowShaComponent('sha-256').exists()).toBe(true); - expect(findFirstToggleDetailsButton().props('icon')).toBe('angle-up'); + expect(findFirstToggleDetailsButton().props('icon')).toBe('chevron-up'); findFirstToggleDetailsButton().vm.$emit('click'); await nextTick(); expect(findFirstRowShaComponent('sha-256').exists()).toBe(false); - expect(findFirstToggleDetailsButton().props('icon')).toBe('angle-down'); + expect(findFirstToggleDetailsButton().props('icon')).toBe('chevron-down'); }); }); diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/package_history_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/package_history_spec.js index 57b8be40a7c..f4e6d43812d 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/package_history_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/package_history_spec.js @@ -1,17 +1,29 @@ -import { GlLink, GlSprintf } from '@gitlab/ui'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui'; +import * as Sentry from '@sentry/browser'; import { stubComponent } from 'helpers/stub_component'; +import createMockApollo from 'helpers/mock_apollo_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { packageData, packagePipelines, + packagePipelinesQuery, } from 'jest/packages_and_registries/package_registry/mock_data'; import { HISTORY_PIPELINES_LIMIT } from '~/packages_and_registries/shared/constants'; import component from '~/packages_and_registries/package_registry/components/details/package_history.vue'; +import PackageHistoryLoader from '~/packages_and_registries/package_registry/components/details/package_history_loader.vue'; import HistoryItem from '~/vue_shared/components/registry/history_item.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import waitForPromises from 'helpers/wait_for_promises'; +import getPackagePipelines from '~/packages_and_registries/package_registry/graphql/queries/get_package_pipelines.query.graphql'; + +Vue.use(VueApollo); describe('Package History', () => { let wrapper; + let apolloProvider; + const defaultProps = { projectName: 'baz project', packageEntity: { ...packageData() }, @@ -22,8 +34,15 @@ describe('Package History', () => { const createPipelines = (amount) => [...Array(amount)].map((x, index) => packagePipelines({ id: index + 1 })[0]); - const mountComponent = (props) => { + const mountComponent = ({ + props = {}, + resolver = jest.fn().mockResolvedValue(packagePipelinesQuery()), + } = {}) => { + const requestHandlers = [[getPackagePipelines, resolver]]; + apolloProvider = createMockApollo(requestHandlers); + wrapper = shallowMountExtended(component, { + apolloProvider, propsData: { ...defaultProps, ...props }, stubs: { HistoryItem: stubComponent(HistoryItem, { @@ -34,18 +53,40 @@ describe('Package History', () => { }); }; + beforeEach(() => { + jest.spyOn(Sentry, 'captureException').mockImplementation(); + }); + afterEach(() => { wrapper.destroy(); + wrapper = null; }); + const findPackageHistoryLoader = () => wrapper.findComponent(PackageHistoryLoader); const findHistoryElement = (testId) => wrapper.findByTestId(testId); const findElementLink = (container) => container.findComponent(GlLink); const findElementTimeAgo = (container) => container.findComponent(TimeAgoTooltip); + const findPackageHistoryAlert = () => wrapper.findComponent(GlAlert); const findTitle = () => wrapper.findByTestId('title'); const findTimeline = () => wrapper.findByTestId('timeline'); - it('has the correct title', () => { + it('renders the loading container when loading', () => { + mountComponent(); + + expect(findPackageHistoryLoader().exists()).toBe(true); + }); + + it('does not render the loading container once resolved', async () => { + mountComponent(); + await waitForPromises(); + + expect(findPackageHistoryLoader().exists()).toBe(false); + expect(Sentry.captureException).not.toHaveBeenCalled(); + }); + + it('has the correct title', async () => { mountComponent(); + await waitForPromises(); const title = findTitle(); @@ -53,8 +94,9 @@ describe('Package History', () => { expect(title.text()).toBe('History'); }); - it('has a timeline container', () => { + it('has a timeline container', async () => { mountComponent(); + await waitForPromises(); const title = findTimeline(); @@ -64,6 +106,24 @@ describe('Package History', () => { ); }); + it('does not render gl-alert', () => { + mountComponent(); + + expect(findPackageHistoryAlert().exists()).toBe(false); + }); + + it('renders gl-alert if load fails', async () => { + mountComponent({ resolver: jest.fn().mockRejectedValue() }); + + await waitForPromises(); + + expect(findPackageHistoryAlert().exists()).toBe(true); + expect(findPackageHistoryAlert().text()).toEqual( + 'Something went wrong while fetching the package history.', + ); + expect(Sentry.captureException).toHaveBeenCalled(); + }); + describe.each` name | amount | icon | text | timeAgoTooltip | link ${'created-on'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'clock'} | ${'@gitlab-org/package-15 version 1.0.0 was first created'} | ${packageData().createdAt} | ${null} @@ -78,11 +138,21 @@ describe('Package History', () => { ({ name, icon, text, timeAgoTooltip, link, amount }) => { let element; - beforeEach(() => { - const packageEntity = { ...packageData(), pipelines: { nodes: createPipelines(amount) } }; + beforeEach(async () => { + const packageEntity = { ...packageData() }; + const pipelinesResolver = jest + .fn() + .mockResolvedValue(packagePipelinesQuery(createPipelines(amount))); + mountComponent({ - packageEntity, + props: { + packageEntity, + }, + resolver: pipelinesResolver, }); + + await waitForPromises(); + element = findHistoryElement(name); }); 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 3670cfca8ea..19505618ff7 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 @@ -134,7 +134,7 @@ describe('Package Search', () => { await nextTick(); - expect(findRegistrySearch().props('filter')).toEqual(['foo']); + expect(findRegistrySearch().props('filters')).toEqual(['foo']); }); it('on filter:submit emits update event', async () => { @@ -175,7 +175,7 @@ describe('Package Search', () => { expect(getQueryParams).toHaveBeenCalled(); expect(findRegistrySearch().props()).toMatchObject({ - filter: defaultQueryParamsMock.filters, + filters: defaultQueryParamsMock.filters, sorting: defaultQueryParamsMock.sorting, }); }); diff --git a/spec/frontend/packages_and_registries/package_registry/mock_data.js b/spec/frontend/packages_and_registries/package_registry/mock_data.js index 0a4747fc9ec..d40feee582f 100644 --- a/spec/frontend/packages_and_registries/package_registry/mock_data.js +++ b/spec/frontend/packages_and_registries/package_registry/mock_data.js @@ -148,6 +148,8 @@ export const conanMetadata = () => ({ recipePath: 'package-8/1.0.0/gitlab-org+gitlab-test/stable', }); +const conanMetadataQuery = () => ({ ...conanMetadata(), __typename: 'ConanMetadata' }); + export const composerMetadata = () => ({ targetSha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0', composerJson: { @@ -156,23 +158,45 @@ export const composerMetadata = () => ({ }, }); +const composerMetadataQuery = () => ({ + ...composerMetadata(), + __typename: 'ComposerMetadata', +}); + export const pypiMetadata = () => ({ + id: 'pypi-1', requiredPython: '1.0.0', }); +const pypiMetadataQuery = () => ({ ...pypiMetadata(), __typename: 'PypiMetadata' }); + export const mavenMetadata = () => ({ + id: 'maven-1', appName: 'appName', appGroup: 'appGroup', appVersion: 'appVersion', path: 'path', }); +const mavenMetadataQuery = () => ({ ...mavenMetadata(), __typename: 'MavenMetadata' }); + export const nugetMetadata = () => ({ + id: 'nuget-1', iconUrl: 'iconUrl', licenseUrl: 'licenseUrl', projectUrl: 'projectUrl', }); +const nugetMetadataQuery = () => ({ ...nugetMetadata(), __typename: 'NugetMetadata' }); + +const packageTypeMetadataQueryMapping = { + CONAN: conanMetadataQuery, + COMPOSER: composerMetadataQuery, + PYPI: pypiMetadataQuery, + MAVEN: mavenMetadataQuery, + NUGET: nugetMetadataQuery, +}; + export const pagination = (extend) => ({ endCursor: 'eyJpZCI6IjIwNSIsIm5hbWUiOiJteS9jb21wYW55L2FwcC9teS1hcHAifQ', hasNextPage: true, @@ -223,6 +247,19 @@ export const packageDetailsQuery = (extendPackage) => ({ }, }); +export const packagePipelinesQuery = (pipelines = packagePipelines()) => ({ + data: { + package: { + id: 'gid://gitlab/Packages::Package/111', + pipelines: { + nodes: pipelines, + __typename: 'PipelineConnection', + }, + __typename: 'PackageDetailsType', + }, + }, +}); + export const emptyPackageDetailsQuery = () => ({ data: { package: { @@ -231,6 +268,21 @@ export const emptyPackageDetailsQuery = () => ({ }, }); +export const packageMetadataQuery = (packageType) => { + return { + data: { + package: { + id: 'gid://gitlab/Packages::Package/111', + packageType, + metadata: { + ...(packageTypeMetadataQueryMapping[packageType]?.() ?? {}), + }, + __typename: 'PackageDetailsType', + }, + }, + }; +}; + export const packageDestroyMutation = () => ({ data: { destroyPackage: { diff --git a/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js index a7e31d42c9e..3cadb001c58 100644 --- a/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js @@ -23,6 +23,10 @@ import { DELETE_PACKAGE_FILE_SUCCESS_MESSAGE, DELETE_PACKAGE_FILE_ERROR_MESSAGE, PACKAGE_TYPE_NUGET, + PACKAGE_TYPE_MAVEN, + PACKAGE_TYPE_CONAN, + PACKAGE_TYPE_PYPI, + PACKAGE_TYPE_NPM, } from '~/packages_and_registries/package_registry/constants'; import destroyPackageFileMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package_file.mutation.graphql'; @@ -160,15 +164,38 @@ describe('PackagesApp', () => { }); }); - it('renders additional metadata and has the right props', async () => { - createComponent(); + describe('additional metadata', () => { + it.each` + packageType | visible + ${PACKAGE_TYPE_MAVEN} | ${true} + ${PACKAGE_TYPE_CONAN} | ${true} + ${PACKAGE_TYPE_NUGET} | ${true} + ${PACKAGE_TYPE_COMPOSER} | ${true} + ${PACKAGE_TYPE_PYPI} | ${true} + ${PACKAGE_TYPE_NPM} | ${false} + `( + `It is $visible that the component is visible when the package is $packageType`, + async ({ packageType, visible }) => { + createComponent({ + resolver: jest.fn().mockResolvedValue( + packageDetailsQuery({ + packageType, + }), + ), + }); - await waitForPromises(); + await waitForPromises(); - expect(findAdditionalMetadata().exists()).toBe(true); - expect(findAdditionalMetadata().props()).toMatchObject({ - packageEntity: expect.objectContaining(packageWithoutTypename), - }); + expect(findAdditionalMetadata().exists()).toBe(visible); + + if (visible) { + expect(findAdditionalMetadata().props()).toMatchObject({ + packageId: packageWithoutTypename.id, + packageType, + }); + } + }, + ); }); it('renders installation commands and has the right props', async () => { 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 22754d31f93..e60989b0949 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 @@ -134,12 +134,6 @@ describe('DependencyProxySettings', () => { mountComponent(); }); - it('has the help prop correctly set', () => { - expect(findEnableProxyToggle().props()).toMatchObject({ - help: component.i18n.enabledProxyHelpText, - }); - }); - it('has help text with a link', () => { expect(findEnableProxyToggle().text()).toContain( 'To see the image prefix and what is in the cache, visit the Dependency Proxy', @@ -157,12 +151,6 @@ describe('DependencyProxySettings', () => { }); }); - it('has the help prop set to empty', () => { - expect(findEnableProxyToggle().props()).toMatchObject({ - help: '', - }); - }); - it('the help text is not visible', () => { expect(findToggleHelpLink().exists()).toBe(false); }); diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/settings_form_spec.js.snap b/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap index 841a9bf8290..faa313118f3 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/settings_form_spec.js.snap +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Settings Form Cadence matches snapshot 1`] = ` +exports[`Container Expiration Policy Settings Form Cadence matches snapshot 1`] = ` <expiration-dropdown-stub class="gl-mr-7 gl-mb-0!" data-testid="cadence-dropdown" @@ -11,7 +11,7 @@ exports[`Settings Form Cadence matches snapshot 1`] = ` /> `; -exports[`Settings Form Enable matches snapshot 1`] = ` +exports[`Container Expiration Policy Settings Form Enable matches snapshot 1`] = ` <expiration-toggle-stub class="gl-mb-0!" data-testid="enable-toggle" @@ -19,7 +19,7 @@ exports[`Settings Form Enable matches snapshot 1`] = ` /> `; -exports[`Settings Form Keep N matches snapshot 1`] = ` +exports[`Container Expiration Policy Settings Form Keep N matches snapshot 1`] = ` <expiration-dropdown-stub data-testid="keep-n-dropdown" formoptions="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" @@ -29,7 +29,7 @@ exports[`Settings Form Keep N matches snapshot 1`] = ` /> `; -exports[`Settings Form Keep Regex matches snapshot 1`] = ` +exports[`Container Expiration Policy Settings Form Keep Regex matches snapshot 1`] = ` <expiration-input-stub data-testid="keep-regex-input" description="Tags with names that match this regex pattern are kept. %{linkStart}View regex examples.%{linkEnd}" @@ -41,7 +41,7 @@ exports[`Settings Form Keep Regex matches snapshot 1`] = ` /> `; -exports[`Settings Form OlderThan matches snapshot 1`] = ` +exports[`Container Expiration Policy Settings Form OlderThan matches snapshot 1`] = ` <expiration-dropdown-stub data-testid="older-than-dropdown" formoptions="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" @@ -51,7 +51,7 @@ exports[`Settings Form OlderThan matches snapshot 1`] = ` /> `; -exports[`Settings Form Remove regex matches snapshot 1`] = ` +exports[`Container Expiration Policy Settings Form Remove regex matches snapshot 1`] = ` <expiration-input-stub data-testid="remove-regex-input" description="Tags with names that match this regex pattern are removed. %{linkStart}View regex examples.%{linkEnd}" 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/container_expiration_policy_form_spec.js index 465e6dc73e2..ca44e77e694 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/container_expiration_policy_form_spec.js @@ -4,7 +4,7 @@ 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'; -import component from '~/packages_and_registries/settings/project/components/settings_form.vue'; +import component from '~/packages_and_registries/settings/project/components/container_expiration_policy_form.vue'; import { UPDATE_SETTINGS_ERROR_MESSAGE, UPDATE_SETTINGS_SUCCESS_MESSAGE, @@ -14,7 +14,7 @@ import expirationPolicyQuery from '~/packages_and_registries/settings/project/gr import Tracking from '~/tracking'; import { expirationPolicyPayload, expirationPolicyMutationPayload } from '../mock_data'; -describe('Settings Form', () => { +describe('Container Expiration Policy Settings Form', () => { let wrapper; let fakeApollo; diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js new file mode 100644 index 00000000000..aa3506771fa --- /dev/null +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js @@ -0,0 +1,167 @@ +import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import component from '~/packages_and_registries/settings/project/components/container_expiration_policy.vue'; +import ContainerExpirationPolicyForm from '~/packages_and_registries/settings/project/components/container_expiration_policy_form.vue'; +import { + FETCH_SETTINGS_ERROR_MESSAGE, + UNAVAILABLE_FEATURE_INTRO_TEXT, + 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 SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; + +import { + expirationPolicyPayload, + emptyExpirationPolicyPayload, + containerExpirationPolicyData, +} from '../mock_data'; + +describe('Container expiration policy project settings', () => { + let wrapper; + let fakeApollo; + + const defaultProvidedValues = { + projectPath: 'path', + isAdmin: false, + adminSettingsPath: 'settingsPath', + enableHistoricEntries: false, + helpPagePath: 'helpPagePath', + showCleanupPolicyLink: false, + }; + + const findFormComponent = () => wrapper.find(ContainerExpirationPolicyForm); + const findAlert = () => wrapper.find(GlAlert); + const findSettingsBlock = () => wrapper.find(SettingsBlock); + + const mountComponent = (provide = defaultProvidedValues, config) => { + wrapper = shallowMount(component, { + stubs: { + GlSprintf, + SettingsBlock, + }, + mocks: { + $toast: { + show: jest.fn(), + }, + }, + provide, + ...config, + }); + }; + + const mountComponentWithApollo = ({ provide = defaultProvidedValues, resolver } = {}) => { + Vue.use(VueApollo); + + const requestHandlers = [[expirationPolicyQuery, resolver]]; + + fakeApollo = createMockApollo(requestHandlers); + mountComponent(provide, { + apolloProvider: fakeApollo, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('isEdited status', () => { + it.each` + description | apiResponse | workingCopy | result + ${'empty response and no changes from user'} | ${emptyExpirationPolicyPayload()} | ${{}} | ${false} + ${'empty response and changes from user'} | ${emptyExpirationPolicyPayload()} | ${{ enabled: true }} | ${true} + ${'response and no changes'} | ${expirationPolicyPayload()} | ${containerExpirationPolicyData()} | ${false} + ${'response and changes'} | ${expirationPolicyPayload()} | ${{ ...containerExpirationPolicyData(), nameRegex: '12345' }} | ${true} + ${'response and empty'} | ${expirationPolicyPayload()} | ${{}} | ${true} + `('$description', async ({ apiResponse, workingCopy, result }) => { + mountComponentWithApollo({ + provide: { ...defaultProvidedValues, enableHistoricEntries: true }, + resolver: jest.fn().mockResolvedValue(apiResponse), + }); + await waitForPromises(); + + findFormComponent().vm.$emit('input', workingCopy); + + await waitForPromises(); + + expect(findFormComponent().props('isEdited')).toBe(result); + }); + }); + + it('renders the setting form', async () => { + mountComponentWithApollo({ + resolver: jest.fn().mockResolvedValue(expirationPolicyPayload()), + }); + await waitForPromises(); + + expect(findFormComponent().exists()).toBe(true); + expect(findSettingsBlock().props('collapsible')).toBe(false); + }); + + describe('the form is disabled', () => { + it('the form is hidden', () => { + mountComponent(); + + expect(findFormComponent().exists()).toBe(false); + }); + + it('shows an alert', () => { + mountComponent(); + + const text = findAlert().text(); + expect(text).toContain(UNAVAILABLE_FEATURE_INTRO_TEXT); + expect(text).toContain(UNAVAILABLE_USER_FEATURE_TEXT); + }); + + describe('an admin is visiting the page', () => { + it('shows the admin part of the alert message', () => { + mountComponent({ ...defaultProvidedValues, isAdmin: true }); + + const sprintf = findAlert().find(GlSprintf); + expect(sprintf.text()).toBe('administration settings'); + expect(sprintf.find(GlLink).attributes('href')).toBe( + defaultProvidedValues.adminSettingsPath, + ); + }); + }); + }); + + describe('fetchSettingsError', () => { + beforeEach(async () => { + mountComponentWithApollo({ + resolver: jest.fn().mockRejectedValue(new Error('GraphQL error')), + }); + await waitForPromises(); + }); + + it('the form is hidden', () => { + expect(findFormComponent().exists()).toBe(false); + }); + + it('shows an alert', () => { + expect(findAlert().html()).toContain(FETCH_SETTINGS_ERROR_MESSAGE); + }); + }); + + describe('empty API response', () => { + it.each` + enableHistoricEntries | isShown + ${true} | ${true} + ${false} | ${false} + `('is $isShown that the form is shown', async ({ enableHistoricEntries, isShown }) => { + mountComponentWithApollo({ + provide: { + ...defaultProvidedValues, + enableHistoricEntries, + }, + resolver: jest.fn().mockResolvedValue(emptyExpirationPolicyPayload()), + }); + await waitForPromises(); + + expect(findFormComponent().exists()).toBe(isShown); + }); + }); +}); 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 0a72f0269ee..337991dfae0 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js @@ -1,165 +1,19 @@ -import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; -import Vue from 'vue'; -import VueApollo from 'vue-apollo'; -import createMockApollo from 'helpers/mock_apollo_helper'; -import waitForPromises from 'helpers/wait_for_promises'; import component from '~/packages_and_registries/settings/project/components/registry_settings_app.vue'; -import SettingsForm from '~/packages_and_registries/settings/project/components/settings_form.vue'; -import { - FETCH_SETTINGS_ERROR_MESSAGE, - UNAVAILABLE_FEATURE_INTRO_TEXT, - 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 SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; +import ContainerExpirationPolicy from '~/packages_and_registries/settings/project/components/container_expiration_policy.vue'; -import { - expirationPolicyPayload, - emptyExpirationPolicyPayload, - containerExpirationPolicyData, -} from '../mock_data'; - -describe('Registry Settings App', () => { +describe('Registry Settings app', () => { let wrapper; - let fakeApollo; - - const defaultProvidedValues = { - projectPath: 'path', - isAdmin: false, - adminSettingsPath: 'settingsPath', - enableHistoricEntries: false, - helpPagePath: 'helpPagePath', - showCleanupPolicyLink: false, - }; - - const findSettingsComponent = () => wrapper.find(SettingsForm); - const findAlert = () => wrapper.find(GlAlert); - - const mountComponent = (provide = defaultProvidedValues, config) => { - wrapper = shallowMount(component, { - stubs: { - GlSprintf, - SettingsBlock, - }, - mocks: { - $toast: { - show: jest.fn(), - }, - }, - provide, - ...config, - }); - }; - - const mountComponentWithApollo = ({ provide = defaultProvidedValues, resolver } = {}) => { - Vue.use(VueApollo); - - const requestHandlers = [[expirationPolicyQuery, resolver]]; - - fakeApollo = createMockApollo(requestHandlers); - mountComponent(provide, { - apolloProvider: fakeApollo, - }); - }; + const findContainerExpirationPolicy = () => wrapper.find(ContainerExpirationPolicy); afterEach(() => { wrapper.destroy(); + wrapper = null; }); - describe('isEdited status', () => { - it.each` - description | apiResponse | workingCopy | result - ${'empty response and no changes from user'} | ${emptyExpirationPolicyPayload()} | ${{}} | ${false} - ${'empty response and changes from user'} | ${emptyExpirationPolicyPayload()} | ${{ enabled: true }} | ${true} - ${'response and no changes'} | ${expirationPolicyPayload()} | ${containerExpirationPolicyData()} | ${false} - ${'response and changes'} | ${expirationPolicyPayload()} | ${{ ...containerExpirationPolicyData(), nameRegex: '12345' }} | ${true} - ${'response and empty'} | ${expirationPolicyPayload()} | ${{}} | ${true} - `('$description', async ({ apiResponse, workingCopy, result }) => { - mountComponentWithApollo({ - provide: { ...defaultProvidedValues, enableHistoricEntries: true }, - resolver: jest.fn().mockResolvedValue(apiResponse), - }); - await waitForPromises(); - - findSettingsComponent().vm.$emit('input', workingCopy); - - await waitForPromises(); - - expect(findSettingsComponent().props('isEdited')).toBe(result); - }); - }); - - it('renders the setting form', async () => { - mountComponentWithApollo({ - resolver: jest.fn().mockResolvedValue(expirationPolicyPayload()), - }); - await waitForPromises(); - - expect(findSettingsComponent().exists()).toBe(true); - }); - - describe('the form is disabled', () => { - it('the form is hidden', () => { - mountComponent(); - - expect(findSettingsComponent().exists()).toBe(false); - }); - - it('shows an alert', () => { - mountComponent(); - - const text = findAlert().text(); - expect(text).toContain(UNAVAILABLE_FEATURE_INTRO_TEXT); - expect(text).toContain(UNAVAILABLE_USER_FEATURE_TEXT); - }); - - describe('an admin is visiting the page', () => { - it('shows the admin part of the alert message', () => { - mountComponent({ ...defaultProvidedValues, isAdmin: true }); - - const sprintf = findAlert().find(GlSprintf); - expect(sprintf.text()).toBe('administration settings'); - expect(sprintf.find(GlLink).attributes('href')).toBe( - defaultProvidedValues.adminSettingsPath, - ); - }); - }); - }); - - describe('fetchSettingsError', () => { - beforeEach(async () => { - mountComponentWithApollo({ - resolver: jest.fn().mockRejectedValue(new Error('GraphQL error')), - }); - await waitForPromises(); - }); - - it('the form is hidden', () => { - expect(findSettingsComponent().exists()).toBe(false); - }); - - it('shows an alert', () => { - expect(findAlert().html()).toContain(FETCH_SETTINGS_ERROR_MESSAGE); - }); - }); - - describe('empty API response', () => { - it.each` - enableHistoricEntries | isShown - ${true} | ${true} - ${false} | ${false} - `('is $isShown that the form is shown', async ({ enableHistoricEntries, isShown }) => { - mountComponentWithApollo({ - provide: { - ...defaultProvidedValues, - enableHistoricEntries, - }, - resolver: jest.fn().mockResolvedValue(emptyExpirationPolicyPayload()), - }); - await waitForPromises(); + it('renders container expiration policy component', () => { + wrapper = shallowMount(component); - expect(findSettingsComponent().exists()).toBe(isShown); - }); + expect(findContainerExpirationPolicy().exists()).toBe(true); }); }); 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 3dd6023140f..e6e89806ce0 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 @@ -30,11 +30,11 @@ exports[`Registry Breadcrumb when is not rootRoute renders 1`] = ` <svg aria-hidden="true" class="gl-icon s8" - data-testid="angle-right-icon" + data-testid="chevron-lg-right-icon" role="img" > <use - href="#angle-right" + href="#chevron-lg-right" /> </svg> </span> diff --git a/spec/frontend/packages_and_registries/shared/components/persisted_search_spec.js b/spec/frontend/packages_and_registries/shared/components/persisted_search_spec.js index bd492a5ae8f..db9f96bff39 100644 --- a/spec/frontend/packages_and_registries/shared/components/persisted_search_spec.js +++ b/spec/frontend/packages_and_registries/shared/components/persisted_search_spec.js @@ -100,7 +100,7 @@ describe('Persisted Search', () => { await nextTick(); - expect(findRegistrySearch().props('filter')).toEqual(['foo']); + expect(findRegistrySearch().props('filters')).toEqual(['foo']); }); it('on filter:submit emits update event', async () => { @@ -138,7 +138,7 @@ describe('Persisted Search', () => { expect(getQueryParams).toHaveBeenCalled(); expect(findRegistrySearch().props()).toMatchObject({ - filter: defaultQueryParamsMock.filters, + filters: defaultQueryParamsMock.filters, sorting: defaultQueryParamsMock.sorting, }); }); |