import { GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import setWindowLocation from 'helpers/set_window_location_helper';
import createFlash from '~/flash';
import * as commonUtils from '~/lib/utils/common_utils';
import PackageListApp from '~/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue';
import { DELETE_PACKAGE_SUCCESS_MESSAGE } from '~/packages_and_registries/infrastructure_registry/list/constants';
import {
SHOW_DELETE_SUCCESS_ALERT,
FILTERED_SEARCH_TERM,
} from '~/packages_and_registries/shared/constants';
import * as packageUtils from '~/packages_and_registries/shared/utils';
import InfrastructureSearch from '~/packages_and_registries/infrastructure_registry/list/components/infrastructure_search.vue';
jest.mock('~/lib/utils/common_utils');
jest.mock('~/flash');
Vue.use(Vuex);
describe('packages_list_app', () => {
let wrapper;
let store;
const PackageList = {
name: 'package-list',
template: '
',
};
const GlLoadingIcon = { name: 'gl-loading-icon', template: 'loading
' };
const emptyListHelpUrl = 'helpUrl';
const findEmptyState = () => wrapper.find(GlEmptyState);
const findListComponent = () => wrapper.find(PackageList);
const findInfrastructureSearch = () => wrapper.find(InfrastructureSearch);
const createStore = ({ filter = [], packageCount = 0 } = {}) => {
store = new Vuex.Store({
state: {
isLoading: false,
config: {
resourceId: 'project_id',
emptyListIllustration: 'helpSvg',
emptyListHelpUrl,
packageHelpUrl: 'foo',
},
filter,
pagination: {
total: packageCount,
},
},
});
store.dispatch = jest.fn();
};
const mountComponent = (provide) => {
wrapper = shallowMount(PackageListApp, {
store,
stubs: {
GlEmptyState,
GlLoadingIcon,
PackageList,
GlSprintf,
GlLink,
},
provide,
});
};
beforeEach(() => {
createStore();
jest.spyOn(packageUtils, 'getQueryParams').mockReturnValue({});
mountComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('renders', () => {
createStore({ packageCount: 1 });
mountComponent();
expect(wrapper.element).toMatchSnapshot();
});
it('calls requestPackagesList on page:changed', () => {
const list = findListComponent();
list.vm.$emit('page:changed', 1);
expect(store.dispatch).toHaveBeenCalledWith('requestPackagesList', { page: 1 });
});
it('calls requestDeletePackage on package:delete', () => {
const list = findListComponent();
list.vm.$emit('package:delete', 'foo');
expect(store.dispatch).toHaveBeenCalledWith('requestDeletePackage', 'foo');
});
it('calls requestPackagesList only once on render', () => {
expect(store.dispatch).toHaveBeenCalledTimes(3);
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'setSorting', expect.any(Object));
expect(store.dispatch).toHaveBeenNthCalledWith(2, 'setFilter', expect.any(Array));
expect(store.dispatch).toHaveBeenNthCalledWith(3, 'requestPackagesList');
});
describe('url query string handling', () => {
const defaultQueryParamsMock = {
search: [1, 2],
type: 'npm',
sort: 'asc',
orderBy: 'created',
};
beforeEach(() => {
createStore();
jest.spyOn(packageUtils, 'getQueryParams').mockReturnValue(defaultQueryParamsMock);
});
it('calls setSorting with the query string based sorting', () => {
mountComponent();
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'setSorting', {
orderBy: defaultQueryParamsMock.orderBy,
sort: defaultQueryParamsMock.sort,
});
});
it('calls setFilter with the query string based filters', () => {
mountComponent();
expect(store.dispatch).toHaveBeenNthCalledWith(2, 'setFilter', [
{ type: 'type', value: { data: defaultQueryParamsMock.type } },
{ type: FILTERED_SEARCH_TERM, value: { data: defaultQueryParamsMock.search[0] } },
{ type: FILTERED_SEARCH_TERM, value: { data: defaultQueryParamsMock.search[1] } },
]);
});
it('calls setSorting and setFilters with the results of extractFilterAndSorting', () => {
jest
.spyOn(packageUtils, 'extractFilterAndSorting')
.mockReturnValue({ filters: ['foo'], sorting: { sort: 'desc' } });
mountComponent();
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'setSorting', { sort: 'desc' });
expect(store.dispatch).toHaveBeenNthCalledWith(2, 'setFilter', ['foo']);
});
});
describe('empty state', () => {
it('generate the correct empty list link', () => {
const link = findListComponent().find(GlLink);
expect(link.attributes('href')).toBe(emptyListHelpUrl);
expect(link.text()).toBe('publish and share your packages');
});
it('includes the right content on the default tab', () => {
const heading = findEmptyState().find('h1');
expect(heading.text()).toBe('There are no packages yet');
});
});
describe('filter without results', () => {
beforeEach(() => {
createStore({ filter: [{ type: 'something' }] });
mountComponent();
});
it('should show specific empty message', () => {
expect(findEmptyState().text()).toContain('Sorry, your filter produced no results');
expect(findEmptyState().text()).toContain(
'To widen your search, change or remove the filters above',
);
});
});
describe('search', () => {
describe('with no packages', () => {
it('does not exist', () => {
expect(findInfrastructureSearch().exists()).toBe(false);
});
});
describe('with packages', () => {
beforeEach(() => {
createStore({ packageCount: 1 });
mountComponent();
});
it('exists', () => {
expect(findInfrastructureSearch().exists()).toBe(true);
});
it('on update fetches data from the store', () => {
store.dispatch.mockClear();
findInfrastructureSearch().vm.$emit('update');
expect(store.dispatch).toHaveBeenCalledWith('requestPackagesList');
});
});
});
describe('delete alert handling', () => {
const originalLocation = window.location.href;
const search = `?${SHOW_DELETE_SUCCESS_ALERT}=true`;
beforeEach(() => {
createStore();
jest.spyOn(commonUtils, 'historyReplaceState').mockImplementation(() => {});
setWindowLocation(search);
});
afterEach(() => {
setWindowLocation(originalLocation);
});
it(`creates a flash if the query string contains ${SHOW_DELETE_SUCCESS_ALERT}`, () => {
mountComponent();
expect(createFlash).toHaveBeenCalledWith({
message: DELETE_PACKAGE_SUCCESS_MESSAGE,
type: 'notice',
});
});
it('calls historyReplaceState with a clean url', () => {
mountComponent();
expect(commonUtils.historyReplaceState).toHaveBeenCalledWith(originalLocation);
});
it(`does nothing if the query string does not contain ${SHOW_DELETE_SUCCESS_ALERT}`, () => {
setWindowLocation('?');
mountComponent();
expect(createFlash).not.toHaveBeenCalled();
expect(commonUtils.historyReplaceState).not.toHaveBeenCalled();
});
});
});