Commit 7af59bce authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera Committed by Kushal Pandya

Add warning icon and tooltip on errored packages

parent 3c832e79
<script> <script>
import { GlButton, GlLink, GlSprintf, GlTooltipDirective, GlTruncate } from '@gitlab/ui'; import { GlButton, GlLink, GlSprintf, GlTooltipDirective, GlTruncate } from '@gitlab/ui';
import { s__ } from '~/locale';
import ListItem from '~/vue_shared/components/registry/list_item.vue'; import ListItem from '~/vue_shared/components/registry/list_item.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago'; import timeagoMixin from '~/vue_shared/mixins/timeago';
import { PACKAGE_ERROR_STATUS, PACKAGE_DEFAULT_STATUS } from '../constants';
import { getPackageTypeLabel } from '../utils'; import { getPackageTypeLabel } from '../utils';
import PackagePath from './package_path.vue'; import PackagePath from './package_path.vue';
import PackageTags from './package_tags.vue'; import PackageTags from './package_tags.vue';
...@@ -70,22 +72,45 @@ export default { ...@@ -70,22 +72,45 @@ export default {
hasProjectLink() { hasProjectLink() {
return Boolean(this.packageEntity.project_path); return Boolean(this.packageEntity.project_path);
}, },
showWarningIcon() {
return this.packageEntity.status === PACKAGE_ERROR_STATUS;
},
disabledRow() {
return this.packageEntity.status && this.packageEntity.status !== PACKAGE_DEFAULT_STATUS;
},
disabledDeleteButton() {
return this.disabledRow || !this.packageEntity._links.delete_api_path;
},
},
i18n: {
erroredPackageText: s__('PackageRegistry|Invalid Package: failed metadata extraction'),
}, },
}; };
</script> </script>
<template> <template>
<list-item data-qa-selector="package_row"> <list-item data-qa-selector="package_row" :disabled="disabledRow">
<template #left-primary> <template #left-primary>
<div class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0"> <div class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0">
<gl-link <gl-link
:href="packageLink" :href="packageLink"
class="gl-text-body gl-min-w-0" class="gl-text-body gl-min-w-0"
data-qa-selector="package_link" data-qa-selector="package_link"
:disabled="disabledRow"
> >
<gl-truncate :text="packageEntity.name" /> <gl-truncate :text="packageEntity.name" />
</gl-link> </gl-link>
<gl-button
v-if="showWarningIcon"
v-gl-tooltip="{ title: $options.i18n.erroredPackageText }"
class="gl-hover-bg-transparent!"
icon="warning"
category="tertiary"
data-testid="warning-icon"
:aria-label="__('Warning')"
/>
<package-tags <package-tags
v-if="packageEntity.tags && packageEntity.tags.length" v-if="packageEntity.tags && packageEntity.tags.length"
class="gl-ml-3" class="gl-ml-3"
...@@ -109,7 +134,11 @@ export default { ...@@ -109,7 +134,11 @@ export default {
{{ packageType }} {{ packageType }}
</component> </component>
<package-path v-if="hasProjectLink" :path="packageEntity.project_path" /> <package-path
v-if="hasProjectLink"
:path="packageEntity.project_path"
:disabled="disabledRow"
/>
</div> </div>
</template> </template>
...@@ -137,7 +166,7 @@ export default { ...@@ -137,7 +166,7 @@ export default {
variant="danger" variant="danger"
:title="s__('PackageRegistry|Remove package')" :title="s__('PackageRegistry|Remove package')"
:aria-label="s__('PackageRegistry|Remove package')" :aria-label="s__('PackageRegistry|Remove package')"
:disabled="!packageEntity._links.delete_api_path" :disabled="disabledDeleteButton"
@click="$emit('packageToDelete', packageEntity)" @click="$emit('packageToDelete', packageEntity)"
/> />
</template> </template>
......
...@@ -16,6 +16,11 @@ export default { ...@@ -16,6 +16,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
disabled: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
pathPieces() { pathPieces() {
...@@ -45,7 +50,12 @@ export default { ...@@ -45,7 +50,12 @@ export default {
<div data-qa-selector="package-path" class="gl-display-flex gl-align-items-center"> <div data-qa-selector="package-path" class="gl-display-flex gl-align-items-center">
<gl-icon data-testid="base-icon" name="project" class="gl-mx-3 gl-min-w-0" /> <gl-icon data-testid="base-icon" name="project" class="gl-mx-3 gl-min-w-0" />
<gl-link data-testid="root-link" class="gl-text-gray-500 gl-min-w-0" :href="`/${rootLink}`"> <gl-link
data-testid="root-link"
class="gl-text-gray-500 gl-min-w-0"
:href="`/${rootLink}`"
:disabled="disabled"
>
{{ root }} {{ root }}
</gl-link> </gl-link>
...@@ -63,7 +73,12 @@ export default { ...@@ -63,7 +73,12 @@ export default {
<gl-icon data-testid="ellipsis-chevron" name="chevron-right" class="gl-mx-2 gl-min-w-0" /> <gl-icon data-testid="ellipsis-chevron" name="chevron-right" class="gl-mx-2 gl-min-w-0" />
</template> </template>
<gl-link data-testid="leaf-link" class="gl-text-gray-500 gl-min-w-0" :href="`/${path}`"> <gl-link
data-testid="leaf-link"
class="gl-text-gray-500 gl-min-w-0"
:href="`/${path}`"
:disabled="disabled"
>
{{ leaf }} {{ leaf }}
</gl-link> </gl-link>
</template> </template>
......
...@@ -26,3 +26,8 @@ export const TrackingCategories = { ...@@ -26,3 +26,8 @@ export const TrackingCategories = {
export const SHOW_DELETE_SUCCESS_ALERT = 'showSuccessDeleteAlert'; export const SHOW_DELETE_SUCCESS_ALERT = 'showSuccessDeleteAlert';
export const DELETE_PACKAGE_ERROR_MESSAGE = __('Something went wrong while deleting the package.'); export const DELETE_PACKAGE_ERROR_MESSAGE = __('Something went wrong while deleting the package.');
export const PACKAGE_ERROR_STATUS = 'error';
export const PACKAGE_DEFAULT_STATUS = 'default';
export const PACKAGE_HIDDEN_STATUS = 'hidden';
export const PACKAGE_PROCESSING_STATUS = 'processing';
...@@ -50,6 +50,11 @@ export default { ...@@ -50,6 +50,11 @@ export default {
default: false, default: false,
required: false, required: false,
}, },
disabled: {
type: Boolean,
default: false,
required: false,
},
}, },
i18n: { i18n: {
REMOVE_TAG_BUTTON_TITLE, REMOVE_TAG_BUTTON_TITLE,
...@@ -92,19 +97,25 @@ export default { ...@@ -92,19 +97,25 @@ export default {
tagLocation() { tagLocation() {
return this.tag.path?.replace(`:${this.tag.name}`, ''); return this.tag.path?.replace(`:${this.tag.name}`, '');
}, },
invalidTag() { isInvalidTag() {
return !this.tag.digest; return !this.tag.digest;
}, },
isCheckboxDisabled() {
return this.isInvalidTag || this.disabled;
},
isDeleteDisabled() {
return this.isInvalidTag || this.disabled || !this.tag.canDelete;
},
}, },
}; };
</script> </script>
<template> <template>
<list-item v-bind="$attrs" :selected="selected"> <list-item v-bind="$attrs" :selected="selected" :disabled="disabled">
<template #left-action> <template #left-action>
<gl-form-checkbox <gl-form-checkbox
v-if="tag.canDelete" v-if="tag.canDelete"
:disabled="invalidTag" :disabled="isCheckboxDisabled"
class="gl-m-0" class="gl-m-0"
:checked="selected" :checked="selected"
@change="$emit('select')" @change="$emit('select')"
...@@ -126,10 +137,11 @@ export default { ...@@ -126,10 +137,11 @@ export default {
:title="tag.location" :title="tag.location"
:text="tag.location" :text="tag.location"
category="tertiary" category="tertiary"
:disabled="disabled"
/> />
<gl-icon <gl-icon
v-if="invalidTag" v-if="isInvalidTag"
v-gl-tooltip="{ title: $options.i18n.MISSING_MANIFEST_WARNING_TOOLTIP }" v-gl-tooltip="{ title: $options.i18n.MISSING_MANIFEST_WARNING_TOOLTIP }"
name="warning" name="warning"
class="gl-text-orange-500 gl-mb-2 gl-ml-2" class="gl-text-orange-500 gl-mb-2 gl-ml-2"
...@@ -162,7 +174,7 @@ export default { ...@@ -162,7 +174,7 @@ export default {
</template> </template>
<template #right-action> <template #right-action>
<delete-button <delete-button
:disabled="!tag.canDelete || invalidTag" :disabled="isDeleteDisabled"
:title="$options.i18n.REMOVE_TAG_BUTTON_TITLE" :title="$options.i18n.REMOVE_TAG_BUTTON_TITLE"
:tooltip-title="$options.i18n.REMOVE_TAG_BUTTON_DISABLE_TOOLTIP" :tooltip-title="$options.i18n.REMOVE_TAG_BUTTON_DISABLE_TOOLTIP"
:tooltip-disabled="tag.canDelete" :tooltip-disabled="tag.canDelete"
...@@ -172,7 +184,7 @@ export default { ...@@ -172,7 +184,7 @@ export default {
/> />
</template> </template>
<template v-if="!invalidTag" #details-published> <template v-if="!isInvalidTag" #details-published>
<details-row icon="clock" data-testid="published-date-detail"> <details-row icon="clock" data-testid="published-date-detail">
<gl-sprintf :message="$options.i18n.PUBLISHED_DETAILS_ROW_TEXT"> <gl-sprintf :message="$options.i18n.PUBLISHED_DETAILS_ROW_TEXT">
<template #repositoryPath> <template #repositoryPath>
...@@ -187,7 +199,7 @@ export default { ...@@ -187,7 +199,7 @@ export default {
</gl-sprintf> </gl-sprintf>
</details-row> </details-row>
</template> </template>
<template v-if="!invalidTag" #details-manifest-digest> <template v-if="!isInvalidTag" #details-manifest-digest>
<details-row icon="log" data-testid="manifest-detail"> <details-row icon="log" data-testid="manifest-detail">
<gl-sprintf :message="$options.i18n.MANIFEST_DETAILS_ROW_TEST"> <gl-sprintf :message="$options.i18n.MANIFEST_DETAILS_ROW_TEST">
<template #digest> <template #digest>
...@@ -200,10 +212,11 @@ export default { ...@@ -200,10 +212,11 @@ export default {
:text="tag.digest" :text="tag.digest"
category="tertiary" category="tertiary"
size="small" size="small"
:disabled="disabled"
/> />
</details-row> </details-row>
</template> </template>
<template v-if="!invalidTag" #details-configuration-digest> <template v-if="!isInvalidTag" #details-configuration-digest>
<details-row icon="cloud-gear" data-testid="configuration-detail"> <details-row icon="cloud-gear" data-testid="configuration-detail">
<gl-sprintf :message="$options.i18n.CONFIGURATION_DETAILS_ROW_TEST"> <gl-sprintf :message="$options.i18n.CONFIGURATION_DETAILS_ROW_TEST">
<template #digest> <template #digest>
...@@ -216,6 +229,7 @@ export default { ...@@ -216,6 +229,7 @@ export default {
:text="formattedRevision" :text="formattedRevision"
category="tertiary" category="tertiary"
size="small" size="small"
:disabled="disabled"
/> />
</details-row> </details-row>
</template> </template>
......
...@@ -78,6 +78,9 @@ export default { ...@@ -78,6 +78,9 @@ export default {
imageName() { imageName() {
return this.item.name ? this.item.path : `${this.item.path}/ ${ROOT_IMAGE_TEXT}`; return this.item.name ? this.item.path : `${this.item.path}/ ${ROOT_IMAGE_TEXT}`;
}, },
routerLinkEvent() {
return this.deleting ? '' : 'click';
},
}, },
}; };
</script> </script>
...@@ -97,6 +100,7 @@ export default { ...@@ -97,6 +100,7 @@ export default {
class="gl-text-body gl-font-weight-bold" class="gl-text-body gl-font-weight-bold"
data-testid="details-link" data-testid="details-link"
data-qa-selector="registry_image_content" data-qa-selector="registry_image_content"
:event="routerLinkEvent"
:to="{ name: 'details', params: { id } }" :to="{ name: 'details', params: { id } }"
> >
{{ imageName }} {{ imageName }}
......
...@@ -32,7 +32,7 @@ export default { ...@@ -32,7 +32,7 @@ export default {
return { return {
'gl-border-t-transparent': !this.first && !this.selected, 'gl-border-t-transparent': !this.first && !this.selected,
'gl-border-t-gray-100': this.first && !this.selected, 'gl-border-t-gray-100': this.first && !this.selected,
'disabled-content': this.disabled, 'gl-opacity-5': this.disabled,
'gl-border-b-gray-100': !this.selected, 'gl-border-b-gray-100': !this.selected,
'gl-bg-blue-50 gl-border-blue-200': this.selected, 'gl-bg-blue-50 gl-border-blue-200': this.selected,
}; };
......
...@@ -23359,6 +23359,9 @@ msgstr "" ...@@ -23359,6 +23359,9 @@ msgstr ""
msgid "PackageRegistry|Install package version" msgid "PackageRegistry|Install package version"
msgstr "" msgstr ""
msgid "PackageRegistry|Invalid Package: failed metadata extraction"
msgstr ""
msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab." msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab."
msgstr "" msgstr ""
......
...@@ -34,6 +34,8 @@ exports[`packages_list_row renders 1`] = ` ...@@ -34,6 +34,8 @@ exports[`packages_list_row renders 1`] = `
</gl-link-stub> </gl-link-stub>
<!----> <!---->
<!---->
</div> </div>
<!----> <!---->
......
import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import PackagesListRow from '~/packages/shared/components/package_list_row.vue'; import PackagesListRow from '~/packages/shared/components/package_list_row.vue';
import PackagePath from '~/packages/shared/components/package_path.vue'; import PackagePath from '~/packages/shared/components/package_path.vue';
import PackageTags from '~/packages/shared/components/package_tags.vue'; import PackageTags from '~/packages/shared/components/package_tags.vue';
import { PACKAGE_ERROR_STATUS } from '~/packages/shared/constants';
import ListItem from '~/vue_shared/components/registry/list_item.vue'; import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { packageList } from '../../mock_data'; import { packageList } from '../../mock_data';
...@@ -20,7 +23,10 @@ describe('packages_list_row', () => { ...@@ -20,7 +23,10 @@ describe('packages_list_row', () => {
const findPackagePath = () => wrapper.find(PackagePath); const findPackagePath = () => wrapper.find(PackagePath);
const findDeleteButton = () => wrapper.find('[data-testid="action-delete"]'); const findDeleteButton = () => wrapper.find('[data-testid="action-delete"]');
const findPackageIconAndName = () => wrapper.find(PackageIconAndName); const findPackageIconAndName = () => wrapper.find(PackageIconAndName);
const findInfrastructureIconAndName = () => wrapper.find(InfrastructureIconAndName); const findInfrastructureIconAndName = () => wrapper.findComponent(InfrastructureIconAndName);
const findListItem = () => wrapper.findComponent(ListItem);
const findPackageLink = () => wrapper.findComponent(GlLink);
const findWarningIcon = () => wrapper.find('[data-testid="warning-icon"]');
const mountComponent = ({ const mountComponent = ({
isGroup = false, isGroup = false,
...@@ -44,6 +50,9 @@ describe('packages_list_row', () => { ...@@ -44,6 +50,9 @@ describe('packages_list_row', () => {
showPackageType, showPackageType,
disableDelete, disableDelete,
}, },
directives: {
GlTooltip: createMockDirective(),
},
}); });
}; };
...@@ -146,4 +155,31 @@ describe('packages_list_row', () => { ...@@ -146,4 +155,31 @@ describe('packages_list_row', () => {
expect(findInfrastructureIconAndName().exists()).toBe(true); expect(findInfrastructureIconAndName().exists()).toBe(true);
}); });
}); });
describe(`when the package is in ${PACKAGE_ERROR_STATUS} status`, () => {
beforeEach(() => {
mountComponent({ packageEntity: { ...packageWithoutTags, status: PACKAGE_ERROR_STATUS } });
});
it('list item has a disabled prop', () => {
expect(findListItem().props('disabled')).toBe(true);
});
it('details link is disabled', () => {
expect(findPackageLink().attributes('disabled')).toBe('true');
});
it('has a warning icon', () => {
const icon = findWarningIcon();
const tooltip = getBinding(icon.element, 'gl-tooltip');
expect(icon.props('icon')).toBe('warning');
expect(tooltip.value).toMatchObject({
title: 'Invalid Package: failed metadata extraction',
});
});
it('delete button is disabled', () => {
expect(findDeleteButton().props('disabled')).toBe(true);
});
});
}); });
...@@ -39,6 +39,7 @@ describe('PackagePath', () => { ...@@ -39,6 +39,7 @@ describe('PackagePath', () => {
const pathPieces = path.split('/').slice(1); const pathPieces = path.split('/').slice(1);
const hasTooltip = shouldExist.includes(ELLIPSIS_ICON); const hasTooltip = shouldExist.includes(ELLIPSIS_ICON);
describe('not disabled component', () => {
beforeEach(() => { beforeEach(() => {
mountComponent({ path }); mountComponent({ path });
}); });
...@@ -83,4 +84,21 @@ describe('PackagePath', () => { ...@@ -83,4 +84,21 @@ describe('PackagePath', () => {
}); });
} }
}); });
describe('disabled component', () => {
beforeEach(() => {
mountComponent({ path, disabled: true });
});
it('root link is disabled', () => {
expect(findItem(ROOT_LINK).attributes('disabled')).toBe('true');
});
if (shouldExist.includes(LEAF_LINK)) {
it('the last link is disabled', () => {
expect(findItem(LEAF_LINK).attributes('disabled')).toBe('true');
});
}
});
});
}); });
import { GlFormCheckbox, GlSprintf, GlIcon } from '@gitlab/ui'; import { GlFormCheckbox, GlSprintf, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import DeleteButton from '~/registry/explorer/components/delete_button.vue'; import DeleteButton from '~/registry/explorer/components/delete_button.vue';
...@@ -72,8 +73,15 @@ describe('tags list row', () => { ...@@ -72,8 +73,15 @@ describe('tags list row', () => {
expect(findCheckbox().exists()).toBe(false); expect(findCheckbox().exists()).toBe(false);
}); });
it('is disabled when the digest is missing', () => { it.each`
mountComponent({ tag: { ...tag, digest: null } }); digest | disabled
${'foo'} | ${true}
${null} | ${false}
${null} | ${true}
${'foo'} | ${true}
`('is disabled when the digest $digest and disabled is $disabled', ({ digest, disabled }) => {
mountComponent({ tag: { ...tag, digest }, disabled });
expect(findCheckbox().attributes('disabled')).toBe('true'); expect(findCheckbox().attributes('disabled')).toBe('true');
}); });
...@@ -141,6 +149,12 @@ describe('tags list row', () => { ...@@ -141,6 +149,12 @@ describe('tags list row', () => {
title: tag.location, title: tag.location,
}); });
}); });
it('is disabled when the component is disabled', () => {
mountComponent({ ...defaultProps, disabled: true });
expect(findClipboardButton().attributes('disabled')).toBe('true');
});
}); });
describe('warning icon', () => { describe('warning icon', () => {
...@@ -266,15 +280,19 @@ describe('tags list row', () => { ...@@ -266,15 +280,19 @@ describe('tags list row', () => {
}); });
it.each` it.each`
canDelete | digest canDelete | digest | disabled
${true} | ${null} ${true} | ${null} | ${true}
${false} | ${'foo'} ${false} | ${'foo'} | ${true}
${false} | ${null} ${false} | ${null} | ${true}
`('is disabled when canDelete is $canDelete and digest is $digest', ({ canDelete, digest }) => { ${true} | ${'foo'} | ${true}
mountComponent({ ...defaultProps, tag: { ...tag, canDelete, digest } }); `(
'is disabled when canDelete is $canDelete and digest is $digest and disabled is $disabled',
({ canDelete, digest, disabled }) => {
mountComponent({ ...defaultProps, tag: { ...tag, canDelete, digest }, disabled });
expect(findDeleteButton().attributes('disabled')).toBe('true'); expect(findDeleteButton().attributes('disabled')).toBe('true');
}); },
);
it('delete event emits delete', () => { it('delete event emits delete', () => {
mountComponent(); mountComponent();
...@@ -287,13 +305,10 @@ describe('tags list row', () => { ...@@ -287,13 +305,10 @@ describe('tags list row', () => {
describe('details rows', () => { describe('details rows', () => {
describe('when the tag has a digest', () => { describe('when the tag has a digest', () => {
beforeEach(() => { it('has 3 details rows', async () => {
mountComponent(); mountComponent();
await nextTick();
return wrapper.vm.$nextTick();
});
it('has 3 details rows', () => {
expect(findDetailsRows().length).toBe(3); expect(findDetailsRows().length).toBe(3);
}); });
...@@ -303,17 +318,37 @@ describe('tags list row', () => { ...@@ -303,17 +318,37 @@ describe('tags list row', () => {
${'manifest detail'} | ${findManifestDetail} | ${'Manifest digest: sha256:2cf3d2fdac1b04a14301d47d51cb88dcd26714c74f91440eeee99ce399089062'} | ${'log'} | ${true} ${'manifest detail'} | ${findManifestDetail} | ${'Manifest digest: sha256:2cf3d2fdac1b04a14301d47d51cb88dcd26714c74f91440eeee99ce399089062'} | ${'log'} | ${true}
${'configuration detail'} | ${findConfigurationDetail} | ${'Configuration digest: sha256:c2613843ab33aabf847965442b13a8b55a56ae28837ce182627c0716eb08c02b'} | ${'cloud-gear'} | ${true} ${'configuration detail'} | ${findConfigurationDetail} | ${'Configuration digest: sha256:c2613843ab33aabf847965442b13a8b55a56ae28837ce182627c0716eb08c02b'} | ${'cloud-gear'} | ${true}
`('$name details row', ({ finderFunction, text, icon, clipboard }) => { `('$name details row', ({ finderFunction, text, icon, clipboard }) => {
it(`has ${text} as text`, () => { it(`has ${text} as text`, async () => {
mountComponent();
await nextTick();
expect(finderFunction().text()).toMatchInterpolatedText(text); expect(finderFunction().text()).toMatchInterpolatedText(text);
}); });
it(`has the ${icon} icon`, () => { it(`has the ${icon} icon`, async () => {
mountComponent();
await nextTick();
expect(finderFunction().props('icon')).toBe(icon); expect(finderFunction().props('icon')).toBe(icon);
}); });
it(`is ${clipboard} that clipboard button exist`, () => { if (clipboard) {
it(`clipboard button exist`, async () => {
mountComponent();
await nextTick();
expect(finderFunction().find(ClipboardButton).exists()).toBe(clipboard); expect(finderFunction().find(ClipboardButton).exists()).toBe(clipboard);
}); });
it('is disabled when the component is disabled', async () => {
mountComponent({ ...defaultProps, disabled: true });
await nextTick();
expect(finderFunction().findComponent(ClipboardButton).attributes('disabled')).toBe(
'true',
);
});
}
}); });
}); });
...@@ -321,7 +356,7 @@ describe('tags list row', () => { ...@@ -321,7 +356,7 @@ describe('tags list row', () => {
it('hides the details rows', async () => { it('hides the details rows', async () => {
mountComponent({ tag: { ...tag, digest: null } }); mountComponent({ tag: { ...tag, digest: null } });
await wrapper.vm.$nextTick(); await nextTick();
expect(findDetailsRows().length).toBe(0); expect(findDetailsRows().length).toBe(0);
}); });
}); });
......
...@@ -25,10 +25,11 @@ describe('Image List Row', () => { ...@@ -25,10 +25,11 @@ describe('Image List Row', () => {
const findDetailsLink = () => wrapper.find('[data-testid="details-link"]'); const findDetailsLink = () => wrapper.find('[data-testid="details-link"]');
const findTagsCount = () => wrapper.find('[data-testid="tags-count"]'); const findTagsCount = () => wrapper.find('[data-testid="tags-count"]');
const findDeleteBtn = () => wrapper.find(DeleteButton); const findDeleteBtn = () => wrapper.findComponent(DeleteButton);
const findClipboardButton = () => wrapper.find(ClipboardButton); const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
const findWarningIcon = () => wrapper.find('[data-testid="warning-icon"]'); const findWarningIcon = () => wrapper.find('[data-testid="warning-icon"]');
const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader); const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
const findListItemComponent = () => wrapper.findComponent(ListItem);
const mountComponent = (props) => { const mountComponent = (props) => {
wrapper = shallowMount(Component, { wrapper = shallowMount(Component, {
...@@ -52,7 +53,8 @@ describe('Image List Row', () => { ...@@ -52,7 +53,8 @@ describe('Image List Row', () => {
wrapper = null; wrapper = null;
}); });
describe('main tooltip', () => { describe('list item component', () => {
describe('tooltip', () => {
it(`the title is ${ROW_SCHEDULED_FOR_DELETION}`, () => { it(`the title is ${ROW_SCHEDULED_FOR_DELETION}`, () => {
mountComponent(); mountComponent();
...@@ -69,6 +71,13 @@ describe('Image List Row', () => { ...@@ -69,6 +71,13 @@ describe('Image List Row', () => {
}); });
}); });
it('is disabled when the item is in deleting status', () => {
mountComponent({ item: { ...item, status: IMAGE_DELETE_SCHEDULED_STATUS } });
expect(findListItemComponent().props('disabled')).toBe(true);
});
});
describe('image title and path', () => { describe('image title and path', () => {
it('contains a link to the details page', () => { it('contains a link to the details page', () => {
mountComponent(); mountComponent();
...@@ -118,6 +127,20 @@ describe('Image List Row', () => { ...@@ -118,6 +127,20 @@ describe('Image List Row', () => {
}, },
); );
}); });
describe('when the item is deleting', () => {
beforeEach(() => {
mountComponent({ item: { ...item, status: IMAGE_DELETE_SCHEDULED_STATUS } });
});
it('the router link is disabled', () => {
// we check the event prop as is the only workaround to disable a router link
expect(findDetailsLink().props('event')).toBe('');
});
it('the clipboard button is disabled', () => {
expect(findClipboardButton().attributes('disabled')).toBe('true');
});
});
}); });
describe('delete button', () => { describe('delete button', () => {
......
...@@ -101,16 +101,16 @@ describe('list item', () => { ...@@ -101,16 +101,16 @@ describe('list item', () => {
}); });
describe('disabled prop', () => { describe('disabled prop', () => {
it('when true applies disabled-content class', () => { it('when true applies gl-opacity-5 class', () => {
mountComponent({ disabled: true }); mountComponent({ disabled: true });
expect(wrapper.classes('disabled-content')).toBe(true); expect(wrapper.classes('gl-opacity-5')).toBe(true);
}); });
it('when false does not apply disabled-content class', () => { it('when false does not apply gl-opacity-5 class', () => {
mountComponent({ disabled: false }); mountComponent({ disabled: false });
expect(wrapper.classes('disabled-content')).toBe(false); expect(wrapper.classes('gl-opacity-5')).toBe(false);
}); });
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment