diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-11-18 16:16:36 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-11-18 16:16:36 +0300 |
commit | 311b0269b4eb9839fa63f80c8d7a58f32b8138a0 (patch) | |
tree | 07e7870bca8aed6d61fdcc810731c50d2c40af47 /spec/frontend/registry/explorer/pages/list_spec.js | |
parent | 27909cef6c4170ed9205afa7426b8d3de47cbb0c (diff) |
Add latest changes from gitlab-org/gitlab@14-5-stable-eev14.5.0-rc42
Diffstat (limited to 'spec/frontend/registry/explorer/pages/list_spec.js')
-rw-r--r-- | spec/frontend/registry/explorer/pages/list_spec.js | 597 |
1 files changed, 0 insertions, 597 deletions
diff --git a/spec/frontend/registry/explorer/pages/list_spec.js b/spec/frontend/registry/explorer/pages/list_spec.js deleted file mode 100644 index e1f24a2b65b..00000000000 --- a/spec/frontend/registry/explorer/pages/list_spec.js +++ /dev/null @@ -1,597 +0,0 @@ -import { GlSkeletonLoader, GlSprintf, GlAlert } from '@gitlab/ui'; -import { shallowMount, createLocalVue } from '@vue/test-utils'; -import { nextTick } from 'vue'; -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 '~/registry/explorer/components/delete_image.vue'; -import CliCommands from '~/registry/explorer/components/list_page/cli_commands.vue'; -import GroupEmptyState from '~/registry/explorer/components/list_page/group_empty_state.vue'; -import ImageList from '~/registry/explorer/components/list_page/image_list.vue'; -import ProjectEmptyState from '~/registry/explorer/components/list_page/project_empty_state.vue'; -import RegistryHeader from '~/registry/explorer/components/list_page/registry_header.vue'; -import { - DELETE_IMAGE_SUCCESS_MESSAGE, - DELETE_IMAGE_ERROR_MESSAGE, - SORT_FIELDS, -} from '~/registry/explorer/constants'; -import deleteContainerRepositoryMutation from '~/registry/explorer/graphql/mutations/delete_container_repository.mutation.graphql'; -import getContainerRepositoriesDetails from '~/registry/explorer/graphql/queries/get_container_repositories_details.query.graphql'; -import component from '~/registry/explorer/pages/list.vue'; -import Tracking from '~/tracking'; -import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue'; -import TitleArea from '~/vue_shared/components/registry/title_area.vue'; - -import { $toast } from '../../shared/mocks'; -import { - graphQLImageListMock, - graphQLImageDeleteMock, - deletedContainerRepository, - graphQLEmptyImageListMock, - graphQLEmptyGroupImageListMock, - pageInfo, - graphQLProjectImageRepositoriesDetailsMock, - dockerCommands, -} from '../mock_data'; -import { GlModal, GlEmptyState } from '../stubs'; - -const localVue = createLocalVue(); - -describe('List Page', () => { - let wrapper; - let apolloProvider; - - const findDeleteModal = () => wrapper.findComponent(GlModal); - const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader); - - const findEmptyState = () => wrapper.findComponent(GlEmptyState); - - const findCliCommands = () => wrapper.findComponent(CliCommands); - const findProjectEmptyState = () => wrapper.findComponent(ProjectEmptyState); - const findGroupEmptyState = () => wrapper.findComponent(GroupEmptyState); - const findRegistryHeader = () => wrapper.findComponent(RegistryHeader); - - const findDeleteAlert = () => wrapper.findComponent(GlAlert); - const findImageList = () => wrapper.findComponent(ImageList); - const findRegistrySearch = () => wrapper.findComponent(RegistrySearch); - const findEmptySearchMessage = () => wrapper.find('[data-testid="emptySearch"]'); - const findDeleteImage = () => wrapper.findComponent(DeleteImage); - const findCleanupAlert = () => wrapper.findComponent(CleanupPolicyEnabledAlert); - - const waitForApolloRequestRender = async () => { - jest.runOnlyPendingTimers(); - await waitForPromises(); - await nextTick(); - }; - - const mountComponent = ({ - mocks, - resolver = jest.fn().mockResolvedValue(graphQLImageListMock), - detailsResolver = jest.fn().mockResolvedValue(graphQLProjectImageRepositoriesDetailsMock), - mutationResolver = jest.fn().mockResolvedValue(graphQLImageDeleteMock), - config = { isGroupPage: false }, - query = {}, - } = {}) => { - localVue.use(VueApollo); - - const requestHandlers = [ - [getContainerRepositoriesQuery, resolver], - [getContainerRepositoriesDetails, detailsResolver], - [deleteContainerRepositoryMutation, mutationResolver], - ]; - - apolloProvider = createMockApollo(requestHandlers); - - wrapper = shallowMount(component, { - localVue, - apolloProvider, - stubs: { - GlModal, - GlEmptyState, - GlSprintf, - RegistryHeader, - TitleArea, - DeleteImage, - }, - mocks: { - $toast, - $route: { - name: 'foo', - query, - }, - ...mocks, - }, - provide() { - return { - config, - ...dockerCommands, - }; - }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - it('contains registry header', async () => { - mountComponent(); - - await waitForApolloRequestRender(); - - expect(findRegistryHeader().exists()).toBe(true); - expect(findRegistryHeader().props()).toMatchObject({ - imagesCount: 2, - metadataLoading: false, - }); - }); - - describe.each([ - { error: 'connectionError', errorName: 'connection error' }, - { error: 'invalidPathError', errorName: 'invalid path error' }, - ])('handling $errorName', ({ error }) => { - const config = { - containersErrorImage: 'foo', - helpPagePath: 'bar', - isGroupPage: false, - }; - config[error] = true; - - it('should show an empty state', () => { - mountComponent({ config }); - - expect(findEmptyState().exists()).toBe(true); - }); - - it('empty state should have an svg-path', () => { - mountComponent({ config }); - - expect(findEmptyState().props('svgPath')).toBe(config.containersErrorImage); - }); - - it('empty state should have a description', () => { - mountComponent({ config }); - - expect(findEmptyState().props('title')).toContain('connection error'); - }); - - it('should not show the loading or default state', () => { - mountComponent({ config }); - - expect(findSkeletonLoader().exists()).toBe(false); - expect(findImageList().exists()).toBe(false); - }); - }); - - describe('isLoading is true', () => { - it('shows the skeleton loader', async () => { - mountComponent(); - - await nextTick(); - - expect(findSkeletonLoader().exists()).toBe(true); - }); - - it('imagesList is not visible', () => { - mountComponent(); - - expect(findImageList().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(); - - await nextTick(); - - expect(findRegistryHeader().props('metadataLoading')).toBe(true); - }); - }); - - describe('list is empty', () => { - describe('project page', () => { - const resolver = jest.fn().mockResolvedValue(graphQLEmptyImageListMock); - - it('cli commands is not visible', async () => { - mountComponent({ resolver }); - - await waitForApolloRequestRender(); - - expect(findCliCommands().exists()).toBe(false); - }); - - it('project empty state is visible', async () => { - mountComponent({ resolver }); - - await waitForApolloRequestRender(); - - expect(findProjectEmptyState().exists()).toBe(true); - }); - }); - - describe('group page', () => { - const resolver = jest.fn().mockResolvedValue(graphQLEmptyGroupImageListMock); - - const config = { - isGroupPage: true, - }; - - it('group empty state is visible', async () => { - mountComponent({ resolver, config }); - - await waitForApolloRequestRender(); - - expect(findGroupEmptyState().exists()).toBe(true); - }); - - it('cli commands is not visible', async () => { - mountComponent({ resolver, config }); - - await waitForApolloRequestRender(); - - expect(findCliCommands().exists()).toBe(false); - }); - }); - }); - - describe('list is not empty', () => { - describe('unfiltered state', () => { - it('quick start is visible', async () => { - mountComponent(); - - await waitForApolloRequestRender(); - - expect(findCliCommands().exists()).toBe(true); - }); - - it('list component is visible', async () => { - mountComponent(); - - await waitForApolloRequestRender(); - - expect(findImageList().exists()).toBe(true); - }); - - describe('additional metadata', () => { - it('is called on component load', async () => { - const detailsResolver = jest - .fn() - .mockResolvedValue(graphQLProjectImageRepositoriesDetailsMock); - mountComponent({ detailsResolver }); - - jest.runOnlyPendingTimers(); - await waitForPromises(); - - expect(detailsResolver).toHaveBeenCalled(); - }); - - it('does not block the list ui to show', async () => { - const detailsResolver = jest.fn().mockRejectedValue(); - mountComponent({ detailsResolver }); - - await waitForApolloRequestRender(); - - expect(findImageList().exists()).toBe(true); - }); - - it('loading state is passed to list component', async () => { - // this is a promise that never resolves, to trick apollo to think that this request is still loading - const detailsResolver = jest.fn().mockImplementation(() => new Promise(() => {})); - - mountComponent({ detailsResolver }); - await waitForApolloRequestRender(); - - expect(findImageList().props('metadataLoading')).toBe(true); - }); - }); - - describe('delete image', () => { - const selectImageForDeletion = async () => { - await waitForApolloRequestRender(); - - findImageList().vm.$emit('delete', deletedContainerRepository); - }; - - it('should call deleteItem when confirming deletion', async () => { - const mutationResolver = jest.fn().mockResolvedValue(graphQLImageDeleteMock); - mountComponent({ mutationResolver }); - - await selectImageForDeletion(); - - findDeleteModal().vm.$emit('primary'); - await waitForApolloRequestRender(); - - expect(wrapper.vm.itemToDelete).toEqual(deletedContainerRepository); - - const updatedImage = findImageList() - .props('images') - .find((i) => i.id === deletedContainerRepository.id); - - expect(updatedImage.status).toBe(deletedContainerRepository.status); - }); - - it('should show a success alert when delete request is successful', async () => { - mountComponent(); - - await selectImageForDeletion(); - - findDeleteImage().vm.$emit('success'); - await nextTick(); - - const alert = findDeleteAlert(); - expect(alert.exists()).toBe(true); - expect(alert.text().replace(/\s\s+/gm, ' ')).toBe( - DELETE_IMAGE_SUCCESS_MESSAGE.replace('%{title}', wrapper.vm.itemToDelete.path), - ); - }); - - describe('when delete request fails it shows an alert', () => { - it('user recoverable error', async () => { - mountComponent(); - - await selectImageForDeletion(); - - findDeleteImage().vm.$emit('error'); - await nextTick(); - - const alert = findDeleteAlert(); - expect(alert.exists()).toBe(true); - expect(alert.text().replace(/\s\s+/gm, ' ')).toBe( - DELETE_IMAGE_ERROR_MESSAGE.replace('%{title}', wrapper.vm.itemToDelete.path), - ); - }); - }); - }); - }); - - describe('search and sorting', () => { - const doSearch = async () => { - await waitForApolloRequestRender(); - findRegistrySearch().vm.$emit('filter:changed', [ - { type: FILTERED_SEARCH_TERM, value: { data: 'centos6' } }, - ]); - - findRegistrySearch().vm.$emit('filter:submit'); - - await nextTick(); - }; - - it('has a search box element', async () => { - mountComponent(); - - await waitForApolloRequestRender(); - - const registrySearch = findRegistrySearch(); - expect(registrySearch.exists()).toBe(true); - expect(registrySearch.props()).toMatchObject({ - filter: [], - sorting: { orderBy: 'UPDATED', sort: 'desc' }, - sortableFields: SORT_FIELDS, - tokens: [], - }); - }); - - it('performs sorting', async () => { - const resolver = jest.fn().mockResolvedValue(graphQLImageListMock); - mountComponent({ resolver }); - - await waitForApolloRequestRender(); - - findRegistrySearch().vm.$emit('sorting:changed', { sort: 'asc' }); - await nextTick(); - - expect(resolver).toHaveBeenCalledWith(expect.objectContaining({ sort: 'UPDATED_DESC' })); - }); - - it('performs a search', async () => { - const resolver = jest.fn().mockResolvedValue(graphQLImageListMock); - mountComponent({ resolver }); - - await doSearch(); - - expect(resolver).toHaveBeenCalledWith(expect.objectContaining({ name: 'centos6' })); - }); - - it('when search result is empty displays an empty search message', async () => { - const resolver = jest.fn().mockResolvedValue(graphQLImageListMock); - const detailsResolver = jest - .fn() - .mockResolvedValue(graphQLProjectImageRepositoriesDetailsMock); - mountComponent({ resolver, detailsResolver }); - - await waitForApolloRequestRender(); - - resolver.mockResolvedValue(graphQLEmptyImageListMock); - detailsResolver.mockResolvedValue(graphQLEmptyImageListMock); - - await doSearch(); - - expect(findEmptySearchMessage().exists()).toBe(true); - }); - }); - - describe('pagination', () => { - it('prev-page event triggers a fetchMore request', async () => { - const resolver = jest.fn().mockResolvedValue(graphQLImageListMock); - const detailsResolver = jest - .fn() - .mockResolvedValue(graphQLProjectImageRepositoriesDetailsMock); - mountComponent({ resolver, detailsResolver }); - - await waitForApolloRequestRender(); - - findImageList().vm.$emit('prev-page'); - await nextTick(); - - expect(resolver).toHaveBeenCalledWith( - expect.objectContaining({ before: pageInfo.startCursor }), - ); - expect(detailsResolver).toHaveBeenCalledWith( - expect.objectContaining({ before: pageInfo.startCursor }), - ); - }); - - it('next-page event triggers a fetchMore request', async () => { - const resolver = jest.fn().mockResolvedValue(graphQLImageListMock); - const detailsResolver = jest - .fn() - .mockResolvedValue(graphQLProjectImageRepositoriesDetailsMock); - mountComponent({ resolver, detailsResolver }); - - await waitForApolloRequestRender(); - - findImageList().vm.$emit('next-page'); - await nextTick(); - - expect(resolver).toHaveBeenCalledWith( - expect.objectContaining({ after: pageInfo.endCursor }), - ); - expect(detailsResolver).toHaveBeenCalledWith( - expect.objectContaining({ after: pageInfo.endCursor }), - ); - }); - }); - }); - - describe('modal', () => { - beforeEach(() => { - mountComponent(); - }); - - it('exists', () => { - expect(findDeleteModal().exists()).toBe(true); - }); - - it('contains a description with the path of the item to delete', async () => { - findImageList().vm.$emit('delete', { path: 'foo' }); - await nextTick(); - expect(findDeleteModal().html()).toContain('foo'); - }); - }); - - describe('tracking', () => { - beforeEach(() => { - mountComponent(); - }); - - const testTrackingCall = (action) => { - expect(Tracking.event).toHaveBeenCalledWith(undefined, action, { - label: 'registry_repository_delete', - }); - }; - - beforeEach(() => { - jest.spyOn(Tracking, 'event'); - }); - - it('send an event when delete button is clicked', () => { - findImageList().vm.$emit('delete', {}); - - testTrackingCall('click_button'); - }); - - it('send an event when cancel is pressed on modal', () => { - const deleteModal = findDeleteModal(); - deleteModal.vm.$emit('cancel'); - testTrackingCall('cancel_delete'); - }); - - it('send an event when the deletion starts', () => { - findDeleteImage().vm.$emit('start'); - testTrackingCall('confirm_delete'); - }); - }); - - describe('url query string handling', () => { - const defaultQueryParams = { - search: [1, 2], - sort: 'asc', - orderBy: 'CREATED', - }; - const queryChangePayload = 'foo'; - - it('query:updated event pushes the new query to the router', async () => { - const push = jest.fn(); - mountComponent({ mocks: { $router: { push } } }); - - await nextTick(); - - findRegistrySearch().vm.$emit('query:changed', queryChangePayload); - - expect(push).toHaveBeenCalledWith({ query: queryChangePayload }); - }); - - it('graphql API call has the variables set from the URL', async () => { - const resolver = jest.fn().mockResolvedValue(graphQLImageListMock); - mountComponent({ query: defaultQueryParams, resolver }); - - await nextTick(); - - expect(resolver).toHaveBeenCalledWith( - expect.objectContaining({ - name: 1, - sort: 'CREATED_ASC', - }), - ); - }); - - it.each` - sort | orderBy | search | payload - ${'ASC'} | ${undefined} | ${undefined} | ${{ sort: 'UPDATED_ASC' }} - ${undefined} | ${'bar'} | ${undefined} | ${{ sort: 'BAR_DESC' }} - ${'ASC'} | ${'bar'} | ${undefined} | ${{ sort: 'BAR_ASC' }} - ${undefined} | ${undefined} | ${undefined} | ${{}} - ${undefined} | ${undefined} | ${['one']} | ${{ name: 'one' }} - ${undefined} | ${undefined} | ${['one', 'two']} | ${{ name: 'one' }} - ${undefined} | ${'UPDATED'} | ${['one', 'two']} | ${{ name: 'one', sort: 'UPDATED_DESC' }} - ${'ASC'} | ${'UPDATED'} | ${['one', 'two']} | ${{ name: 'one', sort: 'UPDATED_ASC' }} - `( - 'with sort equal to $sort, orderBy equal to $orderBy, search set to $search API call has the variables set as $payload', - async ({ sort, orderBy, search, payload }) => { - const resolver = jest.fn().mockResolvedValue({ sort, orderBy }); - mountComponent({ query: { sort, orderBy, search }, resolver }); - - await nextTick(); - - expect(resolver).toHaveBeenCalledWith(expect.objectContaining(payload)); - }, - ); - }); - - 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); - }); - }); -}); |