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:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-12-10 18:10:12 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-12-10 18:10:12 +0300
commit8f143a46faf2e7b594301512757edf372c294a0c (patch)
tree8bd5957ffa44d028905ab51a7252cce6783d2e25 /spec/frontend/registry
parent3e06afc4cd1b75b3e957e8debf5e4f1963ba18e0 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/registry')
-rw-r--r--spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js53
-rw-r--r--spec/frontend/registry/explorer/components/details_page/tags_list_spec.js8
-rw-r--r--spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js9
-rw-r--r--spec/frontend/registry/explorer/mock_data.js165
-rw-r--r--spec/frontend/registry/explorer/pages/details_spec.js327
5 files changed, 381 insertions, 181 deletions
diff --git a/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js b/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
index 3276ef911e3..9a5a8b8b7a7 100644
--- a/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
+++ b/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
@@ -20,7 +20,7 @@ import { ListItem } from '../../stubs';
describe('tags list row', () => {
let wrapper;
- const [tag] = [...tagsListResponse.data];
+ const [tag] = [...tagsListResponse];
const defaultProps = { tag, isMobile: false, index: 0 };
@@ -65,7 +65,7 @@ describe('tags list row', () => {
});
it("does not exist when the row can't be deleted", () => {
- const customTag = { ...tag, destroy_path: '' };
+ const customTag = { ...tag, canDelete: false };
mountComponent({ ...defaultProps, tag: customTag });
@@ -137,8 +137,8 @@ describe('tags list row', () => {
mountComponent();
expect(findClipboardButton().attributes()).toMatchObject({
- text: 'location',
- title: 'location',
+ text: tag.location,
+ title: tag.location,
});
});
});
@@ -171,26 +171,26 @@ describe('tags list row', () => {
expect(findSize().exists()).toBe(true);
});
- it('contains the total_size and layers', () => {
- mountComponent({ ...defaultProps, tag: { ...tag, total_size: 1024 } });
+ it('contains the totalSize and layers', () => {
+ mountComponent({ ...defaultProps, tag: { ...tag, totalSize: 1024 } });
expect(findSize().text()).toMatchInterpolatedText('1.00 KiB · 10 layers');
});
- it('when total_size is missing', () => {
- mountComponent();
+ it('when totalSize is missing', () => {
+ mountComponent({ ...defaultProps, tag: { ...tag, totalSize: 0 } });
expect(findSize().text()).toMatchInterpolatedText(`${NOT_AVAILABLE_SIZE} · 10 layers`);
});
it('when layers are missing', () => {
- mountComponent({ ...defaultProps, tag: { ...tag, total_size: 1024, layers: null } });
+ mountComponent({ ...defaultProps, tag: { ...tag, totalSize: 1024, layers: null } });
expect(findSize().text()).toMatchInterpolatedText('1.00 KiB');
});
it('when there is 1 layer', () => {
- mountComponent({ ...defaultProps, tag: { ...tag, layers: 1 } });
+ mountComponent({ ...defaultProps, tag: { ...tag, totalSize: 0, layers: 1 } });
expect(findSize().text()).toMatchInterpolatedText(`${NOT_AVAILABLE_SIZE} · 1 layer`);
});
@@ -218,7 +218,7 @@ describe('tags list row', () => {
it('pass the correct props to time ago tooltip', () => {
mountComponent();
- expect(findTimeAgoTooltip().attributes()).toMatchObject({ time: tag.created_at });
+ expect(findTimeAgoTooltip().attributes()).toMatchObject({ time: tag.createdAt });
});
});
@@ -232,7 +232,7 @@ describe('tags list row', () => {
it('has the correct text', () => {
mountComponent();
- expect(findShortRevision().text()).toMatchInterpolatedText('Digest: 1ab51d5');
+ expect(findShortRevision().text()).toMatchInterpolatedText('Digest: 9d72ae1');
});
it(`displays ${NOT_AVAILABLE_TEXT} when digest is missing`, () => {
@@ -260,18 +260,15 @@ describe('tags list row', () => {
});
it.each`
- destroy_path | digest
- ${'foo'} | ${null}
- ${null} | ${'foo'}
- ${null} | ${null}
- `(
- 'is disabled when destroy_path is $destroy_path and digest is $digest',
- ({ destroy_path, digest }) => {
- mountComponent({ ...defaultProps, tag: { ...tag, destroy_path, digest } });
-
- expect(findDeleteButton().attributes('disabled')).toBe('true');
- },
- );
+ canDelete | digest
+ ${true} | ${null}
+ ${false} | ${'foo'}
+ ${false} | ${null}
+ `('is disabled when canDelete is $canDelete and digest is $digest', ({ canDelete, digest }) => {
+ mountComponent({ ...defaultProps, tag: { ...tag, canDelete, digest } });
+
+ expect(findDeleteButton().attributes('disabled')).toBe('true');
+ });
it('delete event emits delete', () => {
mountComponent();
@@ -295,10 +292,10 @@ describe('tags list row', () => {
});
describe.each`
- name | finderFunction | text | icon | clipboard
- ${'published date detail'} | ${findPublishedDateDetail} | ${'Published to the bar image repository at 10:23 GMT+0000 on 2020-06-29'} | ${'clock'} | ${false}
- ${'manifest detail'} | ${findManifestDetail} | ${'Manifest digest: sha256:1ab51d519f574b636ae7788051c60239334ae8622a9fd82a0cf7bae7786dfd5c'} | ${'log'} | ${true}
- ${'configuration detail'} | ${findConfigurationDetail} | ${'Configuration digest: sha256:b118ab5b0e90b7cb5127db31d5321ac14961d097516a8e0e72084b6cdc783b43'} | ${'cloud-gear'} | ${true}
+ name | finderFunction | text | icon | clipboard
+ ${'published date detail'} | ${findPublishedDateDetail} | ${'Published to the gitlab-org/gitlab-test/rails-12009 image repository at 01:29 GMT+0000 on 2020-11-03'} | ${'clock'} | ${false}
+ ${'manifest detail'} | ${findManifestDetail} | ${'Manifest digest: sha256:9d72ae1db47404e44e1760eb1ca4cb427b84be8c511f05dfe2089e1b9f741dd7'} | ${'log'} | ${true}
+ ${'configuration detail'} | ${findConfigurationDetail} | ${'Configuration digest: sha256:5183b5d133fa864dca2de602f874b0d1bffe0f204ad894e3660432a487935139'} | ${'cloud-gear'} | ${true}
`('$name details row', ({ finderFunction, text, icon, clipboard }) => {
it(`has ${text} as text`, () => {
expect(finderFunction().text()).toMatchInterpolatedText(text);
diff --git a/spec/frontend/registry/explorer/components/details_page/tags_list_spec.js b/spec/frontend/registry/explorer/components/details_page/tags_list_spec.js
index ebeaa8ff870..e5779b2c103 100644
--- a/spec/frontend/registry/explorer/components/details_page/tags_list_spec.js
+++ b/spec/frontend/registry/explorer/components/details_page/tags_list_spec.js
@@ -7,8 +7,8 @@ import { tagsListResponse } from '../../mock_data';
describe('Tags List', () => {
let wrapper;
- const tags = [...tagsListResponse.data];
- const readOnlyTags = tags.map(t => ({ ...t, destroy_path: undefined }));
+ const tags = [...tagsListResponse];
+ const readOnlyTags = tags.map(t => ({ ...t, canDelete: false }));
const findTagsListRow = () => wrapper.findAll(TagsListRow);
const findDeleteButton = () => wrapper.find(GlButton);
@@ -92,7 +92,7 @@ describe('Tags List', () => {
.vm.$emit('select');
findDeleteButton().vm.$emit('click');
- expect(wrapper.emitted('delete')).toEqual([[{ centos6: true }]]);
+ expect(wrapper.emitted('delete')).toEqual([[{ 'alpha-11821': true }]]);
});
});
@@ -132,7 +132,7 @@ describe('Tags List', () => {
findTagsListRow()
.at(0)
.vm.$emit('delete');
- expect(wrapper.emitted('delete')).toEqual([[{ centos6: true }]]);
+ expect(wrapper.emitted('delete')).toEqual([[{ 'alpha-11821': true }]]);
});
});
});
diff --git a/spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js b/spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js
index d730bfcde24..fb0b98ba004 100644
--- a/spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js
+++ b/spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js
@@ -32,10 +32,6 @@ describe('Registry Breadcrumb', () => {
{ name: 'baz', meta: { nameGenerator } },
];
- const state = {
- imageDetails: { foo: 'bar' },
- };
-
const findDivider = () => wrapper.find('.js-divider');
const findRootRoute = () => wrapper.find({ ref: 'rootRouteLink' });
const findChildRoute = () => wrapper.find({ ref: 'childRouteLink' });
@@ -56,9 +52,6 @@ describe('Registry Breadcrumb', () => {
routes,
},
},
- $store: {
- state,
- },
},
});
};
@@ -87,7 +80,6 @@ describe('Registry Breadcrumb', () => {
});
it('the link text is calculated by nameGenerator', () => {
- expect(nameGenerator).toHaveBeenCalledWith(state);
expect(nameGenerator).toHaveBeenCalledTimes(1);
});
});
@@ -111,7 +103,6 @@ describe('Registry Breadcrumb', () => {
});
it('the link text is calculated by nameGenerator', () => {
- expect(nameGenerator).toHaveBeenCalledWith(state);
expect(nameGenerator).toHaveBeenCalledTimes(2);
});
});
diff --git a/spec/frontend/registry/explorer/mock_data.js b/spec/frontend/registry/explorer/mock_data.js
index 13b1c4a485d..06a25470c45 100644
--- a/spec/frontend/registry/explorer/mock_data.js
+++ b/spec/frontend/registry/explorer/mock_data.js
@@ -72,34 +72,34 @@ export const imagesListResponse = [
},
];
-export const tagsListResponse = {
- data: [
- {
- name: 'centos6',
- revision: 'b118ab5b0e90b7cb5127db31d5321ac14961d097516a8e0e72084b6cdc783b43',
- short_revision: 'b118ab5b0',
- size: 19,
- layers: 10,
- location: 'location',
- path: 'bar:centos6',
- created_at: '2020-06-29T10:23:51.766+00:00',
- destroy_path: 'path',
- digest: 'sha256:1ab51d519f574b636ae7788051c60239334ae8622a9fd82a0cf7bae7786dfd5c',
- },
- {
- name: 'test-tag',
- revision: 'b969de599faea2b3d9b6605a8b0897261c571acaa36db1bdc7349b5775b4e0b4',
- short_revision: 'b969de599',
- size: 19,
- layers: 10,
- path: 'foo:test-tag',
- location: 'location-2',
- created_at: '2020-06-29T10:23:51.766+00:00',
- digest: 'sha256:1ab51d519f574b636ae7788051c60239334ae8622a9fd82a0cf7bae7736dfd5c',
- },
- ],
- headers,
-};
+export const tagsListResponse = [
+ {
+ canDelete: true,
+ createdAt: '2020-11-03T13:29:49+00:00',
+ digest: 'sha256:9d72ae1db47404e44e1760eb1ca4cb427b84be8c511f05dfe2089e1b9f741dd7',
+ location: 'host.docker.internal:5000/gitlab-org/gitlab-test/rails-12009:alpha-11821',
+ name: 'alpha-11821',
+ path: 'gitlab-org/gitlab-test/rails-12009:alpha-11821',
+ revision: '5183b5d133fa864dca2de602f874b0d1bffe0f204ad894e3660432a487935139',
+ shortRevision: '5183b5d13',
+ totalSize: 104,
+ layers: 10,
+ __typename: 'ContainerRepositoryTag',
+ },
+ {
+ canDelete: true,
+ createdAt: '2020-11-03T13:29:48+00:00',
+ digest: 'sha256:64f61282a71659f72066f9decd30b9038a465859b277a5e20da8681eb83e72f7',
+ location: 'host.docker.internal:5000/gitlab-org/gitlab-test/rails-12009:alpha-20825',
+ name: 'alpha-20825',
+ path: 'gitlab-org/gitlab-test/rails-12009:alpha-20825',
+ revision: 'e4212f1b73c6f9def2c37fa7df6c8d35c345fb1402860ff9a56404821aacf16f',
+ shortRevision: 'e4212f1b7',
+ totalSize: 105,
+ layers: 10,
+ __typename: 'ContainerRepositoryTag',
+ },
+];
export const pageInfo = {
hasNextPage: true,
@@ -110,14 +110,14 @@ export const pageInfo = {
};
export const imageDetailsMock = {
- id: 1,
- name: 'rails-32309',
- path: 'gitlab-org/gitlab-test/rails-32309',
- project_id: 1,
- location: '0.0.0.0:5000/gitlab-org/gitlab-test/rails-32309',
- created_at: '2020-06-29T10:23:47.838Z',
- cleanup_policy_started_at: null,
- delete_api_path: 'http://0.0.0.0:3000/api/v4/projects/1/registry/repositories/1',
+ canDelete: true,
+ createdAt: '2020-11-03T13:29:21Z',
+ expirationPolicyStartedAt: null,
+ id: 'gid://gitlab/ContainerRepository/26',
+ location: 'host.docker.internal:5000/gitlab-org/gitlab-test/rails-12009',
+ name: 'rails-12009',
+ path: 'gitlab-org/gitlab-test/rails-12009',
+ status: null,
};
export const graphQLImageListMock = {
@@ -192,3 +192,96 @@ export const graphQLImageDeleteMockError = {
},
},
};
+
+export const containerRepositoryMock = {
+ id: 'gid://gitlab/ContainerRepository/26',
+ name: 'rails-12009',
+ path: 'gitlab-org/gitlab-test/rails-12009',
+ status: null,
+ location: 'host.docker.internal:5000/gitlab-org/gitlab-test/rails-12009',
+ canDelete: true,
+ createdAt: '2020-11-03T13:29:21Z',
+ tagsCount: 13,
+ expirationPolicyStartedAt: null,
+};
+
+export const tagsPageInfo = {
+ __typename: 'PageInfo',
+ hasNextPage: true,
+ hasPreviousPage: true,
+ startCursor: 'MQ',
+ endCursor: 'MTA',
+};
+
+export const tagsMock = [
+ {
+ digest: 'sha256:2cf3d2fdac1b04a14301d47d51cb88dcd26714c74f91440eeee99ce399089062',
+ location: 'host.docker.internal:5000/gitlab-org/gitlab-test/rails-12009:beta-24753',
+ path: 'gitlab-org/gitlab-test/rails-12009:beta-24753',
+ name: 'beta-24753',
+ revision: 'c2613843ab33aabf847965442b13a8b55a56ae28837ce182627c0716eb08c02b',
+ shortRevision: 'c2613843a',
+ createdAt: '2020-11-03T13:29:38+00:00',
+ totalSize: 105,
+ canDelete: true,
+ __typename: 'ContainerRepositoryTag',
+ },
+ {
+ digest: 'sha256:7f94f97dff89ffd122cafe50cd32329adf682356a7a96f69cbfe313ee589791c',
+ location: 'host.docker.internal:5000/gitlab-org/gitlab-test/rails-12009:beta-31075',
+ path: 'gitlab-org/gitlab-test/rails-12009:beta-31075',
+ name: 'beta-31075',
+ revision: 'df44e7228f0f255c73e35b6f0699624a615f42746e3e8e2e4b3804a6d6fc3292',
+ shortRevision: 'df44e7228',
+ createdAt: '2020-11-03T13:29:32+00:00',
+ totalSize: 104,
+ canDelete: true,
+ __typename: 'ContainerRepositoryTag',
+ },
+];
+
+export const graphQLImageDetailsMock = override => ({
+ data: {
+ containerRepository: {
+ ...containerRepositoryMock,
+
+ tags: {
+ nodes: tagsMock,
+ pageInfo: { ...tagsPageInfo },
+ __typename: 'ContainerRepositoryTagConnection',
+ },
+ __typename: 'ContainerRepositoryDetails',
+ ...override,
+ },
+ },
+});
+
+export const graphQLImageDetailsEmptyTagsMock = {
+ data: {
+ containerRepository: {
+ ...containerRepositoryMock,
+ tags: {
+ nodes: [],
+ pageInfo: {
+ __typename: 'PageInfo',
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: '',
+ endCursor: '',
+ },
+ __typename: 'ContainerRepositoryTagConnection',
+ },
+ __typename: 'ContainerRepositoryDetails',
+ },
+ },
+};
+
+export const graphQLDeleteImageRepositoryTagsMock = {
+ data: {
+ destroyContainerRepositoryTags: {
+ deletedTagNames: [],
+ errors: [],
+ __typename: 'DestroyContainerRepositoryTagsPayload',
+ },
+ },
+};
diff --git a/spec/frontend/registry/explorer/pages/details_spec.js b/spec/frontend/registry/explorer/pages/details_spec.js
index c09b7e0c067..b2b0d4de9b9 100644
--- a/spec/frontend/registry/explorer/pages/details_spec.js
+++ b/spec/frontend/registry/explorer/pages/details_spec.js
@@ -1,5 +1,8 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlPagination } from '@gitlab/ui';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { GlKeysetPagination } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'jest/helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import Tracking from '~/tracking';
import component from '~/registry/explorer/pages/details.vue';
import DeleteAlert from '~/registry/explorer/components/details_page/delete_alert.vue';
@@ -9,24 +12,29 @@ import TagsLoader from '~/registry/explorer/components/details_page/tags_loader.
import TagsList from '~/registry/explorer/components/details_page/tags_list.vue';
import EmptyTagsState from '~/registry/explorer/components/details_page/empty_tags_state.vue';
import { createStore } from '~/registry/explorer/stores/';
+
+import getContainerRepositoryDetailsQuery from '~/registry/explorer/graphql/queries/get_container_repository_details.graphql';
+import deleteContainerRepositoryTagsMutation from '~/registry/explorer/graphql/mutations/delete_container_repository_tags.graphql';
+
import {
- SET_MAIN_LOADING,
- SET_TAGS_LIST_SUCCESS,
- SET_TAGS_PAGINATION,
- SET_INITIAL_STATE,
- SET_IMAGE_DETAILS,
-} from '~/registry/explorer/stores/mutation_types';
-
-import { tagsListResponse, imageDetailsMock } from '../mock_data';
+ graphQLImageDetailsMock,
+ graphQLImageDetailsEmptyTagsMock,
+ graphQLDeleteImageRepositoryTagsMock,
+ containerRepositoryMock,
+ tagsMock,
+ tagsPageInfo,
+} from '../mock_data';
import { DeleteModal } from '../stubs';
+const localVue = createLocalVue();
+
describe('Details Page', () => {
let wrapper;
- let dispatchSpy;
let store;
+ let apolloProvider;
const findDeleteModal = () => wrapper.find(DeleteModal);
- const findPagination = () => wrapper.find(GlPagination);
+ const findPagination = () => wrapper.find(GlKeysetPagination);
const findTagsLoader = () => wrapper.find(TagsLoader);
const findTagsList = () => wrapper.find(TagsList);
const findDeleteAlert = () => wrapper.find(DeleteAlert);
@@ -36,15 +44,46 @@ describe('Details Page', () => {
const routeId = 1;
+ const breadCrumbState = {
+ updateName: jest.fn(),
+ };
+
+ const cleanTags = tagsMock.map(t => {
+ const result = { ...t };
+ // eslint-disable-next-line no-underscore-dangle
+ delete result.__typename;
+ return result;
+ });
+
+ const waitForApolloRequestRender = async () => {
+ await waitForPromises();
+ await wrapper.vm.$nextTick();
+ };
+
const tagsArrayToSelectedTags = tags =>
tags.reduce((acc, c) => {
acc[c.name] = true;
return acc;
}, {});
- const mountComponent = ({ options } = {}) => {
+ const mountComponent = ({
+ resolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock()),
+ mutationResolver = jest.fn().mockResolvedValue(graphQLDeleteImageRepositoryTagsMock),
+ options,
+ } = {}) => {
+ localVue.use(VueApollo);
+
+ const requestHandlers = [
+ [getContainerRepositoryDetailsQuery, resolver],
+ [deleteContainerRepositoryTagsMutation, mutationResolver],
+ ];
+
+ apolloProvider = createMockApollo(requestHandlers);
+
wrapper = shallowMount(component, {
store,
+ localVue,
+ apolloProvider,
stubs: {
DeleteModal,
},
@@ -55,17 +94,17 @@ describe('Details Page', () => {
},
},
},
+ provide() {
+ return {
+ breadCrumbState,
+ };
+ },
...options,
});
};
beforeEach(() => {
store = createStore();
- dispatchSpy = jest.spyOn(store, 'dispatch');
- dispatchSpy.mockResolvedValue();
- store.commit(SET_TAGS_LIST_SUCCESS, tagsListResponse.data);
- store.commit(SET_TAGS_PAGINATION, tagsListResponse.headers);
- store.commit(SET_IMAGE_DETAILS, imageDetailsMock);
jest.spyOn(Tracking, 'event');
});
@@ -74,85 +113,90 @@ describe('Details Page', () => {
wrapper = null;
});
- describe('lifecycle events', () => {
- it('calls the appropriate action on mount', () => {
- mountComponent();
- expect(dispatchSpy).toHaveBeenCalledWith('requestImageDetailsAndTagsList', routeId);
- });
- });
-
describe('when isLoading is true', () => {
- beforeEach(() => {
- store.commit(SET_MAIN_LOADING, true);
+ it('shows the loader', () => {
mountComponent();
- });
-
- afterEach(() => store.commit(SET_MAIN_LOADING, false));
- it('shows the loader', () => {
expect(findTagsLoader().exists()).toBe(true);
});
it('does not show the list', () => {
+ mountComponent();
+
expect(findTagsList().exists()).toBe(false);
});
it('does not show pagination', () => {
+ mountComponent();
+
expect(findPagination().exists()).toBe(false);
});
});
describe('when the list of tags is empty', () => {
- beforeEach(() => {
- store.commit(SET_TAGS_LIST_SUCCESS, []);
- mountComponent();
- });
+ const resolver = jest.fn().mockResolvedValue(graphQLImageDetailsEmptyTagsMock);
+
+ it('has the empty state', async () => {
+ mountComponent({ resolver });
+
+ await waitForApolloRequestRender();
- it('has the empty state', () => {
expect(findEmptyTagsState().exists()).toBe(true);
});
- it('does not show the loader', () => {
+ it('does not show the loader', async () => {
+ mountComponent({ resolver });
+
+ await waitForApolloRequestRender();
+
expect(findTagsLoader().exists()).toBe(false);
});
- it('does not show the list', () => {
+ it('does not show the list', async () => {
+ mountComponent({ resolver });
+
+ await waitForApolloRequestRender();
+
expect(findTagsList().exists()).toBe(false);
});
});
describe('list', () => {
- beforeEach(() => {
+ it('exists', async () => {
mountComponent();
- });
- it('exists', () => {
+ await waitForApolloRequestRender();
+
expect(findTagsList().exists()).toBe(true);
});
- it('has the correct props bound', () => {
+ it('has the correct props bound', async () => {
+ mountComponent();
+
+ await waitForApolloRequestRender();
+
expect(findTagsList().props()).toMatchObject({
isMobile: false,
- tags: store.state.tags,
+ tags: cleanTags,
});
});
describe('deleteEvent', () => {
describe('single item', () => {
let tagToBeDeleted;
- beforeEach(() => {
- [tagToBeDeleted] = store.state.tags;
+ beforeEach(async () => {
+ mountComponent();
+
+ await waitForApolloRequestRender();
+
+ [tagToBeDeleted] = cleanTags;
findTagsList().vm.$emit('delete', { [tagToBeDeleted.name]: true });
});
- it('open the modal', () => {
+ it('open the modal', async () => {
expect(DeleteModal.methods.show).toHaveBeenCalled();
});
- it('maps the selection to itemToBeDeleted', () => {
- expect(wrapper.vm.itemsToBeDeleted).toEqual([tagToBeDeleted]);
- });
-
it('tracks a single delete event', () => {
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'click_button', {
label: 'registry_tag_delete',
@@ -161,18 +205,18 @@ describe('Details Page', () => {
});
describe('multiple items', () => {
- beforeEach(() => {
- findTagsList().vm.$emit('delete', tagsArrayToSelectedTags(store.state.tags));
+ beforeEach(async () => {
+ mountComponent();
+
+ await waitForApolloRequestRender();
+
+ findTagsList().vm.$emit('delete', tagsArrayToSelectedTags(cleanTags));
});
it('open the modal', () => {
expect(DeleteModal.methods.show).toHaveBeenCalled();
});
- it('maps the selection to itemToBeDeleted', () => {
- expect(wrapper.vm.itemsToBeDeleted).toEqual(store.state.tags);
- });
-
it('tracks a single delete event', () => {
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'click_button', {
label: 'bulk_registry_tag_delete',
@@ -183,40 +227,77 @@ describe('Details Page', () => {
});
describe('pagination', () => {
- beforeEach(() => {
+ it('exists', async () => {
mountComponent();
- });
- it('exists', () => {
+ await waitForApolloRequestRender();
+
expect(findPagination().exists()).toBe(true);
});
- it('is wired to the correct pagination props', () => {
- const pagination = findPagination();
- expect(pagination.props('perPage')).toBe(store.state.tagsPagination.perPage);
- expect(pagination.props('totalItems')).toBe(store.state.tagsPagination.total);
- expect(pagination.props('value')).toBe(store.state.tagsPagination.page);
+ it('is hidden when there are no more pages', async () => {
+ mountComponent({ resolver: jest.fn().mockResolvedValue(graphQLImageDetailsEmptyTagsMock) });
+
+ await waitForApolloRequestRender();
+
+ expect(findPagination().exists()).toBe(false);
});
- it('fetch the data from the API when the v-model changes', () => {
- dispatchSpy.mockResolvedValue();
- findPagination().vm.$emit(GlPagination.model.event, 2);
- expect(store.dispatch).toHaveBeenCalledWith('requestTagsList', {
- page: 2,
+ it('is wired to the correct pagination props', async () => {
+ mountComponent();
+
+ await waitForApolloRequestRender();
+
+ expect(findPagination().props()).toMatchObject({
+ hasNextPage: tagsPageInfo.hasNextPage,
+ hasPreviousPage: tagsPageInfo.hasPreviousPage,
});
});
+
+ it('fetch next page when user clicks next', async () => {
+ const resolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock());
+ mountComponent({ resolver });
+
+ await waitForApolloRequestRender();
+
+ findPagination().vm.$emit('next');
+
+ expect(resolver).toHaveBeenCalledWith(
+ expect.objectContaining({ after: tagsPageInfo.endCursor }),
+ );
+ });
+
+ it('fetch previous page when user clicks prev', async () => {
+ const resolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock());
+ mountComponent({ resolver });
+
+ await waitForApolloRequestRender();
+
+ findPagination().vm.$emit('prev');
+
+ expect(resolver).toHaveBeenCalledWith(
+ expect.objectContaining({ first: null, before: tagsPageInfo.startCursor }),
+ );
+ });
});
describe('modal', () => {
- it('exists', () => {
+ it('exists', async () => {
mountComponent();
+
+ await waitForApolloRequestRender();
+
expect(findDeleteModal().exists()).toBe(true);
});
describe('cancel event', () => {
- it('tracks cancel_delete', () => {
+ it('tracks cancel_delete', async () => {
mountComponent();
+
+ await waitForApolloRequestRender();
+
findDeleteModal().vm.$emit('cancel');
+
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'cancel_delete', {
label: 'registry_tag_delete',
});
@@ -224,45 +305,57 @@ describe('Details Page', () => {
});
describe('confirmDelete event', () => {
+ let mutationResolver;
+
+ beforeEach(() => {
+ mutationResolver = jest.fn().mockResolvedValue(graphQLDeleteImageRepositoryTagsMock);
+ mountComponent({ mutationResolver });
+
+ return waitForApolloRequestRender();
+ });
describe('when one item is selected to be deleted', () => {
- beforeEach(() => {
- mountComponent();
- findTagsList().vm.$emit('delete', { [store.state.tags[0].name]: true });
- });
+ it('calls apollo mutation with the right parameters', async () => {
+ findTagsList().vm.$emit('delete', { [cleanTags[0].name]: true });
+
+ await wrapper.vm.$nextTick();
- it('dispatch requestDeleteTag with the right parameters', () => {
findDeleteModal().vm.$emit('confirmDelete');
- expect(dispatchSpy).toHaveBeenCalledWith('requestDeleteTag', {
- tag: store.state.tags[0],
- });
+
+ expect(mutationResolver).toHaveBeenCalledWith(
+ expect.objectContaining({ tagNames: [cleanTags[0].name] }),
+ );
});
});
describe('when more than one item is selected to be deleted', () => {
- beforeEach(() => {
- mountComponent();
- findTagsList().vm.$emit('delete', tagsArrayToSelectedTags(store.state.tags));
- });
+ it('calls apollo mutation with the right parameters', async () => {
+ findTagsList().vm.$emit('delete', { ...tagsArrayToSelectedTags(tagsMock) });
+
+ await wrapper.vm.$nextTick();
- it('dispatch requestDeleteTags with the right parameters', () => {
findDeleteModal().vm.$emit('confirmDelete');
- expect(dispatchSpy).toHaveBeenCalledWith('requestDeleteTags', {
- ids: store.state.tags.map(t => t.name),
- });
+
+ expect(mutationResolver).toHaveBeenCalledWith(
+ expect.objectContaining({ tagNames: tagsMock.map(t => t.name) }),
+ );
});
});
});
});
describe('Header', () => {
- it('exists', () => {
+ it('exists', async () => {
mountComponent();
+
+ await waitForApolloRequestRender();
expect(findDetailsHeader().exists()).toBe(true);
});
- it('has the correct props', () => {
+ it('has the correct props', async () => {
mountComponent();
- expect(findDetailsHeader().props()).toEqual({ imageName: imageDetailsMock.name });
+
+ await waitForApolloRequestRender();
+ expect(findDetailsHeader().props()).toEqual({ imageName: containerRepositoryMock.name });
});
});
@@ -273,13 +366,15 @@ describe('Details Page', () => {
};
const deleteAlertType = 'success_tag';
- it('exists', () => {
+ it('exists', async () => {
mountComponent();
+
+ await waitForApolloRequestRender();
expect(findDeleteAlert().exists()).toBe(true);
});
- it('has the correct props', () => {
- store.commit(SET_INITIAL_STATE, { ...config });
+ it('has the correct props', async () => {
+ store.commit('SET_INITIAL_STATE', { ...config });
mountComponent({
options: {
data: () => ({
@@ -287,6 +382,9 @@ describe('Details Page', () => {
}),
},
});
+
+ await waitForApolloRequestRender();
+
expect(findDeleteAlert().props()).toEqual({ ...config, deleteAlertType });
});
});
@@ -298,30 +396,40 @@ describe('Details Page', () => {
};
describe('when expiration_policy_started is not null', () => {
+ let resolver;
+
beforeEach(() => {
- store.commit(SET_IMAGE_DETAILS, {
- ...imageDetailsMock,
- cleanup_policy_started_at: Date.now().toString(),
- });
+ resolver = jest.fn().mockResolvedValue(
+ graphQLImageDetailsMock({
+ expirationPolicyStartedAt: Date.now().toString(),
+ }),
+ );
});
- it('exists', () => {
- mountComponent();
+ it('exists', async () => {
+ mountComponent({ resolver });
+
+ await waitForApolloRequestRender();
expect(findPartialCleanupAlert().exists()).toBe(true);
});
- it('has the correct props', () => {
- store.commit(SET_INITIAL_STATE, { ...config });
+ it('has the correct props', async () => {
+ store.commit('SET_INITIAL_STATE', { ...config });
- mountComponent();
+ mountComponent({ resolver });
+
+ await waitForApolloRequestRender();
expect(findPartialCleanupAlert().props()).toEqual({ ...config });
});
it('dismiss hides the component', async () => {
- mountComponent();
+ mountComponent({ resolver });
+
+ await waitForApolloRequestRender();
expect(findPartialCleanupAlert().exists()).toBe(true);
+
findPartialCleanupAlert().vm.$emit('dismiss');
await wrapper.vm.$nextTick();
@@ -331,11 +439,22 @@ describe('Details Page', () => {
});
describe('when expiration_policy_started is null', () => {
- it('the component is hidden', () => {
+ it('the component is hidden', async () => {
mountComponent();
+ await waitForApolloRequestRender();
expect(findPartialCleanupAlert().exists()).toBe(false);
});
});
});
+
+ describe('Breadcrumb connection', () => {
+ it('when the details are fetched updates the name', async () => {
+ mountComponent();
+
+ await waitForApolloRequestRender();
+
+ expect(breadCrumbState.updateName).toHaveBeenCalledWith(containerRepositoryMock.name);
+ });
+ });
});