Commit 4e0a6e4d authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera Committed by Natalia Tepluhina

Customise Package list app

parent 0067c3aa
......@@ -11,25 +11,25 @@ export default {
MetadataItem,
},
props: {
packagesCount: {
count: {
type: Number,
required: false,
default: null,
},
packageHelpUrl: {
helpUrl: {
type: String,
required: true,
},
},
computed: {
showPackageCount() {
return Number.isInteger(this.packagesCount);
return Number.isInteger(this.count);
},
packageAmountText() {
return n__(`%d Package`, `%d Packages`, this.packagesCount);
return n__(`%d Package`, `%d Packages`, this.count);
},
infoMessages() {
return [{ text: LIST_INTRO_TEXT, link: this.packageHelpUrl }];
return [{ text: LIST_INTRO_TEXT, link: this.helpUrl }];
},
},
i18n: {
......
......@@ -8,8 +8,6 @@ import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants';
import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants';
import { getQueryParams, extractFilterAndSorting } from '~/packages_and_registries/shared/utils';
import { DELETE_PACKAGE_SUCCESS_MESSAGE } from '../constants';
import PackageSearch from './package_search.vue';
import PackageTitle from './package_title.vue';
import PackageList from './packages_list.vue';
export default {
......@@ -18,8 +16,38 @@ export default {
GlLink,
GlSprintf,
PackageList,
PackageTitle,
PackageSearch,
PackageTitle: () =>
import(/* webpackChunkName: 'package_registry_components' */ './package_title.vue'),
PackageSearch: () =>
import(/* webpackChunkName: 'package_registry_components' */ './package_search.vue'),
InfrastructureTitle: () =>
import(
/* webpackChunkName: 'infrastructure_registry_components' */ '~/packages_and_registries/infrastructure_registry/components/infrastructure_title.vue'
),
InfrastructureSearch: () =>
import(
/* webpackChunkName: 'infrastructure_registry_components' */ '~/packages_and_registries/infrastructure_registry/components/infrastructure_search.vue'
),
},
inject: {
titleComponent: {
from: 'titleComponent',
default: 'PackageTitle',
},
searchComponent: {
from: 'searchComponent',
default: 'PackageSearch',
},
emptyPageTitle: {
from: 'emptyPageTitle',
default: s__('PackageRegistry|There are no packages yet'),
},
noResultsText: {
from: 'noResultsText',
default: s__(
'PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab.',
),
},
},
computed: {
...mapState({
......@@ -38,7 +66,7 @@ export default {
emptyStateTitle() {
return this.emptySearch
? s__('PackageRegistry|There are no packages yet')
? this.emptyPageTitle
: s__('PackageRegistry|Sorry, your filter produced no results');
},
},
......@@ -77,24 +105,21 @@ export default {
},
i18n: {
widenFilters: s__('PackageRegistry|To widen your search, change or remove the filters above.'),
noResults: s__(
'PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab.',
),
},
};
</script>
<template>
<div>
<package-title :package-help-url="packageHelpUrl" :packages-count="packagesCount" />
<package-search @update="requestPackagesList" />
<component :is="titleComponent" :help-url="packageHelpUrl" :count="packagesCount" />
<component :is="searchComponent" @update="requestPackagesList" />
<package-list @page:changed="onPageChanged" @package:delete="onPackageDeleteRequest">
<template #empty-state>
<gl-empty-state :title="emptyStateTitle" :svg-path="emptyListIllustration">
<template #description>
<gl-sprintf v-if="!emptySearch" :message="$options.i18n.widenFilters" />
<gl-sprintf v-else :message="$options.i18n.noResults">
<gl-sprintf v-else :message="noResultsText">
<template #noPackagesLink="{ content }">
<gl-link :href="emptyListHelpUrl" target="_blank">{{ content }}</gl-link>
</template>
......
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import Translate from '~/vue_shared/translate';
import PackagesListApp from './components/packages_list_app.vue';
import { createStore } from './stores';
Vue.use(VueApollo);
Vue.use(Translate);
export default () => {
......@@ -13,14 +10,9 @@ export default () => {
const store = createStore();
store.dispatch('setInitialState', el.dataset);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
return new Vue({
el,
store,
apolloProvider,
components: {
PackagesListApp,
},
......
<script>
import { GlIcon } from '@gitlab/ui';
export default {
name: 'PackageIconAndName',
components: {
GlIcon,
},
};
</script>
<template>
<div class="gl-display-flex gl-align-items-center">
<gl-icon name="package" class="gl-ml-3 gl-mr-2" />
<span><slot></slot></span>
</div>
</template>
<script>
import { GlButton, GlIcon, GlLink, GlSprintf, GlTooltipDirective, GlTruncate } from '@gitlab/ui';
import { GlButton, GlLink, GlSprintf, GlTooltipDirective, GlTruncate } from '@gitlab/ui';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import { getPackageTypeLabel } from '../utils';
......@@ -11,7 +11,6 @@ export default {
name: 'PackageListRow',
components: {
GlButton,
GlIcon,
GlLink,
GlSprintf,
GlTruncate,
......@@ -19,11 +18,23 @@ export default {
PackagePath,
PublishMethod,
ListItem,
PackageIconAndName: () =>
import(/* webpackChunkName: 'package_registry_components' */ './package_icon_and_name.vue'),
InfrastructureIconAndName: () =>
import(
/* webpackChunkName: 'infrastructure_registry_components' */ '~/packages_and_registries/infrastructure_registry/components/infrastructure_icon_and_name.vue'
),
},
directives: {
GlTooltip: GlTooltipDirective,
},
mixins: [timeagoMixin],
inject: {
iconComponent: {
from: 'iconComponent',
default: 'PackageIconAndName',
},
},
props: {
packageEntity: {
type: Object,
......@@ -94,10 +105,9 @@ export default {
</gl-sprintf>
</div>
<div v-if="showPackageType" class="d-flex align-items-center" data-testid="package-type">
<gl-icon name="package" class="gl-ml-3 gl-mr-2" />
<span>{{ packageType }}</span>
</div>
<component :is="iconComponent" v-if="showPackageType">
{{ packageType }}
</component>
<package-path v-if="hasProjectLink" :path="packageEntity.project_path" />
</div>
......
<script>
import { GlIcon } from '@gitlab/ui';
export default {
name: 'InfrastructureIconAndName',
components: {
GlIcon,
},
};
</script>
<template>
<div class="gl-display-flex gl-align-items-center">
<gl-icon name="infrastructure-registry" class="gl-ml-3 gl-mr-2" />
<span>{{ s__('InfrastructureRegistry|Terraform') }}</span>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
import { LIST_KEY_PACKAGE_TYPE } from '~/packages/list/constants';
import getTableHeaders from '~/packages/list/utils';
import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
import UrlSync from '~/vue_shared/components/url_sync.vue';
export default {
components: { RegistrySearch, UrlSync },
computed: {
...mapState({
isGroupPage: (state) => state.config.isGroupPage,
sorting: (state) => state.sorting,
filter: (state) => state.filter,
}),
sortableFields() {
return getTableHeaders(this.isGroupPage).filter((h) => h.orderBy !== LIST_KEY_PACKAGE_TYPE);
},
},
methods: {
...mapActions(['setSorting', 'setFilter']),
updateSorting(newValue) {
this.setSorting(newValue);
this.$emit('update');
},
},
};
</script>
<template>
<url-sync>
<template #default="{ updateQuery }">
<registry-search
:filter="filter"
:sorting="sorting"
:tokens="[]"
:sortable-fields="sortableFields"
@sorting:changed="updateSorting"
@filter:changed="setFilter"
@filter:submit="$emit('update')"
@query:changed="updateQuery"
/>
</template>
</url-sync>
</template>
<script>
import { s__, n__ } from '~/locale';
import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
export default {
name: 'InfrastructureTitle',
components: {
TitleArea,
MetadataItem,
},
props: {
count: {
type: Number,
required: false,
default: null,
},
helpUrl: {
type: String,
required: true,
},
},
computed: {
showModuleCount() {
return Number.isInteger(this.count);
},
moduleAmountText() {
return n__(`%d Module`, `%d Modules`, this.count);
},
infoMessages() {
return [{ text: this.$options.i18n.LIST_INTRO_TEXT, link: this.helpUrl }];
},
},
i18n: {
LIST_TITLE_TEXT: s__('InfrastructureRegistry|Infrastructure Registry'),
LIST_INTRO_TEXT: s__(
'InfrastructureRegistry|Publish and share your modules. %{docLinkStart}More information%{docLinkEnd}',
),
},
};
</script>
<template>
<title-area :title="$options.i18n.LIST_TITLE_TEXT" :info-messages="infoMessages">
<template #metadata-amount>
<metadata-item
v-if="showModuleCount"
icon="infrastructure-registry"
:text="moduleAmountText"
/>
</template>
</title-area>
</template>
import Vue from 'vue';
import { s__ } from '~/locale';
import PackagesListApp from '~/packages/list/components/packages_list_app.vue';
import { createStore } from '~/packages/list/stores';
import Translate from '~/vue_shared/translate';
Vue.use(Translate);
export default () => {
const el = document.getElementById('js-vue-packages-list');
const store = createStore();
store.dispatch('setInitialState', el.dataset);
return new Vue({
el,
store,
components: {
PackagesListApp,
},
provide: {
titleComponent: 'InfrastructureTitle',
searchComponent: 'InfrastructureSearch',
iconComponent: 'InfrastructureIconAndName',
emptyPageTitle: s__('InfrastructureRegistry|You have no Terraform modules in your project'),
noResultsText: s__(
'InfrastructureRegistry|Terraform modules are the main way to package and reuse resource configurations with Terraform. Learn more about how to %{noPackagesLinkStart}create Terraform modules%{noPackagesLinkEnd} in GitLab.',
),
},
render(createElement) {
return createElement('packages-list-app');
},
});
};
import initPackageList from '~/packages/list/packages_list_app_bundle';
import initList from '~/packages_and_registries/infrastructure_registry/list_app_bundle';
initPackageList();
initList();
......@@ -5,6 +5,6 @@
.col-12
#js-vue-packages-list{ data: { resource_id: @project.id,
page_type: 'project',
empty_list_help_url: help_page_path('user/packages/package_registry/index'),
empty_list_illustration: image_path('illustrations/no-packages.svg'),
package_help_url: help_page_path('user/packages/index') } }
empty_list_help_url: help_page_path('user/infrastructure/index'),
empty_list_illustration: image_path('illustrations/empty-state/empty-terraform-register-lg.svg'),
package_help_url: help_page_path('user/infrastructure/index') } }
......@@ -91,6 +91,11 @@ msgid_plural "%d Approvals"
msgstr[0] ""
msgstr[1] ""
msgid "%d Module"
msgid_plural "%d Modules"
msgstr[0] ""
msgstr[1] ""
msgid "%d Other"
msgid_plural "%d Others"
msgstr[0] ""
......@@ -16821,6 +16826,21 @@ msgstr ""
msgid "Infrastructure Registry"
msgstr ""
msgid "InfrastructureRegistry|Infrastructure Registry"
msgstr ""
msgid "InfrastructureRegistry|Publish and share your modules. %{docLinkStart}More information%{docLinkEnd}"
msgstr ""
msgid "InfrastructureRegistry|Terraform"
msgstr ""
msgid "InfrastructureRegistry|Terraform modules are the main way to package and reuse resource configurations with Terraform. Learn more about how to %{noPackagesLinkStart}create Terraform modules%{noPackagesLinkEnd} in GitLab."
msgstr ""
msgid "InfrastructureRegistry|You have no Terraform modules in your project"
msgstr ""
msgid "Inherited"
msgstr ""
......
......@@ -2,11 +2,11 @@
exports[`packages_list_app renders 1`] = `
<div>
<package-title-stub
packagehelpurl="foo"
<div
help-url="foo"
/>
<package-search-stub />
<div />
<div>
<section
......
......@@ -3,7 +3,6 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import createFlash from '~/flash';
import * as commonUtils from '~/lib/utils/common_utils';
import PackageSearch from '~/packages/list/components/package_search.vue';
import PackageListApp from '~/packages/list/components/packages_list_app.vue';
import { DELETE_PACKAGE_SUCCESS_MESSAGE } from '~/packages/list/constants';
import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants';
......@@ -26,10 +25,19 @@ describe('packages_list_app', () => {
};
const GlLoadingIcon = { name: 'gl-loading-icon', template: '<div>loading</div>' };
// we need to manually stub dynamic imported components because shallowMount is not able to stub them automatically. See: https://github.com/vuejs/vue-test-utils/issues/1279
const PackageSearch = { name: 'PackageSearch', template: '<div></div>' };
const PackageTitle = { name: 'PackageTitle', template: '<div></div>' };
const InfrastructureTitle = { name: 'InfrastructureTitle', template: '<div></div>' };
const InfrastructureSearch = { name: 'InfrastructureSearch', template: '<div></div>' };
const emptyListHelpUrl = 'helpUrl';
const findEmptyState = () => wrapper.find(GlEmptyState);
const findListComponent = () => wrapper.find(PackageList);
const findPackageSearch = () => wrapper.find(PackageSearch);
const findPackageTitle = () => wrapper.find(PackageTitle);
const findInfrastructureTitle = () => wrapper.find(InfrastructureTitle);
const findInfrastructureSearch = () => wrapper.find(InfrastructureSearch);
const createStore = (filter = []) => {
store = new Vuex.Store({
......@@ -47,7 +55,7 @@ describe('packages_list_app', () => {
store.dispatch = jest.fn();
};
const mountComponent = () => {
const mountComponent = (provide) => {
wrapper = shallowMount(PackageListApp, {
localVue,
store,
......@@ -57,7 +65,12 @@ describe('packages_list_app', () => {
PackageList,
GlSprintf,
GlLink,
PackageSearch,
PackageTitle,
InfrastructureTitle,
InfrastructureSearch,
},
provide,
});
};
......@@ -194,6 +207,31 @@ describe('packages_list_app', () => {
});
});
describe('Infrastructure config', () => {
it('defaults to package registry components', () => {
mountComponent();
expect(findPackageSearch().exists()).toBe(true);
expect(findPackageTitle().exists()).toBe(true);
expect(findInfrastructureTitle().exists()).toBe(false);
expect(findInfrastructureSearch().exists()).toBe(false);
});
it('mount different component based on the provided values', () => {
mountComponent({
titleComponent: 'InfrastructureTitle',
searchComponent: 'InfrastructureSearch',
});
expect(findPackageSearch().exists()).toBe(false);
expect(findPackageTitle().exists()).toBe(false);
expect(findInfrastructureTitle().exists()).toBe(true);
expect(findInfrastructureSearch().exists()).toBe(true);
});
});
describe('delete alert handling', () => {
const { location } = window.location;
const search = `?${SHOW_DELETE_SUCCESS_ALERT}=true`;
......
......@@ -11,7 +11,7 @@ describe('PackageTitle', () => {
const findTitleArea = () => wrapper.find(TitleArea);
const findMetadataItem = () => wrapper.find(MetadataItem);
const mountComponent = (propsData = { packageHelpUrl: 'foo' }) => {
const mountComponent = (propsData = { helpUrl: 'foo' }) => {
wrapper = shallowMount(PackageTitle, {
store,
propsData,
......@@ -44,15 +44,15 @@ describe('PackageTitle', () => {
});
describe.each`
packagesCount | exist | text
${null} | ${false} | ${''}
${undefined} | ${false} | ${''}
${0} | ${true} | ${'0 Packages'}
${1} | ${true} | ${'1 Package'}
${2} | ${true} | ${'2 Packages'}
`('when packagesCount is $packagesCount metadata item', ({ packagesCount, exist, text }) => {
count | exist | text
${null} | ${false} | ${''}
${undefined} | ${false} | ${''}
${0} | ${true} | ${'0 Packages'}
${1} | ${true} | ${'1 Package'}
${2} | ${true} | ${'2 Packages'}
`('when count is $count metadata item', ({ count, exist, text }) => {
beforeEach(() => {
mountComponent({ packagesCount, packageHelpUrl: 'foo' });
mountComponent({ count, helpUrl: 'foo' });
});
it(`is ${exist} that it exists`, () => {
......
......@@ -51,20 +51,7 @@ exports[`packages_list_row renders 1`] = `
<!---->
<div
class="d-flex align-items-center"
data-testid="package-type"
>
<gl-icon-stub
class="gl-ml-3 gl-mr-2"
name="package"
size="16"
/>
<span>
Maven
</span>
</div>
<div />
<package-path-stub
path="foo/bar/baz"
......
import { GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import PackageIconAndName from '~/packages/shared/components/package_icon_and_name.vue';
describe('PackageIconAndName', () => {
let wrapper;
const findIcon = () => wrapper.find(GlIcon);
const mountComponent = () => {
wrapper = shallowMount(PackageIconAndName, {
slots: {
default: 'test',
},
});
};
it('has an icon', () => {
mountComponent();
const icon = findIcon();
expect(icon.exists()).toBe(true);
expect(icon.props('name')).toBe('package');
});
it('renders the slot content', () => {
mountComponent();
expect(wrapper.text()).toBe('test');
});
});
import { shallowMount } from '@vue/test-utils';
import PackagesListRow from '~/packages/shared/components/package_list_row.vue';
import PackagePath from '~/packages/shared/components/package_path.vue';
import PackageTags from '~/packages/shared/components/package_tags.vue';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { packageList } from '../../mock_data';
......@@ -11,20 +13,30 @@ describe('packages_list_row', () => {
const [packageWithoutTags, packageWithTags] = packageList;
const InfrastructureIconAndName = { name: 'InfrastructureIconAndName', template: '<div></div>' };
const PackageIconAndName = { name: 'PackageIconAndName', template: '<div></div>' };
const findPackageTags = () => wrapper.find(PackageTags);
const findPackagePath = () => wrapper.find(PackagePath);
const findDeleteButton = () => wrapper.find('[data-testid="action-delete"]');
const findPackageType = () => wrapper.find('[data-testid="package-type"]');
const findPackageIconAndName = () => wrapper.find(PackageIconAndName);
const findInfrastructureIconAndName = () => wrapper.find(InfrastructureIconAndName);
const mountComponent = ({
isGroup = false,
packageEntity = packageWithoutTags,
showPackageType = true,
disableDelete = false,
provide,
} = {}) => {
wrapper = shallowMount(PackagesListRow, {
store,
stubs: { ListItem },
provide,
stubs: {
ListItem,
InfrastructureIconAndName,
PackageIconAndName,
},
propsData: {
packageLink: 'foo',
packageEntity,
......@@ -72,13 +84,13 @@ describe('packages_list_row', () => {
it('shows the type when set', () => {
mountComponent();
expect(findPackageType().exists()).toBe(true);
expect(findPackageIconAndName().exists()).toBe(true);
});
it('does not show the type when not set', () => {
mountComponent({ showPackageType: false });
expect(findPackageType().exists()).toBe(false);
expect(findPackageIconAndName().exists()).toBe(false);
});
});
......@@ -113,4 +125,25 @@ describe('packages_list_row', () => {
expect(wrapper.emitted('packageToDelete')[0]).toEqual([packageWithoutTags]);
});
});
describe('Infrastructure config', () => {
it('defaults to package registry components', () => {
mountComponent();
expect(findPackageIconAndName().exists()).toBe(true);
expect(findInfrastructureIconAndName().exists()).toBe(false);
});
it('mounts different component based on the provided values', () => {
mountComponent({
provide: {
iconComponent: 'InfrastructureIconAndName',
},
});
expect(findPackageIconAndName().exists()).toBe(false);
expect(findInfrastructureIconAndName().exists()).toBe(true);
});
});
});
import { GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import InfrastructureIconAndName from '~/packages_and_registries/infrastructure_registry/components/infrastructure_icon_and_name.vue';
describe('InfrastructureIconAndName', () => {
let wrapper;
const findIcon = () => wrapper.find(GlIcon);
const mountComponent = () => {
wrapper = shallowMount(InfrastructureIconAndName, {});
};
it('has an icon', () => {
mountComponent();
const icon = findIcon();
expect(icon.exists()).toBe(true);
expect(icon.props('name')).toBe('infrastructure-registry');
});
it('has the type fixed to terraform', () => {
mountComponent();
expect(wrapper.text()).toBe('Terraform');
});
});
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import component from '~/packages_and_registries/infrastructure_registry/components/infrastructure_search.vue';
import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
import UrlSync from '~/vue_shared/components/url_sync.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Infrastructure Search', () => {
let wrapper;
let store;
const sortableFields = () => [
{ orderBy: 'name', label: 'Name' },
{ orderBy: 'project_path', label: 'Project' },
{ orderBy: 'version', label: 'Version' },
{ orderBy: 'created_at', label: 'Published' },
];
const findRegistrySearch = () => wrapper.findComponent(RegistrySearch);
const findUrlSync = () => wrapper.findComponent(UrlSync);
const createStore = (isGroupPage) => {
const state = {
config: {
isGroupPage,
},
sorting: {
orderBy: 'version',
sort: 'desc',
},
filter: [],
};
store = new Vuex.Store({
state,
});
store.dispatch = jest.fn();
};
const mountComponent = (isGroupPage = false) => {
createStore(isGroupPage);
wrapper = shallowMount(component, {
localVue,
store,
stubs: {
UrlSync,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('has a registry search component', () => {
mountComponent();
expect(findRegistrySearch().exists()).toBe(true);
expect(findRegistrySearch().props()).toMatchObject({
filter: store.state.filter,
sorting: store.state.sorting,
tokens: [],
sortableFields: sortableFields(),
});
});
it.each`
isGroupPage | page
${false} | ${'project'}
${true} | ${'group'}
`('in a $page page binds the right props', ({ isGroupPage }) => {
mountComponent(isGroupPage);
expect(findRegistrySearch().props()).toMatchObject({
filter: store.state.filter,
sorting: store.state.sorting,
tokens: [],
sortableFields: sortableFields(),
});
});
it('on sorting:changed emits update event and calls vuex setSorting', () => {
const payload = { sort: 'foo' };
mountComponent();
findRegistrySearch().vm.$emit('sorting:changed', payload);
expect(store.dispatch).toHaveBeenCalledWith('setSorting', payload);
expect(wrapper.emitted('update')).toEqual([[]]);
});
it('on filter:changed calls vuex setFilter', () => {
const payload = ['foo'];
mountComponent();
findRegistrySearch().vm.$emit('filter:changed', payload);
expect(store.dispatch).toHaveBeenCalledWith('setFilter', payload);
});
it('on filter:submit emits update event', () => {
mountComponent();
findRegistrySearch().vm.$emit('filter:submit');
expect(wrapper.emitted('update')).toEqual([[]]);
});
it('has a UrlSync component', () => {
mountComponent();
expect(findUrlSync().exists()).toBe(true);
});
it('on query:changed calls updateQuery from UrlSync', () => {
jest.spyOn(UrlSync.methods, 'updateQuery').mockImplementation(() => {});
mountComponent();
findRegistrySearch().vm.$emit('query:changed');
expect(UrlSync.methods.updateQuery).toHaveBeenCalled();
});
});
import { shallowMount } from '@vue/test-utils';
import component from '~/packages_and_registries/infrastructure_registry/components/infrastructure_title.vue';
import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
describe('Infrastructure Title', () => {
let wrapper;
let store;
const findTitleArea = () => wrapper.find(TitleArea);
const findMetadataItem = () => wrapper.find(MetadataItem);
const mountComponent = (propsData = { helpUrl: 'foo' }) => {
wrapper = shallowMount(component, {
store,
propsData,
stubs: {
TitleArea,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('title area', () => {
it('exists', () => {
mountComponent();
expect(findTitleArea().exists()).toBe(true);
});
it('has the correct props', () => {
mountComponent();
expect(findTitleArea().props()).toMatchObject({
title: 'Infrastructure Registry',
infoMessages: [
{
text: 'Publish and share your modules. %{docLinkStart}More information%{docLinkEnd}',
link: 'foo',
},
],
});
});
});
describe.each`
count | exist | text
${null} | ${false} | ${''}
${undefined} | ${false} | ${''}
${0} | ${true} | ${'0 Modules'}
${1} | ${true} | ${'1 Module'}
${2} | ${true} | ${'2 Modules'}
`('when count is $count metadata item', ({ count, exist, text }) => {
beforeEach(() => {
mountComponent({ count, helpUrl: 'foo' });
});
it(`is ${exist} that it exists`, () => {
expect(findMetadataItem().exists()).toBe(exist);
});
if (exist) {
it('has the correct props', () => {
expect(findMetadataItem().props()).toMatchObject({
icon: 'infrastructure-registry',
text,
});
});
}
});
});
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