Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/registry/explorer/pages/list_spec.js')
-rw-r--r--spec/frontend/registry/explorer/pages/list_spec.js597
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);
- });
- });
-});