import { GlAlert, GlKeysetPagination, GlModal, GlSprintf } from '@gitlab/ui';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import PackagesListRow from '~/packages_and_registries/package_registry/components/list/package_list_row.vue';
import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
import {
DELETE_PACKAGE_TRACKING_ACTION,
REQUEST_DELETE_PACKAGE_TRACKING_ACTION,
CANCEL_DELETE_PACKAGE_TRACKING_ACTION,
} from '~/packages_and_registries/package_registry/constants';
import PackagesList from '~/packages_and_registries/package_registry/components/list/packages_list.vue';
import Tracking from '~/tracking';
import { packageData } from '../../mock_data';
describe('packages_list', () => {
let wrapper;
const firstPackage = packageData();
const secondPackage = {
...packageData(),
id: 'gid://gitlab/Packages::Package/112',
name: 'second-package',
};
const errorPackage = {
...packageData(),
id: 'gid://gitlab/Packages::Package/121',
status: 'ERROR',
name: 'error package',
};
const defaultProps = {
list: [firstPackage, secondPackage],
isLoading: false,
pageInfo: {},
};
const EmptySlotStub = { name: 'empty-slot-stub', template: '
bar
' };
const GlModalStub = {
name: GlModal.name,
template: '
',
methods: { show: jest.fn() },
};
const findPackagesListLoader = () => wrapper.findComponent(PackagesListLoader);
const findPackageListPagination = () => wrapper.findComponent(GlKeysetPagination);
const findPackageListDeleteModal = () => wrapper.findComponent(GlModalStub);
const findEmptySlot = () => wrapper.findComponent(EmptySlotStub);
const findPackagesListRow = () => wrapper.findComponent(PackagesListRow);
const findErrorPackageAlert = () => wrapper.findComponent(GlAlert);
const mountComponent = (props) => {
wrapper = shallowMountExtended(PackagesList, {
propsData: {
...defaultProps,
...props,
},
stubs: {
GlModal: GlModalStub,
GlSprintf,
},
slots: {
'empty-state': EmptySlotStub,
},
});
};
beforeEach(() => {
GlModalStub.methods.show.mockReset();
});
afterEach(() => {
wrapper.destroy();
});
describe('when is loading', () => {
beforeEach(() => {
mountComponent({ isLoading: true });
});
it('shows skeleton loader', () => {
expect(findPackagesListLoader().exists()).toBe(true);
});
it('does not show the rows', () => {
expect(findPackagesListRow().exists()).toBe(false);
});
it('does not show the pagination', () => {
expect(findPackageListPagination().exists()).toBe(false);
});
});
describe('when is not loading', () => {
beforeEach(() => {
mountComponent();
});
it('does not show skeleton loader', () => {
expect(findPackagesListLoader().exists()).toBe(false);
});
it('shows the rows', () => {
expect(findPackagesListRow().exists()).toBe(true);
});
});
describe('layout', () => {
it('contains a pagination component', () => {
mountComponent({ pageInfo: { hasPreviousPage: true } });
expect(findPackageListPagination().exists()).toBe(true);
});
it('contains a modal component', () => {
mountComponent();
expect(findPackageListDeleteModal().exists()).toBe(true);
});
it('does not have an error alert displayed', () => {
mountComponent();
expect(findErrorPackageAlert().exists()).toBe(false);
});
});
describe('when the user can destroy the package', () => {
beforeEach(() => {
mountComponent();
findPackagesListRow().vm.$emit('packageToDelete', firstPackage);
return nextTick();
});
it('deleting a package opens the modal', () => {
expect(findPackageListDeleteModal().text()).toContain(firstPackage.name);
});
it('confirming on the modal emits package:delete', async () => {
findPackageListDeleteModal().vm.$emit('ok');
await nextTick();
expect(wrapper.emitted('package:delete')[0]).toEqual([firstPackage]);
});
it('closing the modal resets itemToBeDeleted', async () => {
// triggering the v-model
findPackageListDeleteModal().vm.$emit('input', false);
await nextTick();
expect(findPackageListDeleteModal().text()).not.toContain(firstPackage.name);
});
});
describe('when an error package is present', () => {
beforeEach(() => {
mountComponent({ list: [firstPackage, errorPackage] });
return nextTick();
});
it('should display an alert message', () => {
expect(findErrorPackageAlert().exists()).toBe(true);
expect(findErrorPackageAlert().props('title')).toBe(
'There was an error publishing a error package package',
);
expect(findErrorPackageAlert().text()).toBe(
'There was a timeout and the package was not published. Delete this package and try again.',
);
});
it('should display the deletion modal when clicked on the confirm button', async () => {
findErrorPackageAlert().vm.$emit('primaryAction');
await nextTick();
expect(findPackageListDeleteModal().text()).toContain(errorPackage.name);
});
});
describe('when the list is empty', () => {
beforeEach(() => {
mountComponent({ list: [] });
});
it('show the empty slot', () => {
const emptySlot = findEmptySlot();
expect(emptySlot.exists()).toBe(true);
});
});
describe('pagination', () => {
beforeEach(() => {
mountComponent({ pageInfo: { hasPreviousPage: true } });
});
it('emits prev-page events when the prev event is fired', () => {
findPackageListPagination().vm.$emit('prev');
expect(wrapper.emitted('prev-page')).toEqual([[]]);
});
it('emits next-page events when the next event is fired', () => {
findPackageListPagination().vm.$emit('next');
expect(wrapper.emitted('next-page')).toEqual([[]]);
});
});
describe('tracking', () => {
let eventSpy;
const category = 'UI::NpmPackages';
beforeEach(() => {
eventSpy = jest.spyOn(Tracking, 'event');
mountComponent();
findPackagesListRow().vm.$emit('packageToDelete', firstPackage);
return nextTick();
});
it('requesting the delete tracks the right action', () => {
expect(eventSpy).toHaveBeenCalledWith(
category,
REQUEST_DELETE_PACKAGE_TRACKING_ACTION,
expect.any(Object),
);
});
it('confirming delete tracks the right action', () => {
findPackageListDeleteModal().vm.$emit('ok');
expect(eventSpy).toHaveBeenCalledWith(
category,
DELETE_PACKAGE_TRACKING_ACTION,
expect.any(Object),
);
});
it('canceling delete tracks the right action', () => {
findPackageListDeleteModal().vm.$emit('cancel');
expect(eventSpy).toHaveBeenCalledWith(
category,
CANCEL_DELETE_PACKAGE_TRACKING_ACTION,
expect.any(Object),
);
});
});
});