diff options
author | Robert Speicher <rspeicher@gmail.com> | 2021-01-20 13:34:23 -0600 |
---|---|---|
committer | Robert Speicher <rspeicher@gmail.com> | 2021-01-20 13:34:23 -0600 |
commit | 6438df3a1e0fb944485cebf07976160184697d72 (patch) | |
tree | 00b09bfd170e77ae9391b1a2f5a93ef6839f2597 /spec/frontend/registry/explorer/components | |
parent | 42bcd54d971da7ef2854b896a7b34f4ef8601067 (diff) | |
download | gitlab-ce-6438df3a1e0fb944485cebf07976160184697d72.tar.gz |
Add latest changes from gitlab-org/gitlab@13-8-stable-eev13.8.0-rc42
Diffstat (limited to 'spec/frontend/registry/explorer/components')
13 files changed, 234 insertions, 159 deletions
diff --git a/spec/frontend/registry/explorer/components/__snapshots__/registry_breadcrumb_spec.js.snap b/spec/frontend/registry/explorer/components/__snapshots__/registry_breadcrumb_spec.js.snap index feae2f629b7..4be4fce1abf 100644 --- a/spec/frontend/registry/explorer/components/__snapshots__/registry_breadcrumb_spec.js.snap +++ b/spec/frontend/registry/explorer/components/__snapshots__/registry_breadcrumb_spec.js.snap @@ -1,28 +1,71 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Registry Breadcrumb when is rootRoute renders 1`] = ` -<ul> - <li - class="foo bar" +exports[`Registry Breadcrumb when is not rootRoute renders 1`] = ` +<div + class="gl-breadcrumbs" +> + <ol + class="breadcrumb gl-breadcrumb-list" > - baz - </li> - <li - class="foo bar" + + <li + class="breadcrumb-item gl-breadcrumb-item" + > + <a + class="" + href="/" + target="_self" + /> + </li> + + <span + class="gl-breadcrumb-separator" + data-testid="separator" + > + <svg + aria-hidden="true" + class="gl-icon s8" + data-testid="angle-right-icon" + > + <use + href="#angle-right" + /> + </svg> + </span> + <li + class="breadcrumb-item gl-breadcrumb-item" + > + <a + class="" + href="#" + target="_self" + /> + </li> + + <!----> + </ol> +</div> +`; + +exports[`Registry Breadcrumb when is rootRoute renders 1`] = ` +<div + class="gl-breadcrumbs" +> + <ol + class="breadcrumb gl-breadcrumb-list" > - foo - </li> - - <!----> - - <li> - <a - class="foo" + + <li + class="breadcrumb-item gl-breadcrumb-item" > - <a> - - </a> - </a> - </li> -</ul> + <a + class="" + href="/" + target="_self" + /> + </li> + + <!----> + </ol> +</div> `; diff --git a/spec/frontend/registry/explorer/components/delete_button_spec.js b/spec/frontend/registry/explorer/components/delete_button_spec.js index a79ca77a464..cd43e97009b 100644 --- a/spec/frontend/registry/explorer/components/delete_button_spec.js +++ b/spec/frontend/registry/explorer/components/delete_button_spec.js @@ -13,7 +13,7 @@ describe('delete_button', () => { const findButton = () => wrapper.find(GlButton); - const mountComponent = props => { + const mountComponent = (props) => { wrapper = shallowMount(component, { propsData: { ...defaultProps, 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 5d54986978b..6a7fbbe367a 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 @@ -15,7 +15,7 @@ describe('Delete alert', () => { const findAlert = () => wrapper.find(GlAlert); const findLink = () => wrapper.find(GlLink); - const mountComponent = propsData => { + const mountComponent = (propsData) => { wrapper = shallowMount(component, { stubs: { GlSprintf }, propsData }); }; 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 c77f7a54d34..636e0a285a6 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 @@ -13,7 +13,7 @@ describe('Delete Modal', () => { const findModal = () => wrapper.find(GlModal); const findDescription = () => wrapper.find('[data-testid="description"]'); - const mountComponent = propsData => { + const mountComponent = (propsData) => { wrapper = shallowMount(component, { propsData, stubs: { 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 f642c66832b..337235e3de5 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 @@ -3,7 +3,18 @@ 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 } from '~/registry/explorer/constants'; +import { + DETAILS_PAGE_TITLE, + UNSCHEDULED_STATUS, + SCHEDULED_STATUS, + ONGOING_STATUS, + UNFINISHED_STATUS, + CLEANUP_DISABLED_TEXT, + CLEANUP_DISABLED_TOOLTIP, + CLEANUP_SCHEDULED_TOOLTIP, + CLEANUP_ONGOING_TOOLTIP, + CLEANUP_UNFINISHED_TOOLTIP, +} from '~/registry/explorer/constants'; describe('Details Header', () => { let wrapper; @@ -11,15 +22,22 @@ describe('Details Header', () => { const defaultImage = { name: 'foo', updatedAt: '2020-11-03T13:29:21Z', + tagsCount: 10, project: { visibility: 'public', + containerExpirationPolicy: { + enabled: false, + }, }, }; // set the date to Dec 4, 2020 useFakeDate(2020, 11, 4); + const findByTestId = (testId) => wrapper.find(`[data-testid="${testId}"]`); - const findLastUpdatedAndVisibility = () => wrapper.find('[data-testid="updated-and-visibility"]'); + const findLastUpdatedAndVisibility = () => findByTestId('updated-and-visibility'); + const findTagsCount = () => findByTestId('tags-count'); + const findCleanup = () => findByTestId('cleanup'); const waitForMetadataItems = async () => { // Metadata items are printed by a loop in the title-area and it takes two ticks for them to be available @@ -54,25 +72,96 @@ describe('Details Header', () => { expect(wrapper.text()).toContain('foo'); }); - it('has a metadata item with last updated text', async () => { - mountComponent(); - await waitForMetadataItems(); + describe('metadata items', () => { + describe('tags count', () => { + it('when there is more than one tag has the correct text', async () => { + mountComponent(); + await waitForMetadataItems(); - expect(findLastUpdatedAndVisibility().props('text')).toBe('Last updated 1 month ago'); - }); + expect(findTagsCount().props('text')).toBe('10 tags'); + }); + + it('when there is one tag has the correct text', async () => { + mountComponent({ ...defaultImage, tagsCount: 1 }); + await waitForMetadataItems(); + + expect(findTagsCount().props('text')).toBe('1 tag'); + }); + + it('has the correct icon', async () => { + mountComponent(); + await waitForMetadataItems(); + + expect(findTagsCount().props('icon')).toBe('tag'); + }); + }); - describe('visibility icon', () => { - it('shows an eye when the project is public', async () => { - mountComponent(); - await waitForMetadataItems(); + describe('cleanup metadata item', () => { + it('has the correct icon', async () => { + mountComponent(); + await waitForMetadataItems(); - expect(findLastUpdatedAndVisibility().props('icon')).toBe('eye'); + expect(findCleanup().props('icon')).toBe('expire'); + }); + + it('when the expiration policy is disabled', async () => { + mountComponent(); + await waitForMetadataItems(); + + expect(findCleanup().props()).toMatchObject({ + text: CLEANUP_DISABLED_TEXT, + textTooltip: CLEANUP_DISABLED_TOOLTIP, + }); + }); + + it.each` + status | text | tooltip + ${UNSCHEDULED_STATUS} | ${'Cleanup will run in 1 month'} | ${''} + ${SCHEDULED_STATUS} | ${'Cleanup pending'} | ${CLEANUP_SCHEDULED_TOOLTIP} + ${ONGOING_STATUS} | ${'Cleanup in progress'} | ${CLEANUP_ONGOING_TOOLTIP} + ${UNFINISHED_STATUS} | ${'Cleanup incomplete'} | ${CLEANUP_UNFINISHED_TOOLTIP} + `( + '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' }, + }, + }); + await waitForMetadataItems(); + + expect(findCleanup().props()).toMatchObject({ + text, + textTooltip: tooltip, + }); + }, + ); }); - it('shows an eye slashed when the project is not public', async () => { - mountComponent({ ...defaultImage, project: { visibility: 'private' } }); - await waitForMetadataItems(); - expect(findLastUpdatedAndVisibility().props('icon')).toBe('eye-slash'); + describe('visibility and updated at ', () => { + it('has last updated text', async () => { + mountComponent(); + await waitForMetadataItems(); + + expect(findLastUpdatedAndVisibility().props('text')).toBe('Last updated 1 month ago'); + }); + + describe('visibility icon', () => { + it('shows an eye when the project is public', async () => { + mountComponent(); + await waitForMetadataItems(); + + expect(findLastUpdatedAndVisibility().props('icon')).toBe('eye'); + }); + it('shows an eye slashed when the project is not public', async () => { + mountComponent({ ...defaultImage, project: { visibility: 'private' } }); + await waitForMetadataItems(); + + expect(findLastUpdatedAndVisibility().props('icon')).toBe('eye-slash'); + }); + }); }); }); }); 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 94944643e8b..c2efc71c159 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 @@ -312,11 +312,7 @@ describe('tags list row', () => { }); it(`is ${clipboard} that clipboard button exist`, () => { - expect( - finderFunction() - .find(ClipboardButton) - .exists(), - ).toBe(clipboard); + expect(finderFunction().find(ClipboardButton).exists()).toBe(clipboard); }); }); }); 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 035b59731c9..413795a7a57 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 @@ -8,7 +8,7 @@ import { tagsMock } from '../../mock_data'; describe('Tags List', () => { let wrapper; const tags = [...tagsMock]; - const readOnlyTags = tags.map(t => ({ ...t, canDelete: false })); + const readOnlyTags = tags.map((t) => ({ ...t, canDelete: false })); const findTagsListRow = () => wrapper.findAll(TagsListRow); const findDeleteButton = () => wrapper.find(GlButton); @@ -78,18 +78,14 @@ describe('Tags List', () => { it('is enabled when at least one item is selected', async () => { mountComponent(); - findTagsListRow() - .at(0) - .vm.$emit('select'); + findTagsListRow().at(0).vm.$emit('select'); await wrapper.vm.$nextTick(); expect(findDeleteButton().attributes('disabled')).toBe(undefined); }); it('click event emits a deleted event with selected items', () => { mountComponent(); - findTagsListRow() - .at(0) - .vm.$emit('select'); + findTagsListRow().at(0).vm.$emit('select'); findDeleteButton().vm.$emit('click'); expect(wrapper.emitted('delete')).toEqual([[{ 'beta-24753': true }]]); @@ -116,22 +112,14 @@ describe('Tags List', () => { describe('events', () => { it('select event update the selected items', async () => { mountComponent(); - findTagsListRow() - .at(0) - .vm.$emit('select'); + findTagsListRow().at(0).vm.$emit('select'); await wrapper.vm.$nextTick(); - expect( - findTagsListRow() - .at(0) - .attributes('selected'), - ).toBe('true'); + expect(findTagsListRow().at(0).attributes('selected')).toBe('true'); }); it('delete event emit a delete event', () => { mountComponent(); - findTagsListRow() - .at(0) - .vm.$emit('delete'); + findTagsListRow().at(0).vm.$emit('delete'); expect(wrapper.emitted('delete')).toEqual([[{ 'beta-24753': true }]]); }); }); diff --git a/spec/frontend/registry/explorer/components/details_page/tags_loader_spec.js b/spec/frontend/registry/explorer/components/details_page/tags_loader_spec.js index b27d3e2c042..40d84d9d4a5 100644 --- a/spec/frontend/registry/explorer/components/details_page/tags_loader_spec.js +++ b/spec/frontend/registry/explorer/components/details_page/tags_loader_spec.js @@ -32,11 +32,7 @@ describe('TagsLoader component', () => { it('has the correct props', () => { mountComponent(); - expect( - findGlSkeletonLoaders() - .at(0) - .props(), - ).toMatchObject({ + expect(findGlSkeletonLoaders().at(0).props()).toMatchObject({ width: component.loader.width, height: component.loader.height, }); diff --git a/spec/frontend/registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap b/spec/frontend/registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap index bab6b25cc15..46b07b4c2d6 100644 --- a/spec/frontend/registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap +++ b/spec/frontend/registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap @@ -56,7 +56,7 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = ` </p> <gl-form-input-group-stub - class="gl-mb-4 " + class="gl-mb-4" predefinedoptions="[object Object]" value="" > 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 b9839d92f1d..a06c4795b2e 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,5 +1,5 @@ import { shallowMount } from '@vue/test-utils'; -import { GlIcon, GlSprintf } from '@gitlab/ui'; +import { GlIcon, GlSprintf, GlSkeletonLoader } from '@gitlab/ui'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; @@ -23,12 +23,13 @@ describe('Image List Row', () => { const [item] = imagesListResponse; const findDetailsLink = () => wrapper.find('[data-testid="details-link"]'); - const findTagsCount = () => wrapper.find('[data-testid="tagsCount"]'); + const findTagsCount = () => wrapper.find('[data-testid="tags-count"]'); const findDeleteBtn = () => wrapper.find(DeleteButton); const findClipboardButton = () => wrapper.find(ClipboardButton); const findWarningIcon = () => wrapper.find('[data-testid="warning-icon"]'); + const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader); - const mountComponent = props => { + const mountComponent = (props) => { wrapper = shallowMount(Component, { stubs: { RouterLink, @@ -164,6 +165,20 @@ describe('Image List Row', () => { expect(icon.props('name')).toBe('tag'); }); + describe('loading state', () => { + it('shows a loader when metadataLoading is true', () => { + mountComponent({ metadataLoading: true }); + + expect(findSkeletonLoader().exists()).toBe(true); + }); + + it('hides the tags count while loading', () => { + mountComponent({ metadataLoading: true }); + + expect(findTagsCount().exists()).toBe(false); + }); + }); + describe('tags count text', () => { it('with one tag in the image', () => { mountComponent({ item: { ...item, tagsCount: 1 } }); 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 54befc9973a..61c362f4d78 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 @@ -11,11 +11,12 @@ describe('Image List', () => { const findRow = () => wrapper.findAll(ImageListRow); const findPagination = () => wrapper.find(GlKeysetPagination); - const mountComponent = (pageInfo = defaultPageInfo) => { + const mountComponent = (props) => { wrapper = shallowMount(Component, { propsData: { images: imagesListResponse, - pageInfo, + pageInfo: defaultPageInfo, + ...props, }, }); }; @@ -35,11 +36,14 @@ describe('Image List', () => { it('when delete event is emitted on the row it emits up a delete event', () => { mountComponent(); - findRow() - .at(0) - .vm.$emit('delete', 'foo'); + findRow().at(0).vm.$emit('delete', 'foo'); expect(wrapper.emitted('delete')).toEqual([['foo']]); }); + + it('passes down the metadataLoading prop', () => { + mountComponent({ metadataLoading: true }); + expect(findRow().at(0).props('metadataLoading')).toBe(true); + }); }); describe('pagination', () => { @@ -57,7 +61,7 @@ describe('Image List', () => { `( 'when hasNextPage is $hasNextPage and hasPreviousPage is $hasPreviousPage: is $isVisible that the component is visible', ({ hasNextPage, hasPreviousPage, isVisible }) => { - mountComponent({ hasNextPage, hasPreviousPage }); + mountComponent({ pageInfo: { ...defaultPageInfo, hasNextPage, hasPreviousPage } }); expect(findPagination().exists()).toBe(isVisible); expect(findPagination().props('hasPreviousPage')).toBe(hasPreviousPage); @@ -66,7 +70,7 @@ describe('Image List', () => { ); it('emits "prev-page" when the user clicks the back page button', () => { - mountComponent({ hasPreviousPage: true }); + mountComponent(); findPagination().vm.$emit('prev'); @@ -74,7 +78,7 @@ describe('Image List', () => { }); it('emits "next-page" when the user clicks the forward page button', () => { - mountComponent({ hasNextPage: true }); + mountComponent(); findPagination().vm.$emit('next'); 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 3c997093d46..58439c185e3 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 @@ -41,9 +41,12 @@ describe('registry_header', () => { describe('header', () => { it('has a title', () => { - mountComponent(); + mountComponent({ metadataLoading: true }); - expect(findTitleArea().props('title')).toBe(CONTAINER_REGISTRY_TITLE); + expect(findTitleArea().props()).toMatchObject({ + title: CONTAINER_REGISTRY_TITLE, + metadataLoading: true, + }); }); it('has a commands slot', () => { diff --git a/spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js b/spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js index fb0b98ba004..487f33594c1 100644 --- a/spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js +++ b/spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js @@ -1,4 +1,4 @@ -import { shallowMount } from '@vue/test-utils'; +import { mount } from '@vue/test-utils'; import component from '~/registry/explorer/components/registry_breadcrumb.vue'; @@ -6,45 +6,13 @@ describe('Registry Breadcrumb', () => { let wrapper; const nameGenerator = jest.fn(); - const crumb = { - className: 'foo bar', - tagName: 'div', - innerHTML: 'baz', - querySelector: jest.fn(), - children: [ - { - tagName: 'a', - className: 'foo', - }, - ], - }; - - const querySelectorReturnValue = { - classList: ['js-divider'], - tagName: 'svg', - innerHTML: 'foo', - }; - - const crumbs = [crumb, { ...crumb, innerHTML: 'foo' }, { ...crumb, className: 'baz' }]; - const routes = [ - { name: 'foo', meta: { nameGenerator, root: true } }, - { name: 'baz', meta: { nameGenerator } }, + { name: 'list', path: '/', meta: { nameGenerator, root: true } }, + { name: 'details', path: '/:id', meta: { nameGenerator } }, ]; - const findDivider = () => wrapper.find('.js-divider'); - const findRootRoute = () => wrapper.find({ ref: 'rootRouteLink' }); - const findChildRoute = () => wrapper.find({ ref: 'childRouteLink' }); - const findLastCrumb = () => wrapper.find({ ref: 'lastCrumb' }); - - const mountComponent = $route => { - wrapper = shallowMount(component, { - propsData: { - crumbs, - }, - stubs: { - 'router-link': { name: 'router-link', template: '<a><slot></slot></a>', props: ['to'] }, - }, + const mountComponent = ($route) => { + wrapper = mount(component, { mocks: { $route, $router: { @@ -58,7 +26,6 @@ describe('Registry Breadcrumb', () => { beforeEach(() => { nameGenerator.mockClear(); - crumb.querySelector = jest.fn(); }); afterEach(() => { @@ -75,8 +42,11 @@ describe('Registry Breadcrumb', () => { expect(wrapper.element).toMatchSnapshot(); }); - it('contains a router-link for the child route', () => { - expect(findChildRoute().exists()).toBe(true); + it('contains only a single router-link to list', () => { + const links = wrapper.findAll('a'); + + expect(links).toHaveLength(1); + expect(links.at(0).attributes('href')).toBe('/'); }); it('the link text is calculated by nameGenerator', () => { @@ -86,52 +56,23 @@ describe('Registry Breadcrumb', () => { describe('when is not rootRoute', () => { beforeEach(() => { - crumb.querySelector.mockReturnValue(querySelectorReturnValue); mountComponent(routes[1]); }); - it('renders a divider', () => { - expect(findDivider().exists()).toBe(true); + it('renders', () => { + expect(wrapper.element).toMatchSnapshot(); }); - it('contains a router-link for the root route', () => { - expect(findRootRoute().exists()).toBe(true); - }); + it('contains two router-links to list and details', () => { + const links = wrapper.findAll('a'); - it('contains a router-link for the child route', () => { - expect(findChildRoute().exists()).toBe(true); + expect(links).toHaveLength(2); + expect(links.at(0).attributes('href')).toBe('/'); + expect(links.at(1).attributes('href')).toBe('#'); }); it('the link text is calculated by nameGenerator', () => { expect(nameGenerator).toHaveBeenCalledTimes(2); }); }); - - describe('last crumb', () => { - const lastChildren = crumb.children[0]; - beforeEach(() => { - nameGenerator.mockReturnValue('foo'); - mountComponent(routes[0]); - }); - - it('has the same tag as the last children of the crumbs', () => { - expect(findLastCrumb().element.tagName).toBe(lastChildren.tagName.toUpperCase()); - }); - - it('has the same classes as the last children of the crumbs', () => { - expect( - findLastCrumb() - .classes() - .join(' '), - ).toEqual(lastChildren.className); - }); - - it('has a link to the current route', () => { - expect(findChildRoute().props('to')).toEqual({ to: routes[0].name }); - }); - - it('the link has the correct text', () => { - expect(findChildRoute().text()).toEqual('foo'); - }); - }); }); |