diff options
Diffstat (limited to 'spec/frontend/packages/shared')
7 files changed, 519 insertions, 0 deletions
diff --git a/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap b/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap new file mode 100644 index 00000000000..eab8d7b67cc --- /dev/null +++ b/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap @@ -0,0 +1,101 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`packages_list_row renders 1`] = ` +<div + class="gl-responsive-table-row" + data-qa-selector="packages-row" +> + <div + class="table-section section-50 d-flex flex-md-column justify-content-between flex-wrap" + > + <div + class="d-flex align-items-center mr-2" + > + <gl-link-stub + class="text-dark font-weight-bold mb-md-1" + data-qa-selector="package_link" + href="foo" + > + + Test package + + </gl-link-stub> + + <!----> + </div> + + <div + class="d-flex text-secondary text-truncate mt-md-2" + > + <span> + 1.0.0 + </span> + + <!----> + + <div + class="d-flex align-items-center" + > + <gl-icon-stub + class="text-secondary ml-2 mr-1" + name="review-list" + size="16" + /> + + <gl-link-stub + class="text-secondary" + data-testid="packages-row-project" + href="/foo/bar/baz" + > + + </gl-link-stub> + </div> + + <div + class="d-flex align-items-center" + data-testid="package-type" + > + <gl-icon-stub + class="text-secondary ml-2 mr-1" + name="package" + size="16" + /> + + <span> + Maven + </span> + </div> + </div> + </div> + + <div + class="table-section d-flex flex-md-column justify-content-between align-items-md-end section-40" + > + <publish-method-stub + packageentity="[object Object]" + /> + + <div + class="text-secondary order-0 order-md-1 mt-md-2" + > + <gl-sprintf-stub + message="Created %{timestamp}" + /> + </div> + </div> + + <div + class="table-section section-10 d-flex justify-content-end" + > + <gl-button-stub + aria-label="Remove package" + category="primary" + data-testid="action-delete" + icon="remove" + size="medium" + title="Remove package" + variant="danger" + /> + </div> +</div> +`; diff --git a/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap b/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap new file mode 100644 index 00000000000..5ecca63d41d --- /dev/null +++ b/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`publish_method renders 1`] = ` +<div + class="d-flex align-items-center text-secondary order-1 order-md-0 mb-md-1" +> + <gl-icon-stub + class="mr-1" + name="git-merge" + size="16" + /> + + <strong + class="mr-1 text-dark" + > + branch-name + </strong> + + <gl-icon-stub + class="mr-1" + name="commit" + size="16" + /> + + <gl-link-stub + class="mr-1" + href="../commit/sha-baz" + > + sha-baz + </gl-link-stub> + + <clipboard-button-stub + cssclass="border-0 text-secondary py-0 px-1" + text="sha-baz" + title="Copy commit SHA" + tooltipplacement="top" + /> +</div> +`; diff --git a/spec/frontend/packages/shared/components/package_list_row_spec.js b/spec/frontend/packages/shared/components/package_list_row_spec.js new file mode 100644 index 00000000000..c0ae972d519 --- /dev/null +++ b/spec/frontend/packages/shared/components/package_list_row_spec.js @@ -0,0 +1,106 @@ +import { mount, shallowMount } from '@vue/test-utils'; +import PackagesListRow from '~/packages/shared/components/package_list_row.vue'; +import PackageTags from '~/packages/shared/components/package_tags.vue'; +import { packageList } from '../../mock_data'; + +describe('packages_list_row', () => { + let wrapper; + let store; + + const [packageWithoutTags, packageWithTags] = packageList; + + const findPackageTags = () => wrapper.find(PackageTags); + const findProjectLink = () => wrapper.find('[data-testid="packages-row-project"]'); + const findDeleteButton = () => wrapper.find('[data-testid="action-delete"]'); + const findPackageType = () => wrapper.find('[data-testid="package-type"]'); + + const mountComponent = ({ + isGroup = false, + packageEntity = packageWithoutTags, + shallow = true, + showPackageType = true, + disableDelete = false, + } = {}) => { + const mountFunc = shallow ? shallowMount : mount; + + wrapper = mountFunc(PackagesListRow, { + store, + propsData: { + packageLink: 'foo', + packageEntity, + isGroup, + showPackageType, + disableDelete, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + it('renders', () => { + mountComponent(); + expect(wrapper.element).toMatchSnapshot(); + }); + + describe('tags', () => { + it('renders package tags when a package has tags', () => { + mountComponent({ isGroup: false, packageEntity: packageWithTags }); + + expect(findPackageTags().exists()).toBe(true); + }); + + it('does not render when there are no tags', () => { + mountComponent(); + + expect(findPackageTags().exists()).toBe(false); + }); + }); + + describe('when is is group', () => { + beforeEach(() => { + mountComponent({ isGroup: true }); + }); + + it('has project field', () => { + expect(findProjectLink().exists()).toBe(true); + }); + }); + + describe('showPackageType', () => { + it('shows the type when set', () => { + mountComponent(); + + expect(findPackageType().exists()).toBe(true); + }); + + it('does not show the type when not set', () => { + mountComponent({ showPackageType: false }); + + expect(findPackageType().exists()).toBe(false); + }); + }); + + describe('deleteAvailable', () => { + it('does not show when not set', () => { + mountComponent({ disableDelete: true }); + + expect(findDeleteButton().exists()).toBe(false); + }); + }); + + describe('delete event', () => { + beforeEach(() => mountComponent({ packageEntity: packageWithoutTags, shallow: false })); + + it('emits the packageToDelete event when the delete button is clicked', () => { + findDeleteButton().trigger('click'); + + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.emitted('packageToDelete')).toBeTruthy(); + expect(wrapper.emitted('packageToDelete')[0]).toEqual([packageWithoutTags]); + }); + }); + }); +}); diff --git a/spec/frontend/packages/shared/components/package_tags_spec.js b/spec/frontend/packages/shared/components/package_tags_spec.js new file mode 100644 index 00000000000..cc49a9a9244 --- /dev/null +++ b/spec/frontend/packages/shared/components/package_tags_spec.js @@ -0,0 +1,115 @@ +import { mount } from '@vue/test-utils'; +import PackageTags from '~/packages/shared/components/package_tags.vue'; +import { mockTags } from '../../mock_data'; + +describe('PackageTags', () => { + let wrapper; + + function createComponent(tags = [], props = {}) { + const propsData = { + tags, + ...props, + }; + + wrapper = mount(PackageTags, { + propsData, + }); + } + + const tagLabel = () => wrapper.find('[data-testid="tagLabel"]'); + const tagBadges = () => wrapper.findAll('[data-testid="tagBadge"]'); + const moreBadge = () => wrapper.find('[data-testid="moreBadge"]'); + + afterEach(() => { + if (wrapper) wrapper.destroy(); + }); + + describe('tag label', () => { + it('shows the tag label by default', () => { + createComponent(); + + expect(tagLabel().exists()).toBe(true); + }); + + it('hides when hideLabel prop is set to true', () => { + createComponent(mockTags, { hideLabel: true }); + + expect(tagLabel().exists()).toBe(false); + }); + }); + + it('renders the correct number of tags', () => { + createComponent(mockTags.slice(0, 2)); + + expect(tagBadges()).toHaveLength(2); + expect(moreBadge().exists()).toBe(false); + }); + + it('does not render more than the configured tagDisplayLimit', () => { + createComponent(mockTags); + + expect(tagBadges()).toHaveLength(2); + }); + + it('renders the more tags badge if there are more than the configured limit', () => { + createComponent(mockTags); + + expect(tagBadges()).toHaveLength(2); + expect(moreBadge().exists()).toBe(true); + expect(moreBadge().text()).toContain('2'); + }); + + it('renders the configured tagDisplayLimit when set in props', () => { + createComponent(mockTags, { tagDisplayLimit: 1 }); + + expect(tagBadges()).toHaveLength(1); + expect(moreBadge().exists()).toBe(true); + expect(moreBadge().text()).toContain('3'); + }); + + describe('tagBadgeStyle', () => { + const defaultStyle = ['badge', 'badge-info', 'gl-display-none']; + + it('shows tag badge when there is only one', () => { + createComponent([mockTags[0]]); + + const expectedStyle = [...defaultStyle, 'gl-display-flex', 'gl-ml-3']; + + expect( + tagBadges() + .at(0) + .classes(), + ).toEqual(expect.arrayContaining(expectedStyle)); + }); + + it('shows tag badge for medium or heigher resolutions', () => { + createComponent(mockTags); + + const expectedStyle = [...defaultStyle, 'd-md-flex']; + + expect( + tagBadges() + .at(1) + .classes(), + ).toEqual(expect.arrayContaining(expectedStyle)); + }); + + it('correctly prepends left and appends right when there is more than one tag', () => { + createComponent(mockTags, { + tagDisplayLimit: 4, + }); + + const expectedStyleWithoutAppend = [...defaultStyle, 'd-md-flex']; + const expectedStyleWithAppend = [...expectedStyleWithoutAppend, 'gl-mr-2']; + + const allBadges = tagBadges(); + + expect(allBadges.at(0).classes()).toEqual( + expect.arrayContaining([...expectedStyleWithAppend, 'gl-ml-3']), + ); + expect(allBadges.at(1).classes()).toEqual(expect.arrayContaining(expectedStyleWithAppend)); + expect(allBadges.at(2).classes()).toEqual(expect.arrayContaining(expectedStyleWithAppend)); + expect(allBadges.at(3).classes()).toEqual(expect.arrayContaining(expectedStyleWithoutAppend)); + }); + }); +}); diff --git a/spec/frontend/packages/shared/components/packages_list_loader_spec.js b/spec/frontend/packages/shared/components/packages_list_loader_spec.js new file mode 100644 index 00000000000..c8c2e2a4ba4 --- /dev/null +++ b/spec/frontend/packages/shared/components/packages_list_loader_spec.js @@ -0,0 +1,42 @@ +import { mount } from '@vue/test-utils'; +import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue'; + +describe('PackagesListLoader', () => { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = mount(PackagesListLoader, { + propsData: { + ...props, + }, + }); + }; + + const getShapes = () => wrapper.vm.desktopShapes; + const findSquareButton = () => wrapper.find({ ref: 'button-loader' }); + + beforeEach(createComponent); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('when used for projects', () => { + it('should return 5 rects with last one being a square', () => { + expect(getShapes()).toHaveLength(5); + expect(findSquareButton().exists()).toBe(true); + }); + }); + + describe('when used for groups', () => { + beforeEach(() => { + createComponent({ isGroup: true }); + }); + + it('should return 5 rects with no square', () => { + expect(getShapes()).toHaveLength(5); + expect(findSquareButton().exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/packages/shared/components/publish_method_spec.js b/spec/frontend/packages/shared/components/publish_method_spec.js new file mode 100644 index 00000000000..bb9287c1204 --- /dev/null +++ b/spec/frontend/packages/shared/components/publish_method_spec.js @@ -0,0 +1,50 @@ +import { shallowMount } from '@vue/test-utils'; +import PublishMethod from '~/packages/shared/components/publish_method.vue'; +import { packageList } from '../../mock_data'; + +describe('publish_method', () => { + let wrapper; + + const [packageWithoutPipeline, packageWithPipeline] = packageList; + + const findPipelineRef = () => wrapper.find({ ref: 'pipeline-ref' }); + const findPipelineSha = () => wrapper.find({ ref: 'pipeline-sha' }); + const findManualPublish = () => wrapper.find({ ref: 'manual-ref' }); + + const mountComponent = (packageEntity = {}, isGroup = false) => { + wrapper = shallowMount(PublishMethod, { + propsData: { + packageEntity, + isGroup, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + it('renders', () => { + mountComponent(packageWithPipeline); + expect(wrapper.element).toMatchSnapshot(); + }); + + describe('pipeline information', () => { + it('displays branch and commit when pipeline info exists', () => { + mountComponent(packageWithPipeline); + + expect(findPipelineRef().exists()).toBe(true); + expect(findPipelineSha().exists()).toBe(true); + }); + + it('does not show any pipeline details when no information exists', () => { + mountComponent(packageWithoutPipeline); + + expect(findPipelineRef().exists()).toBe(false); + expect(findPipelineSha().exists()).toBe(false); + expect(findManualPublish().exists()).toBe(true); + expect(findManualPublish().text()).toBe('Manually Published'); + }); + }); +}); diff --git a/spec/frontend/packages/shared/utils_spec.js b/spec/frontend/packages/shared/utils_spec.js new file mode 100644 index 00000000000..1fe90a4827f --- /dev/null +++ b/spec/frontend/packages/shared/utils_spec.js @@ -0,0 +1,66 @@ +import { + packageTypeToTrackCategory, + beautifyPath, + getPackageTypeLabel, + getCommitLink, +} from '~/packages/shared/utils'; +import { PackageType, TrackingCategories } from '~/packages/shared/constants'; +import { packageList } from '../mock_data'; + +describe('Packages shared utils', () => { + describe('packageTypeToTrackCategory', () => { + it('prepend UI to package category', () => { + expect(packageTypeToTrackCategory()).toMatchInlineSnapshot(`"UI::undefined"`); + }); + + it.each(Object.keys(PackageType))('returns a correct category string for %s', packageKey => { + const packageName = PackageType[packageKey]; + expect(packageTypeToTrackCategory(packageName)).toBe( + `UI::${TrackingCategories[packageName]}`, + ); + }); + }); + + describe('beautifyPath', () => { + it('returns a string with spaces around /', () => { + expect(beautifyPath('foo/bar')).toBe('foo / bar'); + }); + it('does not fail for empty string', () => { + expect(beautifyPath()).toBe(''); + }); + }); + + describe('getPackageTypeLabel', () => { + describe.each` + packageType | expectedResult + ${'conan'} | ${'Conan'} + ${'maven'} | ${'Maven'} + ${'npm'} | ${'NPM'} + ${'nuget'} | ${'NuGet'} + ${'pypi'} | ${'PyPi'} + ${'composer'} | ${'Composer'} + ${'foo'} | ${null} + `(`package type`, ({ packageType, expectedResult }) => { + it(`${packageType} should show as ${expectedResult}`, () => { + expect(getPackageTypeLabel(packageType)).toBe(expectedResult); + }); + }); + }); + + describe('getCommitLink', () => { + it('returns a relative link when isGroup is false', () => { + const link = getCommitLink(packageList[0], false); + + expect(link).toContain('../commit'); + }); + + describe('when isGroup is true', () => { + it('returns an absolute link matching project path', () => { + const mavenPackage = packageList[0]; + const link = getCommitLink(mavenPackage, true); + + expect(link).toContain(`/${mavenPackage.project_path}/commit`); + }); + }); + }); +}); |