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/components')
-rw-r--r--spec/frontend/registry/explorer/components/delete_button_spec.js2
-rw-r--r--spec/frontend/registry/explorer/components/delete_image_spec.js152
-rw-r--r--spec/frontend/registry/explorer/components/details_page/delete_alert_spec.js2
-rw-r--r--spec/frontend/registry/explorer/components/details_page/delete_modal_spec.js68
-rw-r--r--spec/frontend/registry/explorer/components/details_page/details_header_spec.js85
-rw-r--r--spec/frontend/registry/explorer/components/details_page/empty_state_spec.js54
-rw-r--r--spec/frontend/registry/explorer/components/details_page/empty_tags_state_spec.js43
-rw-r--r--spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js2
-rw-r--r--spec/frontend/registry/explorer/components/details_page/status_alert_spec.js57
-rw-r--r--spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js10
-rw-r--r--spec/frontend/registry/explorer/components/details_page/tags_list_spec.js32
-rw-r--r--spec/frontend/registry/explorer/components/list_page/cli_commands_spec.js8
-rw-r--r--spec/frontend/registry/explorer/components/list_page/group_empty_state_spec.js6
-rw-r--r--spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js10
-rw-r--r--spec/frontend/registry/explorer/components/list_page/image_list_spec.js2
-rw-r--r--spec/frontend/registry/explorer/components/list_page/project_empty_state_spec.js6
-rw-r--r--spec/frontend/registry/explorer/components/list_page/registry_header_spec.js4
17 files changed, 426 insertions, 117 deletions
diff --git a/spec/frontend/registry/explorer/components/delete_button_spec.js b/spec/frontend/registry/explorer/components/delete_button_spec.js
index cd43e97009b..a557d9afacc 100644
--- a/spec/frontend/registry/explorer/components/delete_button_spec.js
+++ b/spec/frontend/registry/explorer/components/delete_button_spec.js
@@ -1,5 +1,5 @@
-import { shallowMount } from '@vue/test-utils';
import { GlButton } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import component from '~/registry/explorer/components/delete_button.vue';
diff --git a/spec/frontend/registry/explorer/components/delete_image_spec.js b/spec/frontend/registry/explorer/components/delete_image_spec.js
new file mode 100644
index 00000000000..9a0d070e42b
--- /dev/null
+++ b/spec/frontend/registry/explorer/components/delete_image_spec.js
@@ -0,0 +1,152 @@
+import { shallowMount } from '@vue/test-utils';
+import waitForPromises from 'helpers/wait_for_promises';
+import component from '~/registry/explorer/components/delete_image.vue';
+import { GRAPHQL_PAGE_SIZE } from '~/registry/explorer/constants/index';
+import deleteContainerRepositoryMutation from '~/registry/explorer/graphql/mutations/delete_container_repository.mutation.graphql';
+import getContainerRepositoryDetailsQuery from '~/registry/explorer/graphql/queries/get_container_repository_details.query.graphql';
+
+describe('Delete Image', () => {
+ let wrapper;
+ const id = '1';
+ const storeMock = {
+ readQuery: jest.fn().mockReturnValue({
+ containerRepository: {
+ status: 'foo',
+ },
+ }),
+ writeQuery: jest.fn(),
+ };
+
+ const updatePayload = {
+ data: {
+ destroyContainerRepository: {
+ containerRepository: {
+ status: 'baz',
+ },
+ },
+ },
+ };
+
+ const findButton = () => wrapper.find('button');
+
+ const mountComponent = ({
+ propsData = { id },
+ mutate = jest.fn().mockResolvedValue({}),
+ } = {}) => {
+ wrapper = shallowMount(component, {
+ propsData,
+ mocks: {
+ $apollo: {
+ mutate,
+ },
+ },
+ scopedSlots: {
+ default: '<button @click="props.doDelete">test</button>',
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('executes apollo mutate on doDelete', () => {
+ const mutate = jest.fn().mockResolvedValue({});
+ mountComponent({ mutate });
+
+ wrapper.vm.doDelete();
+
+ expect(mutate).toHaveBeenCalledWith({
+ mutation: deleteContainerRepositoryMutation,
+ variables: {
+ id,
+ },
+ update: undefined,
+ });
+ });
+
+ it('on success emits the correct events', async () => {
+ const mutate = jest.fn().mockResolvedValue({});
+ mountComponent({ mutate });
+
+ wrapper.vm.doDelete();
+
+ await waitForPromises();
+
+ expect(wrapper.emitted('start')).toEqual([[]]);
+ expect(wrapper.emitted('success')).toEqual([[]]);
+ expect(wrapper.emitted('end')).toEqual([[]]);
+ });
+
+ it('when a payload contains an error emits an error event', async () => {
+ const mutate = jest
+ .fn()
+ .mockResolvedValue({ data: { destroyContainerRepository: { errors: ['foo'] } } });
+
+ mountComponent({ mutate });
+ wrapper.vm.doDelete();
+
+ await waitForPromises();
+
+ expect(wrapper.emitted('error')).toEqual([[['foo']]]);
+ });
+
+ it('when the api call errors emits an error event', async () => {
+ const mutate = jest.fn().mockRejectedValue('error');
+
+ mountComponent({ mutate });
+ wrapper.vm.doDelete();
+
+ await waitForPromises();
+
+ expect(wrapper.emitted('error')).toEqual([[['error']]]);
+ });
+
+ it('uses the update function, when the prop is set to true', () => {
+ const mutate = jest.fn().mockResolvedValue({});
+
+ mountComponent({ mutate, propsData: { id, useUpdateFn: true } });
+ wrapper.vm.doDelete();
+
+ expect(mutate).toHaveBeenCalledWith({
+ mutation: deleteContainerRepositoryMutation,
+ variables: {
+ id,
+ },
+ update: wrapper.vm.updateImageStatus,
+ });
+ });
+
+ it('updateImage status reads and write to the cache', () => {
+ mountComponent();
+
+ const variables = {
+ id,
+ first: GRAPHQL_PAGE_SIZE,
+ };
+
+ wrapper.vm.updateImageStatus(storeMock, updatePayload);
+
+ expect(storeMock.readQuery).toHaveBeenCalledWith({
+ query: getContainerRepositoryDetailsQuery,
+ variables,
+ });
+ expect(storeMock.writeQuery).toHaveBeenCalledWith({
+ query: getContainerRepositoryDetailsQuery,
+ variables,
+ data: {
+ containerRepository: {
+ status: updatePayload.data.destroyContainerRepository.containerRepository.status,
+ },
+ },
+ });
+ });
+
+ it('binds the doDelete function to the default scoped slot', () => {
+ const mutate = jest.fn().mockResolvedValue({});
+ mountComponent({ mutate });
+ findButton().trigger('click');
+ expect(mutate).toHaveBeenCalled();
+ });
+});
diff --git a/spec/frontend/registry/explorer/components/details_page/delete_alert_spec.js b/spec/frontend/registry/explorer/components/details_page/delete_alert_spec.js
index 6a7fbbe367a..c2a2a4e06ea 100644
--- a/spec/frontend/registry/explorer/components/details_page/delete_alert_spec.js
+++ b/spec/frontend/registry/explorer/components/details_page/delete_alert_spec.js
@@ -1,5 +1,5 @@
-import { shallowMount } from '@vue/test-utils';
import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import component from '~/registry/explorer/components/details_page/delete_alert.vue';
import {
DELETE_TAG_SUCCESS_MESSAGE,
diff --git a/spec/frontend/registry/explorer/components/details_page/delete_modal_spec.js b/spec/frontend/registry/explorer/components/details_page/delete_modal_spec.js
index 636e0a285a6..8fe659694ba 100644
--- a/spec/frontend/registry/explorer/components/details_page/delete_modal_spec.js
+++ b/spec/frontend/registry/explorer/components/details_page/delete_modal_spec.js
@@ -1,9 +1,11 @@
-import { shallowMount } from '@vue/test-utils';
import { GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import component from '~/registry/explorer/components/details_page/delete_modal.vue';
import {
REMOVE_TAG_CONFIRMATION_TEXT,
REMOVE_TAGS_CONFIRMATION_TEXT,
+ DELETE_IMAGE_CONFIRMATION_TITLE,
+ DELETE_IMAGE_CONFIRMATION_TEXT,
} from '~/registry/explorer/constants';
import { GlModal } from '../../stubs';
@@ -35,13 +37,13 @@ describe('Delete Modal', () => {
describe('events', () => {
it.each`
- glEvent | localEvent
- ${'ok'} | ${'confirmDelete'}
- ${'cancel'} | ${'cancelDelete'}
+ glEvent | localEvent
+ ${'primary'} | ${'confirmDelete'}
+ ${'cancel'} | ${'cancelDelete'}
`('GlModal $glEvent emits $localEvent', ({ glEvent, localEvent }) => {
mountComponent();
findModal().vm.$emit(glEvent);
- expect(wrapper.emitted(localEvent)).toBeTruthy();
+ expect(wrapper.emitted(localEvent)).toEqual([[]]);
});
});
@@ -53,27 +55,51 @@ describe('Delete Modal', () => {
});
});
- describe('itemsToBeDeleted contains one element', () => {
- beforeEach(() => {
- mountComponent({ itemsToBeDeleted: [{ path: 'foo' }] });
- });
- it(`has the correct description`, () => {
- expect(findDescription().text()).toBe(REMOVE_TAG_CONFIRMATION_TEXT.replace('%{item}', 'foo'));
+ describe('when we are deleting images', () => {
+ it('has the correct title', () => {
+ mountComponent({ deleteImage: true });
+
+ expect(wrapper.text()).toContain(DELETE_IMAGE_CONFIRMATION_TITLE);
});
- it('has the correct action', () => {
- expect(wrapper.text()).toContain('Remove tag');
+
+ it('has the correct description', () => {
+ mountComponent({ deleteImage: true });
+
+ expect(wrapper.text()).toContain(DELETE_IMAGE_CONFIRMATION_TEXT);
});
});
- describe('itemsToBeDeleted contains more than element', () => {
- beforeEach(() => {
- mountComponent({ itemsToBeDeleted: [{ path: 'foo' }, { path: 'bar' }] });
- });
- it(`has the correct description`, () => {
- expect(findDescription().text()).toBe(REMOVE_TAGS_CONFIRMATION_TEXT.replace('%{item}', '2'));
+ describe('when we are deleting tags', () => {
+ describe('itemsToBeDeleted contains one element', () => {
+ beforeEach(() => {
+ mountComponent({ itemsToBeDeleted: [{ path: 'foo' }] });
+ });
+
+ it(`has the correct description`, () => {
+ expect(findDescription().text()).toBe(
+ REMOVE_TAG_CONFIRMATION_TEXT.replace('%{item}', 'foo'),
+ );
+ });
+
+ it('has the correct title', () => {
+ expect(wrapper.text()).toContain('Remove tag');
+ });
});
- it('has the correct action', () => {
- expect(wrapper.text()).toContain('Remove tags');
+
+ describe('itemsToBeDeleted contains more than element', () => {
+ beforeEach(() => {
+ mountComponent({ itemsToBeDeleted: [{ path: 'foo' }, { path: 'bar' }] });
+ });
+
+ it(`has the correct description`, () => {
+ expect(findDescription().text()).toBe(
+ REMOVE_TAGS_CONFIRMATION_TEXT.replace('%{item}', '2'),
+ );
+ });
+
+ it('has the correct title', () => {
+ expect(wrapper.text()).toContain('Remove tags');
+ });
});
});
});
diff --git a/spec/frontend/registry/explorer/components/details_page/details_header_spec.js b/spec/frontend/registry/explorer/components/details_page/details_header_spec.js
index 337235e3de5..3fa3a2ae1de 100644
--- a/spec/frontend/registry/explorer/components/details_page/details_header_spec.js
+++ b/spec/frontend/registry/explorer/components/details_page/details_header_spec.js
@@ -1,7 +1,6 @@
+import { GlSprintf, GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import { GlSprintf } from '@gitlab/ui';
import { useFakeDate } from 'helpers/fake_date';
-import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import component from '~/registry/explorer/components/details_page/details_header.vue';
import {
DETAILS_PAGE_TITLE,
@@ -15,6 +14,7 @@ import {
CLEANUP_ONGOING_TOOLTIP,
CLEANUP_UNFINISHED_TOOLTIP,
} from '~/registry/explorer/constants';
+import TitleArea from '~/vue_shared/components/registry/title_area.vue';
describe('Details Header', () => {
let wrapper;
@@ -23,6 +23,7 @@ describe('Details Header', () => {
name: 'foo',
updatedAt: '2020-11-03T13:29:21Z',
tagsCount: 10,
+ canDelete: true,
project: {
visibility: 'public',
containerExpirationPolicy: {
@@ -36,8 +37,10 @@ describe('Details Header', () => {
const findByTestId = (testId) => wrapper.find(`[data-testid="${testId}"]`);
const findLastUpdatedAndVisibility = () => findByTestId('updated-and-visibility');
+ const findTitle = () => findByTestId('title');
const findTagsCount = () => findByTestId('tags-count');
const findCleanup = () => findByTestId('cleanup');
+ const findDeleteButton = () => wrapper.find(GlButton);
const waitForMetadataItems = async () => {
// Metadata items are printed by a loop in the title-area and it takes two ticks for them to be available
@@ -45,11 +48,9 @@ describe('Details Header', () => {
await wrapper.vm.$nextTick();
};
- const mountComponent = (image = defaultImage) => {
+ const mountComponent = (propsData = { image: defaultImage }) => {
wrapper = shallowMount(component, {
- propsData: {
- image,
- },
+ propsData,
stubs: {
GlSprintf,
TitleArea,
@@ -63,13 +64,65 @@ describe('Details Header', () => {
});
it('has the correct title ', () => {
- mountComponent({ ...defaultImage, name: '' });
- expect(wrapper.text()).toMatchInterpolatedText(DETAILS_PAGE_TITLE);
+ mountComponent({ image: { ...defaultImage, name: '' } });
+ expect(findTitle().text()).toMatchInterpolatedText(DETAILS_PAGE_TITLE);
});
it('shows imageName in the title', () => {
mountComponent();
- expect(wrapper.text()).toContain('foo');
+ expect(findTitle().text()).toContain('foo');
+ });
+
+ describe('delete button', () => {
+ it('exists', () => {
+ mountComponent();
+
+ expect(findDeleteButton().exists()).toBe(true);
+ });
+
+ it('is hidden while loading', () => {
+ mountComponent({ image: defaultImage, metadataLoading: true });
+
+ expect(findDeleteButton().exists()).toBe(false);
+ });
+
+ it('has the correct text', () => {
+ mountComponent();
+
+ expect(findDeleteButton().text()).toBe('Delete');
+ });
+
+ it('has the correct props', () => {
+ mountComponent();
+
+ expect(findDeleteButton().props()).toMatchObject({
+ variant: 'danger',
+ disabled: false,
+ });
+ });
+
+ it('emits the correct event', () => {
+ mountComponent();
+
+ findDeleteButton().vm.$emit('click');
+
+ expect(wrapper.emitted('delete')).toEqual([[]]);
+ });
+
+ it.each`
+ canDelete | disabled | isDisabled
+ ${true} | ${false} | ${false}
+ ${true} | ${true} | ${true}
+ ${false} | ${false} | ${true}
+ ${false} | ${true} | ${true}
+ `(
+ 'when canDelete is $canDelete and disabled is $disabled is $isDisabled that the button is disabled',
+ ({ canDelete, disabled, isDisabled }) => {
+ mountComponent({ image: { ...defaultImage, canDelete }, disabled });
+
+ expect(findDeleteButton().props('disabled')).toBe(isDisabled);
+ },
+ );
});
describe('metadata items', () => {
@@ -82,7 +135,7 @@ describe('Details Header', () => {
});
it('when there is one tag has the correct text', async () => {
- mountComponent({ ...defaultImage, tagsCount: 1 });
+ mountComponent({ image: { ...defaultImage, tagsCount: 1 } });
await waitForMetadataItems();
expect(findTagsCount().props('text')).toBe('1 tag');
@@ -124,10 +177,12 @@ describe('Details Header', () => {
'when the status is $status the text is $text and the tooltip is $tooltip',
async ({ status, text, tooltip }) => {
mountComponent({
- ...defaultImage,
- expirationPolicyCleanupStatus: status,
- project: {
- containerExpirationPolicy: { enabled: true, nextRunAt: '2021-01-03T14:29:21Z' },
+ image: {
+ ...defaultImage,
+ expirationPolicyCleanupStatus: status,
+ project: {
+ containerExpirationPolicy: { enabled: true, nextRunAt: '2021-01-03T14:29:21Z' },
+ },
},
});
await waitForMetadataItems();
@@ -156,7 +211,7 @@ describe('Details Header', () => {
expect(findLastUpdatedAndVisibility().props('icon')).toBe('eye');
});
it('shows an eye slashed when the project is not public', async () => {
- mountComponent({ ...defaultImage, project: { visibility: 'private' } });
+ mountComponent({ image: { ...defaultImage, project: { visibility: 'private' } } });
await waitForMetadataItems();
expect(findLastUpdatedAndVisibility().props('icon')).toBe('eye-slash');
diff --git a/spec/frontend/registry/explorer/components/details_page/empty_state_spec.js b/spec/frontend/registry/explorer/components/details_page/empty_state_spec.js
new file mode 100644
index 00000000000..14b15945631
--- /dev/null
+++ b/spec/frontend/registry/explorer/components/details_page/empty_state_spec.js
@@ -0,0 +1,54 @@
+import { GlEmptyState } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import component from '~/registry/explorer/components/details_page/empty_state.vue';
+import {
+ NO_TAGS_TITLE,
+ NO_TAGS_MESSAGE,
+ MISSING_OR_DELETED_IMAGE_TITLE,
+ MISSING_OR_DELETED_IMAGE_MESSAGE,
+} from '~/registry/explorer/constants';
+
+describe('EmptyTagsState component', () => {
+ let wrapper;
+
+ const findEmptyState = () => wrapper.find(GlEmptyState);
+
+ const mountComponent = (propsData) => {
+ wrapper = shallowMount(component, {
+ stubs: {
+ GlEmptyState,
+ },
+ propsData,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('contains gl-empty-state', () => {
+ mountComponent();
+ expect(findEmptyState().exists()).toBe(true);
+ });
+
+ it.each`
+ isEmptyImage | title | description
+ ${false} | ${NO_TAGS_TITLE} | ${NO_TAGS_MESSAGE}
+ ${true} | ${MISSING_OR_DELETED_IMAGE_TITLE} | ${MISSING_OR_DELETED_IMAGE_MESSAGE}
+ `(
+ 'when isEmptyImage is $isEmptyImage has the correct props',
+ ({ isEmptyImage, title, description }) => {
+ mountComponent({
+ noContainersImage: 'foo',
+ isEmptyImage,
+ });
+
+ expect(findEmptyState().props()).toMatchObject({
+ title,
+ description,
+ svgPath: 'foo',
+ });
+ },
+ );
+});
diff --git a/spec/frontend/registry/explorer/components/details_page/empty_tags_state_spec.js b/spec/frontend/registry/explorer/components/details_page/empty_tags_state_spec.js
deleted file mode 100644
index 09afd9d2d84..00000000000
--- a/spec/frontend/registry/explorer/components/details_page/empty_tags_state_spec.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlEmptyState } from '@gitlab/ui';
-import component from '~/registry/explorer/components/details_page/empty_tags_state.vue';
-import {
- EMPTY_IMAGE_REPOSITORY_TITLE,
- EMPTY_IMAGE_REPOSITORY_MESSAGE,
-} from '~/registry/explorer/constants';
-
-describe('EmptyTagsState component', () => {
- let wrapper;
-
- const findEmptyState = () => wrapper.find(GlEmptyState);
-
- const mountComponent = () => {
- wrapper = shallowMount(component, {
- stubs: {
- GlEmptyState,
- },
- propsData: {
- noContainersImage: 'foo',
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- it('contains gl-empty-state', () => {
- mountComponent();
- expect(findEmptyState().exists()).toBe(true);
- });
-
- it('has the correct props', () => {
- mountComponent();
- expect(findEmptyState().props()).toMatchObject({
- title: EMPTY_IMAGE_REPOSITORY_TITLE,
- description: EMPTY_IMAGE_REPOSITORY_MESSAGE,
- svgPath: 'foo',
- });
- });
-});
diff --git a/spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js b/spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js
index 17821d8be31..af8a23e412c 100644
--- a/spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js
+++ b/spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js
@@ -1,5 +1,5 @@
-import { shallowMount } from '@vue/test-utils';
import { GlAlert, GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import component from '~/registry/explorer/components/details_page/partial_cleanup_alert.vue';
import { DELETE_ALERT_TITLE, DELETE_ALERT_LINK_TEXT } from '~/registry/explorer/constants';
diff --git a/spec/frontend/registry/explorer/components/details_page/status_alert_spec.js b/spec/frontend/registry/explorer/components/details_page/status_alert_spec.js
new file mode 100644
index 00000000000..b079883cefd
--- /dev/null
+++ b/spec/frontend/registry/explorer/components/details_page/status_alert_spec.js
@@ -0,0 +1,57 @@
+import { GlLink, GlSprintf, GlAlert } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import component from '~/registry/explorer/components/details_page/status_alert.vue';
+import {
+ DELETE_SCHEDULED,
+ DELETE_FAILED,
+ PACKAGE_DELETE_HELP_PAGE_PATH,
+ SCHEDULED_FOR_DELETION_STATUS_TITLE,
+ SCHEDULED_FOR_DELETION_STATUS_MESSAGE,
+ FAILED_DELETION_STATUS_TITLE,
+ FAILED_DELETION_STATUS_MESSAGE,
+} from '~/registry/explorer/constants';
+
+describe('Status Alert', () => {
+ let wrapper;
+
+ const findLink = () => wrapper.find(GlLink);
+ const findAlert = () => wrapper.find(GlAlert);
+ const findMessage = () => wrapper.find('[data-testid="message"]');
+
+ const mountComponent = (propsData) => {
+ wrapper = shallowMount(component, {
+ propsData,
+ stubs: {
+ GlSprintf,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it.each`
+ status | title | variant | message | link
+ ${DELETE_SCHEDULED} | ${SCHEDULED_FOR_DELETION_STATUS_TITLE} | ${'info'} | ${SCHEDULED_FOR_DELETION_STATUS_MESSAGE} | ${PACKAGE_DELETE_HELP_PAGE_PATH}
+ ${DELETE_FAILED} | ${FAILED_DELETION_STATUS_TITLE} | ${'warning'} | ${FAILED_DELETION_STATUS_MESSAGE} | ${''}
+ `(
+ `when the status is $status, title is $title, variant is $variant, message is $message and the link is $link`,
+ ({ status, title, variant, message, link }) => {
+ mountComponent({ status });
+
+ expect(findMessage().text()).toMatchInterpolatedText(message);
+ expect(findAlert().props()).toMatchObject({
+ title,
+ variant,
+ });
+ if (link) {
+ expect(findLink().attributes()).toMatchObject({
+ target: '_blank',
+ href: link,
+ });
+ }
+ },
+ );
+});
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 c2efc71c159..8b70f84c1bd 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
@@ -1,12 +1,9 @@
-import { shallowMount } from '@vue/test-utils';
import { GlFormCheckbox, GlSprintf, GlIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import component from '~/registry/explorer/components/details_page/tags_list_row.vue';
import DeleteButton from '~/registry/explorer/components/delete_button.vue';
-import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
+import component from '~/registry/explorer/components/details_page/tags_list_row.vue';
import {
REMOVE_TAG_BUTTON_TITLE,
REMOVE_TAG_BUTTON_DISABLE_TOOLTIP,
@@ -14,6 +11,9 @@ import {
NOT_AVAILABLE_TEXT,
NOT_AVAILABLE_SIZE,
} from '~/registry/explorer/constants/index';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { tagsMock } from '../../mock_data';
import { ListItem } from '../../stubs';
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 413795a7a57..dc6760a17bd 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
@@ -1,5 +1,5 @@
-import { shallowMount } from '@vue/test-utils';
import { GlButton } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import component from '~/registry/explorer/components/details_page/tags_list.vue';
import TagsListRow from '~/registry/explorer/components/details_page/tags_list_row.vue';
import { TAGS_LIST_TITLE, REMOVE_TAGS_BUTTON_TITLE } from '~/registry/explorer/constants/index';
@@ -70,18 +70,25 @@ describe('Tags List', () => {
});
});
- it('is disabled when no item is selected', () => {
- mountComponent();
+ it.each`
+ disabled | doSelect | buttonDisabled
+ ${true} | ${false} | ${'true'}
+ ${true} | ${true} | ${'true'}
+ ${false} | ${false} | ${'true'}
+ ${false} | ${true} | ${undefined}
+ `(
+ 'is $buttonDisabled that the button is disabled when the component disabled state is $disabled and is $doSelect that the user selected a tag',
+ async ({ disabled, buttonDisabled, doSelect }) => {
+ mountComponent({ tags, disabled, isMobile: false });
- expect(findDeleteButton().attributes('disabled')).toBe('true');
- });
+ if (doSelect) {
+ findTagsListRow().at(0).vm.$emit('select');
+ await wrapper.vm.$nextTick();
+ }
- it('is enabled when at least one item is selected', async () => {
- mountComponent();
- findTagsListRow().at(0).vm.$emit('select');
- await wrapper.vm.$nextTick();
- expect(findDeleteButton().attributes('disabled')).toBe(undefined);
- });
+ expect(findDeleteButton().attributes('disabled')).toBe(buttonDisabled);
+ },
+ );
it('click event emits a deleted event with selected items', () => {
mountComponent();
@@ -100,12 +107,13 @@ describe('Tags List', () => {
});
it('the correct props are bound to it', () => {
- mountComponent();
+ mountComponent({ tags, disabled: true });
const rows = findTagsListRow();
expect(rows.at(0).attributes()).toMatchObject({
first: 'true',
+ disabled: 'true',
});
});
diff --git a/spec/frontend/registry/explorer/components/list_page/cli_commands_spec.js b/spec/frontend/registry/explorer/components/list_page/cli_commands_spec.js
index 74b9ea5fd96..8ca8fca65ed 100644
--- a/spec/frontend/registry/explorer/components/list_page/cli_commands_spec.js
+++ b/spec/frontend/registry/explorer/components/list_page/cli_commands_spec.js
@@ -1,9 +1,7 @@
-import Vuex from 'vuex';
-import { mount, createLocalVue } from '@vue/test-utils';
import { GlDropdown } from '@gitlab/ui';
-import Tracking from '~/tracking';
+import { mount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
import QuickstartDropdown from '~/registry/explorer/components/list_page/cli_commands.vue';
-import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
import {
QUICK_START,
LOGIN_COMMAND_LABEL,
@@ -13,6 +11,8 @@ import {
PUSH_COMMAND_LABEL,
COPY_PUSH_TITLE,
} from '~/registry/explorer/constants';
+import Tracking from '~/tracking';
+import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
import { dockerCommands } from '../../mock_data';
diff --git a/spec/frontend/registry/explorer/components/list_page/group_empty_state_spec.js b/spec/frontend/registry/explorer/components/list_page/group_empty_state_spec.js
index 1ba2036dc34..989a60625e2 100644
--- a/spec/frontend/registry/explorer/components/list_page/group_empty_state_spec.js
+++ b/spec/frontend/registry/explorer/components/list_page/group_empty_state_spec.js
@@ -1,8 +1,8 @@
-import Vuex from 'vuex';
-import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlSprintf } from '@gitlab/ui';
-import { GlEmptyState } from '../../stubs';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
import groupEmptyState from '~/registry/explorer/components/list_page/group_empty_state.vue';
+import { GlEmptyState } from '../../stubs';
const localVue = createLocalVue();
localVue.use(Vuex);
diff --git a/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js b/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js
index a06c4795b2e..d6ee871341b 100644
--- a/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js
+++ b/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js
@@ -1,11 +1,9 @@
-import { shallowMount } from '@vue/test-utils';
import { GlIcon, GlSprintf, GlSkeletonLoader } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-import Component from '~/registry/explorer/components/list_page/image_list_row.vue';
-import ListItem from '~/vue_shared/components/registry/list_item.vue';
import DeleteButton from '~/registry/explorer/components/delete_button.vue';
+import Component from '~/registry/explorer/components/list_page/image_list_row.vue';
import {
ROW_SCHEDULED_FOR_DELETION,
LIST_DELETE_BUTTON_DISABLED,
@@ -15,8 +13,10 @@ import {
IMAGE_DELETE_SCHEDULED_STATUS,
IMAGE_FAILED_DELETED_STATUS,
} from '~/registry/explorer/constants';
-import { RouterLink } from '../../stubs';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { imagesListResponse } from '../../mock_data';
+import { RouterLink } from '../../stubs';
describe('Image List Row', () => {
let wrapper;
diff --git a/spec/frontend/registry/explorer/components/list_page/image_list_spec.js b/spec/frontend/registry/explorer/components/list_page/image_list_spec.js
index 61c362f4d78..d7dd825ca3e 100644
--- a/spec/frontend/registry/explorer/components/list_page/image_list_spec.js
+++ b/spec/frontend/registry/explorer/components/list_page/image_list_spec.js
@@ -1,5 +1,5 @@
-import { shallowMount } from '@vue/test-utils';
import { GlKeysetPagination } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import Component from '~/registry/explorer/components/list_page/image_list.vue';
import ImageListRow from '~/registry/explorer/components/list_page/image_list_row.vue';
diff --git a/spec/frontend/registry/explorer/components/list_page/project_empty_state_spec.js b/spec/frontend/registry/explorer/components/list_page/project_empty_state_spec.js
index 3a27cf1923c..111aa45f231 100644
--- a/spec/frontend/registry/explorer/components/list_page/project_empty_state_spec.js
+++ b/spec/frontend/registry/explorer/components/list_page/project_empty_state_spec.js
@@ -1,9 +1,9 @@
-import Vuex from 'vuex';
-import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlSprintf } from '@gitlab/ui';
-import { GlEmptyState } from '../../stubs';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
import projectEmptyState from '~/registry/explorer/components/list_page/project_empty_state.vue';
import { dockerCommands } from '../../mock_data';
+import { GlEmptyState } from '../../stubs';
const localVue = createLocalVue();
localVue.use(Vuex);
diff --git a/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js b/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js
index 58439c185e3..07256d2bbf5 100644
--- a/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js
+++ b/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js
@@ -1,13 +1,13 @@
-import { shallowMount } from '@vue/test-utils';
import { GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import Component from '~/registry/explorer/components/list_page/registry_header.vue';
-import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import {
CONTAINER_REGISTRY_TITLE,
LIST_INTRO_TEXT,
EXPIRATION_POLICY_DISABLED_MESSAGE,
EXPIRATION_POLICY_DISABLED_TEXT,
} from '~/registry/explorer/constants';
+import TitleArea from '~/vue_shared/components/registry/title_area.vue';
jest.mock('~/lib/utils/datetime_utility', () => ({
approximateDuration: jest.fn(),