diff options
Diffstat (limited to 'spec/frontend/packages')
17 files changed, 730 insertions, 820 deletions
diff --git a/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap b/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap index 4d9e0af1545..d317264bdae 100644 --- a/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap +++ b/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap @@ -2,151 +2,163 @@ exports[`PackageTitle renders with tags 1`] = ` <div - class="gl-display-flex gl-justify-content-space-between gl-py-3" + class="gl-display-flex gl-flex-direction-column" data-qa-selector="package_title" > <div - class="gl-flex-direction-column" + class="gl-display-flex gl-justify-content-space-between gl-py-3" > <div - class="gl-display-flex" + class="gl-flex-direction-column" > - <!----> - <div - class="gl-display-flex gl-flex-direction-column" + class="gl-display-flex" > - <h1 - class="gl-font-size-h1 gl-mt-3 gl-mb-2" - data-testid="title" - > - Test package - </h1> + <!----> <div - class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1" + class="gl-display-flex gl-flex-direction-column" > - <gl-icon-stub - class="gl-mr-3" - name="eye" - size="16" - /> + <h1 + class="gl-font-size-h1 gl-mt-3 gl-mb-2" + data-testid="title" + > + Test package + </h1> - <gl-sprintf-stub - message="v%{version} published %{timeAgo}" - /> + <div + class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1" + > + <gl-icon-stub + class="gl-mr-3" + name="eye" + size="16" + /> + + <gl-sprintf-stub + message="v%{version} published %{timeAgo}" + /> + </div> </div> </div> - </div> - - <div - class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3" - > - <div - class="gl-display-flex gl-align-items-center gl-mr-5" - > - <metadata-item-stub - data-testid="package-type" - icon="package" - link="" - size="s" - text="maven" - /> - </div> - <div - class="gl-display-flex gl-align-items-center gl-mr-5" - > - <metadata-item-stub - data-testid="package-size" - icon="disk" - link="" - size="s" - text="300 bytes" - /> - </div> + <div - class="gl-display-flex gl-align-items-center gl-mr-5" + class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3" > - <package-tags-stub - hidelabel="true" - tagdisplaylimit="2" - tags="[object Object],[object Object],[object Object],[object Object]" - /> + <div + class="gl-display-flex gl-align-items-center gl-mr-5" + > + <metadata-item-stub + data-testid="package-type" + icon="package" + link="" + size="s" + text="maven" + /> + </div> + <div + class="gl-display-flex gl-align-items-center gl-mr-5" + > + <metadata-item-stub + data-testid="package-size" + icon="disk" + link="" + size="s" + text="300 bytes" + /> + </div> + <div + class="gl-display-flex gl-align-items-center gl-mr-5" + > + <package-tags-stub + hidelabel="true" + tagdisplaylimit="2" + tags="[object Object],[object Object],[object Object],[object Object]" + /> + </div> </div> </div> + + <!----> </div> - <!----> + <p /> </div> `; exports[`PackageTitle renders without tags 1`] = ` <div - class="gl-display-flex gl-justify-content-space-between gl-py-3" + class="gl-display-flex gl-flex-direction-column" data-qa-selector="package_title" > <div - class="gl-flex-direction-column" + class="gl-display-flex gl-justify-content-space-between gl-py-3" > <div - class="gl-display-flex" + class="gl-flex-direction-column" > - <!----> - <div - class="gl-display-flex gl-flex-direction-column" + class="gl-display-flex" > - <h1 - class="gl-font-size-h1 gl-mt-3 gl-mb-2" - data-testid="title" - > - Test package - </h1> + <!----> <div - class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1" + class="gl-display-flex gl-flex-direction-column" > - <gl-icon-stub - class="gl-mr-3" - name="eye" - size="16" - /> + <h1 + class="gl-font-size-h1 gl-mt-3 gl-mb-2" + data-testid="title" + > + Test package + </h1> - <gl-sprintf-stub - message="v%{version} published %{timeAgo}" - /> + <div + class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1" + > + <gl-icon-stub + class="gl-mr-3" + name="eye" + size="16" + /> + + <gl-sprintf-stub + message="v%{version} published %{timeAgo}" + /> + </div> </div> </div> - </div> - - <div - class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3" - > - <div - class="gl-display-flex gl-align-items-center gl-mr-5" - > - <metadata-item-stub - data-testid="package-type" - icon="package" - link="" - size="s" - text="maven" - /> - </div> + <div - class="gl-display-flex gl-align-items-center gl-mr-5" + class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3" > - <metadata-item-stub - data-testid="package-size" - icon="disk" - link="" - size="s" - text="300 bytes" - /> + <div + class="gl-display-flex gl-align-items-center gl-mr-5" + > + <metadata-item-stub + data-testid="package-type" + icon="package" + link="" + size="s" + text="maven" + /> + </div> + <div + class="gl-display-flex gl-align-items-center gl-mr-5" + > + <metadata-item-stub + data-testid="package-size" + icon="disk" + link="" + size="s" + text="300 bytes" + /> + </div> </div> </div> + + <!----> </div> - <!----> + <p /> </div> `; diff --git a/spec/frontend/packages/details/components/composer_installation_spec.js b/spec/frontend/packages/details/components/composer_installation_spec.js index c13981fbb87..b44609e8ae7 100644 --- a/spec/frontend/packages/details/components/composer_installation_spec.js +++ b/spec/frontend/packages/details/components/composer_installation_spec.js @@ -12,21 +12,23 @@ localVue.use(Vuex); describe('ComposerInstallation', () => { let wrapper; + let store; const composerRegistryIncludeStr = 'foo/registry'; const composerPackageIncludeStr = 'foo/package'; - const store = new Vuex.Store({ - state: { - packageEntity, - composerHelpPath, - }, - getters: { - composerRegistryInclude: () => composerRegistryIncludeStr, - composerPackageInclude: () => composerPackageIncludeStr, - }, - }); + const createStore = (groupExists = true) => { + store = new Vuex.Store({ + state: { packageEntity, composerHelpPath }, + getters: { + composerRegistryInclude: () => composerRegistryIncludeStr, + composerPackageInclude: () => composerPackageIncludeStr, + groupExists: () => groupExists, + }, + }); + }; + const findRootNode = () => wrapper.find('[data-testid="root-node"]'); const findRegistryInclude = () => wrapper.find('[data-testid="registry-include"]'); const findPackageInclude = () => wrapper.find('[data-testid="package-include"]'); const findHelpText = () => wrapper.find('[data-testid="help-text"]'); @@ -42,15 +44,16 @@ describe('ComposerInstallation', () => { }); } - beforeEach(() => { - createComponent(); - }); - afterEach(() => { wrapper.destroy(); }); describe('registry include command', () => { + beforeEach(() => { + createStore(); + createComponent(); + }); + it('uses code_instructions', () => { const registryIncludeCommand = findRegistryInclude(); expect(registryIncludeCommand.exists()).toBe(true); @@ -62,11 +65,16 @@ describe('ComposerInstallation', () => { }); it('has the correct title', () => { - expect(findRegistryInclude().props('label')).toBe('composer.json registry include'); + expect(findRegistryInclude().props('label')).toBe('Add composer registry'); }); }); describe('package include command', () => { + beforeEach(() => { + createStore(); + createComponent(); + }); + it('uses code_instructions', () => { const registryIncludeCommand = findPackageInclude(); expect(registryIncludeCommand.exists()).toBe(true); @@ -78,7 +86,7 @@ describe('ComposerInstallation', () => { }); it('has the correct title', () => { - expect(findPackageInclude().props('label')).toBe('composer.json require package include'); + expect(findPackageInclude().props('label')).toBe('Install package version'); }); it('has the correct help text', () => { @@ -91,4 +99,20 @@ describe('ComposerInstallation', () => { }); }); }); + + describe('root node', () => { + it('is normally rendered', () => { + createStore(); + createComponent(); + + expect(findRootNode().exists()).toBe(true); + }); + + it('is not rendered when the group does not exist', () => { + createStore(false); + createComponent(); + + expect(findRootNode().exists()).toBe(false); + }); + }); }); diff --git a/spec/frontend/packages/details/store/getters_spec.js b/spec/frontend/packages/details/store/getters_spec.js index 0e95ee4cfd3..b8c2138e7f5 100644 --- a/spec/frontend/packages/details/store/getters_spec.js +++ b/spec/frontend/packages/details/store/getters_spec.js @@ -15,6 +15,7 @@ import { pypiSetupCommand, composerRegistryInclude, composerPackageInclude, + groupExists, } from '~/packages/details/store/getters'; import { conanPackage, @@ -31,7 +32,6 @@ import { registryUrl, pypiSetupCommandStr, } from '../mock_data'; -import { generateConanRecipe } from '~/packages/details/utils'; import { NpmManager } from '~/packages/details/constants'; describe('Getters PackageDetails Store', () => { @@ -53,8 +53,7 @@ describe('Getters PackageDetails Store', () => { }; }; - const recipe = generateConanRecipe(conanPackage); - const conanInstallationCommandStr = `conan install ${recipe} --remote=gitlab`; + const conanInstallationCommandStr = `conan install ${conanPackage.name} --remote=gitlab`; const conanSetupCommandStr = `conan remote add gitlab ${registryUrl}`; const mavenCommandStr = generateMavenCommand(packageWithoutBuildInfo.maven_metadatum); @@ -69,11 +68,12 @@ describe('Getters PackageDetails Store', () => { const nugetInstallationCommandStr = `nuget install ${nugetPackage.name} -Source "GitLab"`; const nugetSetupCommandStr = `nuget source Add -Name "GitLab" -Source "${registryUrl}" -UserName <your_username> -Password <your_token>`; - const pypiPipCommandStr = `pip install ${pypiPackage.name} --index-url ${registryUrl}`; - const composerRegistryIncludeStr = '{"type":"composer","url":"foo"}'; - const composerPackageIncludeStr = JSON.stringify({ - [packageWithoutBuildInfo.name]: packageWithoutBuildInfo.version, - }); + const pypiPipCommandStr = `pip install ${pypiPackage.name} --extra-index-url ${registryUrl}`; + const composerRegistryIncludeStr = + 'composer config repositories.gitlab.com/123 \'{"type": "composer", "url": "foo"}\''; + const composerPackageIncludeStr = `composer req ${[packageWithoutBuildInfo.name]}:${ + packageWithoutBuildInfo.version + }`; describe('packagePipeline', () => { it('should return the pipeline info when pipeline exists', () => { @@ -101,7 +101,7 @@ describe('Getters PackageDetails Store', () => { ${packageWithoutBuildInfo} | ${'Maven'} ${npmPackage} | ${'NPM'} ${nugetPackage} | ${'NuGet'} - ${pypiPackage} | ${'PyPi'} + ${pypiPackage} | ${'PyPI'} `(`package type`, ({ packageEntity, expectedResult }) => { beforeEach(() => setupState({ packageEntity })); @@ -223,7 +223,7 @@ describe('Getters PackageDetails Store', () => { describe('composer string getters', () => { it('gets the correct composerRegistryInclude command', () => { - setupState({ composerPath: 'foo' }); + setupState({ composerPath: 'foo', composerConfigRepositoryName: 'gitlab.com/123' }); expect(composerRegistryInclude(state)).toBe(composerRegistryIncludeStr); }); @@ -234,4 +234,18 @@ describe('Getters PackageDetails Store', () => { expect(composerPackageInclude(state)).toBe(composerPackageIncludeStr); }); }); + + describe('check if group', () => { + it('is set', () => { + setupState({ groupListUrl: '/groups/composer/-/packages' }); + + expect(groupExists(state)).toBe(true); + }); + + it('is not set', () => { + setupState({ groupListUrl: '' }); + + expect(groupExists(state)).toBe(false); + }); + }); }); diff --git a/spec/frontend/packages/details/utils_spec.js b/spec/frontend/packages/details/utils_spec.js deleted file mode 100644 index 087888016ee..00000000000 --- a/spec/frontend/packages/details/utils_spec.js +++ /dev/null @@ -1,24 +0,0 @@ -import { generateConanRecipe } from '~/packages/details/utils'; -import { conanPackage } from '../mock_data'; - -describe('Package detail utils', () => { - describe('generateConanRecipe', () => { - it('correctly generates the conan recipe', () => { - const recipe = generateConanRecipe(conanPackage); - - expect(recipe).toEqual(conanPackage.recipe); - }); - - it('returns an empty recipe when no information is supplied', () => { - const recipe = generateConanRecipe({}); - - expect(recipe).toEqual('/@/'); - }); - - it('recipe returns empty strings for missing metadata', () => { - const recipe = generateConanRecipe({ name: 'foo', version: '0.0.1' }); - - expect(recipe).toBe('foo/0.0.1@/'); - }); - }); -}); diff --git a/spec/frontend/packages/list/coming_soon/helpers_spec.js b/spec/frontend/packages/list/coming_soon/helpers_spec.js deleted file mode 100644 index 4a996bfad76..00000000000 --- a/spec/frontend/packages/list/coming_soon/helpers_spec.js +++ /dev/null @@ -1,36 +0,0 @@ -import * as comingSoon from '~/packages/list/coming_soon/helpers'; -import { fakeIssues, asGraphQLResponse, asViewModel } from './mock_data'; - -jest.mock('~/api.js'); - -describe('Coming Soon Helpers', () => { - const [noLabels, acceptingMergeRequestLabel, workflowLabel] = fakeIssues; - - describe('toViewModel', () => { - it('formats a GraphQL response correctly', () => { - expect(comingSoon.toViewModel(asGraphQLResponse)).toEqual(asViewModel); - }); - }); - - describe('findWorkflowLabel', () => { - it('finds a workflow label', () => { - expect(comingSoon.findWorkflowLabel(workflowLabel.labels)).toEqual(workflowLabel.labels[0]); - }); - - it("returns undefined when there isn't one", () => { - expect(comingSoon.findWorkflowLabel(noLabels.labels)).toBeUndefined(); - }); - }); - - describe('findAcceptingContributionsLabel', () => { - it('finds the correct label when it exists', () => { - expect(comingSoon.findAcceptingContributionsLabel(acceptingMergeRequestLabel.labels)).toEqual( - acceptingMergeRequestLabel.labels[0], - ); - }); - - it("returns undefined when there isn't one", () => { - expect(comingSoon.findAcceptingContributionsLabel(noLabels.labels)).toBeUndefined(); - }); - }); -}); diff --git a/spec/frontend/packages/list/coming_soon/mock_data.js b/spec/frontend/packages/list/coming_soon/mock_data.js deleted file mode 100644 index bb4568e4bd5..00000000000 --- a/spec/frontend/packages/list/coming_soon/mock_data.js +++ /dev/null @@ -1,90 +0,0 @@ -export const fakeIssues = [ - { - id: 1, - iid: 1, - title: 'issue one', - webUrl: 'foo', - }, - { - id: 2, - iid: 2, - title: 'issue two', - labels: [{ title: 'Accepting merge requests', color: '#69d100' }], - milestone: { - title: '12.10', - }, - webUrl: 'foo', - }, - { - id: 3, - iid: 3, - title: 'issue three', - labels: [{ title: 'workflow::In dev', color: '#428bca' }], - webUrl: 'foo', - }, - { - id: 4, - iid: 4, - title: 'issue four', - labels: [ - { title: 'Accepting merge requests', color: '#69d100' }, - { title: 'workflow::In dev', color: '#428bca' }, - ], - webUrl: 'foo', - }, -]; - -export const asGraphQLResponse = { - project: { - issues: { - nodes: fakeIssues.map(x => ({ - ...x, - labels: { - nodes: x.labels, - }, - })), - }, - }, -}; - -export const asViewModel = [ - { - ...fakeIssues[0], - labels: [], - }, - { - ...fakeIssues[1], - labels: [ - { - title: 'Accepting merge requests', - color: '#69d100', - scoped: false, - }, - ], - }, - { - ...fakeIssues[2], - labels: [ - { - title: 'workflow::In dev', - color: '#428bca', - scoped: true, - }, - ], - }, - { - ...fakeIssues[3], - labels: [ - { - title: 'workflow::In dev', - color: '#428bca', - scoped: true, - }, - { - title: 'Accepting merge requests', - color: '#69d100', - scoped: false, - }, - ], - }, -]; diff --git a/spec/frontend/packages/list/coming_soon/packages_coming_soon_spec.js b/spec/frontend/packages/list/coming_soon/packages_coming_soon_spec.js deleted file mode 100644 index c4cdadc45e6..00000000000 --- a/spec/frontend/packages/list/coming_soon/packages_coming_soon_spec.js +++ /dev/null @@ -1,138 +0,0 @@ -import { GlEmptyState, GlSkeletonLoader, GlLabel } from '@gitlab/ui'; -import { mount, createLocalVue } from '@vue/test-utils'; -import VueApollo, { ApolloQuery } from 'vue-apollo'; -import ComingSoon from '~/packages/list/coming_soon/packages_coming_soon.vue'; -import { TrackingActions } from '~/packages/shared/constants'; -import { asViewModel } from './mock_data'; -import Tracking from '~/tracking'; - -jest.mock('~/packages/list/coming_soon/helpers.js'); - -const localVue = createLocalVue(); -localVue.use(VueApollo); - -describe('packages_coming_soon', () => { - let wrapper; - - const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader); - const findAllIssues = () => wrapper.findAll('[data-testid="issue-row"]'); - const findIssuesData = () => - findAllIssues().wrappers.map(x => { - const titleLink = x.find('[data-testid="issue-title-link"]'); - const milestone = x.find('[data-testid="milestone"]'); - const issueIdLink = x.find('[data-testid="issue-id-link"]'); - const labels = x.findAll(GlLabel); - - const issueId = Number(issueIdLink.text().substr(1)); - - return { - id: issueId, - iid: issueId, - title: titleLink.text(), - webUrl: titleLink.attributes('href'), - labels: labels.wrappers.map(label => ({ - color: label.props('backgroundColor'), - title: label.props('title'), - scoped: label.props('scoped'), - })), - ...(milestone.exists() ? { milestone: { title: milestone.text() } } : {}), - }; - }); - const findIssueTitleLink = () => wrapper.find('[data-testid="issue-title-link"]'); - const findIssueIdLink = () => wrapper.find('[data-testid="issue-id-link"]'); - const findEmptyState = () => wrapper.find(GlEmptyState); - - const mountComponent = (testParams = {}) => { - const $apolloData = { - loading: testParams.isLoading || false, - }; - - wrapper = mount(ComingSoon, { - localVue, - propsData: { - illustration: 'foo', - projectPath: 'foo', - suggestedContributionsPath: 'foo', - }, - stubs: { - ApolloQuery, - GlLink: true, - }, - mocks: { - $apolloData, - }, - }); - - // Mock the GraphQL query result - wrapper.find(ApolloQuery).setData({ - result: { - data: testParams.issues || asViewModel, - }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - }); - - describe('when loading', () => { - beforeEach(() => mountComponent({ isLoading: true })); - - it('renders the skeleton loader', () => { - expect(findSkeletonLoader().exists()).toBe(true); - }); - }); - - describe('when there are no issues', () => { - beforeEach(() => mountComponent({ issues: [] })); - - it('renders the empty state', () => { - expect(findEmptyState().exists()).toBe(true); - }); - }); - - describe('when there are issues', () => { - beforeEach(() => mountComponent()); - - it('renders each issue', () => { - expect(findIssuesData()).toEqual(asViewModel); - }); - }); - - describe('tracking', () => { - const firstIssue = asViewModel[0]; - let eventSpy; - - beforeEach(() => { - eventSpy = jest.spyOn(Tracking, 'event'); - mountComponent(); - }); - - it('tracks when mounted', () => { - expect(eventSpy).toHaveBeenCalledWith(undefined, TrackingActions.COMING_SOON_REQUESTED, {}); - }); - - it('tracks when an issue title link is clicked', () => { - eventSpy.mockClear(); - - findIssueTitleLink().vm.$emit('click'); - - expect(eventSpy).toHaveBeenCalledWith(undefined, TrackingActions.COMING_SOON_LIST, { - label: firstIssue.title, - value: firstIssue.iid, - }); - }); - - it('tracks when an issue id link is clicked', () => { - eventSpy.mockClear(); - - findIssueIdLink().vm.$emit('click'); - - expect(eventSpy).toHaveBeenCalledWith(undefined, TrackingActions.COMING_SOON_LIST, { - label: firstIssue.title, - value: firstIssue.iid, - }); - }); - }); -}); diff --git a/spec/frontend/packages/list/components/__snapshots__/packages_list_app_spec.js.snap b/spec/frontend/packages/list/components/__snapshots__/packages_list_app_spec.js.snap index 6ff9376565a..ce3a58c856d 100644 --- a/spec/frontend/packages/list/components/__snapshots__/packages_list_app_spec.js.snap +++ b/spec/frontend/packages/list/components/__snapshots__/packages_list_app_spec.js.snap @@ -1,457 +1,461 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`packages_list_app renders 1`] = ` -<b-tabs-stub - activenavitemclass="gl-tab-nav-item-active gl-tab-nav-item-active-indigo" - class="gl-tabs" - contentclass=",gl-tab-content" - navclass="gl-tabs-nav" - nofade="true" - nonavstyle="true" - tag="div" -> - <template> - - <b-tab-stub - tag="div" - title="All" - titlelinkclass="gl-tab-nav-item" - > - <template> - <div> - <section - class="row empty-state text-center" - > - <div - class="col-12" +<div> + <package-title-stub + packagehelpurl="foo" + /> + + <b-tabs-stub + activenavitemclass="gl-tab-nav-item-active gl-tab-nav-item-active-indigo" + class="gl-tabs" + contentclass=",gl-tab-content" + navclass="gl-tabs-nav" + nofade="true" + nonavstyle="true" + tag="div" + > + <template> + + <b-tab-stub + tag="div" + title="All" + titlelinkclass="gl-tab-nav-item" + > + <template> + <div> + <section + class="row empty-state text-center" > <div - class="svg-250 svg-content" + class="col-12" > - <img - alt="There are no packages yet" - class="gl-max-w-full" - src="helpSvg" - /> + <div + class="svg-250 svg-content" + > + <img + alt="There are no packages yet" + class="gl-max-w-full" + src="helpSvg" + /> + </div> </div> - </div> - - <div - class="col-12" - > + <div - class="text-content gl-mx-auto gl-my-0 gl-p-5" + class="col-12" > - <h1 - class="h4" + <div + class="text-content gl-mx-auto gl-my-0 gl-p-5" > - There are no packages yet - </h1> - - <p> - Learn how to - <b-link-stub - class="gl-link" - event="click" - href="helpUrl" - routertag="a" - target="_blank" + <h1 + class="h4" > - publish and share your packages - </b-link-stub> - with GitLab. - </p> - - <div> - <!----> + There are no packages yet + </h1> - <!----> + <p> + Learn how to + <b-link-stub + class="gl-link" + event="click" + href="helpUrl" + routertag="a" + target="_blank" + > + publish and share your packages + </b-link-stub> + with GitLab. + </p> + + <div> + <!----> + + <!----> + </div> </div> </div> - </div> - </section> - </div> - </template> - </b-tab-stub> - <b-tab-stub - tag="div" - title="Composer" - titlelinkclass="gl-tab-nav-item" - > - <template> - <div> - <section - class="row empty-state text-center" - > - <div - class="col-12" + </section> + </div> + </template> + </b-tab-stub> + <b-tab-stub + tag="div" + title="Composer" + titlelinkclass="gl-tab-nav-item" + > + <template> + <div> + <section + class="row empty-state text-center" > <div - class="svg-250 svg-content" + class="col-12" > - <img - alt="There are no Composer packages yet" - class="gl-max-w-full" - src="helpSvg" - /> + <div + class="svg-250 svg-content" + > + <img + alt="There are no Composer packages yet" + class="gl-max-w-full" + src="helpSvg" + /> + </div> </div> - </div> - - <div - class="col-12" - > + <div - class="text-content gl-mx-auto gl-my-0 gl-p-5" + class="col-12" > - <h1 - class="h4" + <div + class="text-content gl-mx-auto gl-my-0 gl-p-5" > - There are no Composer packages yet - </h1> - - <p> - Learn how to - <b-link-stub - class="gl-link" - event="click" - href="helpUrl" - routertag="a" - target="_blank" + <h1 + class="h4" > - publish and share your packages - </b-link-stub> - with GitLab. - </p> - - <div> - <!----> + There are no Composer packages yet + </h1> - <!----> + <p> + Learn how to + <b-link-stub + class="gl-link" + event="click" + href="helpUrl" + routertag="a" + target="_blank" + > + publish and share your packages + </b-link-stub> + with GitLab. + </p> + + <div> + <!----> + + <!----> + </div> </div> </div> - </div> - </section> - </div> - </template> - </b-tab-stub> - <b-tab-stub - tag="div" - title="Conan" - titlelinkclass="gl-tab-nav-item" - > - <template> - <div> - <section - class="row empty-state text-center" - > - <div - class="col-12" + </section> + </div> + </template> + </b-tab-stub> + <b-tab-stub + tag="div" + title="Conan" + titlelinkclass="gl-tab-nav-item" + > + <template> + <div> + <section + class="row empty-state text-center" > <div - class="svg-250 svg-content" + class="col-12" > - <img - alt="There are no Conan packages yet" - class="gl-max-w-full" - src="helpSvg" - /> + <div + class="svg-250 svg-content" + > + <img + alt="There are no Conan packages yet" + class="gl-max-w-full" + src="helpSvg" + /> + </div> </div> - </div> - - <div - class="col-12" - > + <div - class="text-content gl-mx-auto gl-my-0 gl-p-5" + class="col-12" > - <h1 - class="h4" + <div + class="text-content gl-mx-auto gl-my-0 gl-p-5" > - There are no Conan packages yet - </h1> - - <p> - Learn how to - <b-link-stub - class="gl-link" - event="click" - href="helpUrl" - routertag="a" - target="_blank" + <h1 + class="h4" > - publish and share your packages - </b-link-stub> - with GitLab. - </p> - - <div> - <!----> + There are no Conan packages yet + </h1> - <!----> + <p> + Learn how to + <b-link-stub + class="gl-link" + event="click" + href="helpUrl" + routertag="a" + target="_blank" + > + publish and share your packages + </b-link-stub> + with GitLab. + </p> + + <div> + <!----> + + <!----> + </div> </div> </div> - </div> - </section> - </div> - </template> - </b-tab-stub> - <b-tab-stub - tag="div" - title="Maven" - titlelinkclass="gl-tab-nav-item" - > - <template> - <div> - <section - class="row empty-state text-center" - > - <div - class="col-12" + </section> + </div> + </template> + </b-tab-stub> + <b-tab-stub + tag="div" + title="Maven" + titlelinkclass="gl-tab-nav-item" + > + <template> + <div> + <section + class="row empty-state text-center" > <div - class="svg-250 svg-content" + class="col-12" > - <img - alt="There are no Maven packages yet" - class="gl-max-w-full" - src="helpSvg" - /> + <div + class="svg-250 svg-content" + > + <img + alt="There are no Maven packages yet" + class="gl-max-w-full" + src="helpSvg" + /> + </div> </div> - </div> - - <div - class="col-12" - > + <div - class="text-content gl-mx-auto gl-my-0 gl-p-5" + class="col-12" > - <h1 - class="h4" + <div + class="text-content gl-mx-auto gl-my-0 gl-p-5" > - There are no Maven packages yet - </h1> - - <p> - Learn how to - <b-link-stub - class="gl-link" - event="click" - href="helpUrl" - routertag="a" - target="_blank" + <h1 + class="h4" > - publish and share your packages - </b-link-stub> - with GitLab. - </p> - - <div> - <!----> + There are no Maven packages yet + </h1> + + <p> + Learn how to + <b-link-stub + class="gl-link" + event="click" + href="helpUrl" + routertag="a" + target="_blank" + > + publish and share your packages + </b-link-stub> + with GitLab. + </p> - <!----> + <div> + <!----> + + <!----> + </div> </div> </div> - </div> - </section> - </div> - </template> - </b-tab-stub> - <b-tab-stub - tag="div" - title="NPM" - titlelinkclass="gl-tab-nav-item" - > - <template> - <div> - <section - class="row empty-state text-center" - > - <div - class="col-12" + </section> + </div> + </template> + </b-tab-stub> + <b-tab-stub + tag="div" + title="NPM" + titlelinkclass="gl-tab-nav-item" + > + <template> + <div> + <section + class="row empty-state text-center" > <div - class="svg-250 svg-content" + class="col-12" > - <img - alt="There are no NPM packages yet" - class="gl-max-w-full" - src="helpSvg" - /> + <div + class="svg-250 svg-content" + > + <img + alt="There are no NPM packages yet" + class="gl-max-w-full" + src="helpSvg" + /> + </div> </div> - </div> - - <div - class="col-12" - > + <div - class="text-content gl-mx-auto gl-my-0 gl-p-5" + class="col-12" > - <h1 - class="h4" + <div + class="text-content gl-mx-auto gl-my-0 gl-p-5" > - There are no NPM packages yet - </h1> - - <p> - Learn how to - <b-link-stub - class="gl-link" - event="click" - href="helpUrl" - routertag="a" - target="_blank" + <h1 + class="h4" > - publish and share your packages - </b-link-stub> - with GitLab. - </p> - - <div> - <!----> + There are no NPM packages yet + </h1> + + <p> + Learn how to + <b-link-stub + class="gl-link" + event="click" + href="helpUrl" + routertag="a" + target="_blank" + > + publish and share your packages + </b-link-stub> + with GitLab. + </p> - <!----> + <div> + <!----> + + <!----> + </div> </div> </div> - </div> - </section> - </div> - </template> - </b-tab-stub> - <b-tab-stub - tag="div" - title="NuGet" - titlelinkclass="gl-tab-nav-item" - > - <template> - <div> - <section - class="row empty-state text-center" - > - <div - class="col-12" + </section> + </div> + </template> + </b-tab-stub> + <b-tab-stub + tag="div" + title="NuGet" + titlelinkclass="gl-tab-nav-item" + > + <template> + <div> + <section + class="row empty-state text-center" > <div - class="svg-250 svg-content" + class="col-12" > - <img - alt="There are no NuGet packages yet" - class="gl-max-w-full" - src="helpSvg" - /> + <div + class="svg-250 svg-content" + > + <img + alt="There are no NuGet packages yet" + class="gl-max-w-full" + src="helpSvg" + /> + </div> </div> - </div> - - <div - class="col-12" - > + <div - class="text-content gl-mx-auto gl-my-0 gl-p-5" + class="col-12" > - <h1 - class="h4" + <div + class="text-content gl-mx-auto gl-my-0 gl-p-5" > - There are no NuGet packages yet - </h1> - - <p> - Learn how to - <b-link-stub - class="gl-link" - event="click" - href="helpUrl" - routertag="a" - target="_blank" + <h1 + class="h4" > - publish and share your packages - </b-link-stub> - with GitLab. - </p> - - <div> - <!----> + There are no NuGet packages yet + </h1> + + <p> + Learn how to + <b-link-stub + class="gl-link" + event="click" + href="helpUrl" + routertag="a" + target="_blank" + > + publish and share your packages + </b-link-stub> + with GitLab. + </p> - <!----> + <div> + <!----> + + <!----> + </div> </div> </div> - </div> - </section> - </div> - </template> - </b-tab-stub> - <b-tab-stub - tag="div" - title="PyPi" - titlelinkclass="gl-tab-nav-item" - > - <template> - <div> - <section - class="row empty-state text-center" - > - <div - class="col-12" + </section> + </div> + </template> + </b-tab-stub> + <b-tab-stub + tag="div" + title="PyPI" + titlelinkclass="gl-tab-nav-item" + > + <template> + <div> + <section + class="row empty-state text-center" > <div - class="svg-250 svg-content" + class="col-12" > - <img - alt="There are no PyPi packages yet" - class="gl-max-w-full" - src="helpSvg" - /> + <div + class="svg-250 svg-content" + > + <img + alt="There are no PyPI packages yet" + class="gl-max-w-full" + src="helpSvg" + /> + </div> </div> - </div> - - <div - class="col-12" - > + <div - class="text-content gl-mx-auto gl-my-0 gl-p-5" + class="col-12" > - <h1 - class="h4" + <div + class="text-content gl-mx-auto gl-my-0 gl-p-5" > - There are no PyPi packages yet - </h1> - - <p> - Learn how to - <b-link-stub - class="gl-link" - event="click" - href="helpUrl" - routertag="a" - target="_blank" + <h1 + class="h4" > - publish and share your packages - </b-link-stub> - with GitLab. - </p> - - <div> - <!----> + There are no PyPI packages yet + </h1> + + <p> + Learn how to + <b-link-stub + class="gl-link" + event="click" + href="helpUrl" + routertag="a" + target="_blank" + > + publish and share your packages + </b-link-stub> + with GitLab. + </p> - <!----> + <div> + <!----> + + <!----> + </div> </div> </div> - </div> - </section> - </div> - </template> - </b-tab-stub> - - <!----> - </template> - <template> - <div - class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end" - > - <package-filter-stub - class="mr-1" - /> - - <package-sort-stub /> - </div> - </template> -</b-tabs-stub> + </section> + </div> + </template> + </b-tab-stub> + </template> + <template> + <div + class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end" + > + <package-filter-stub + class="gl-mr-2" + /> + + <package-sort-stub /> + </div> + </template> + </b-tabs-stub> +</div> `; diff --git a/spec/frontend/packages/list/components/packages_list_app_spec.js b/spec/frontend/packages/list/components/packages_list_app_spec.js index 19ff4290f50..217096f822a 100644 --- a/spec/frontend/packages/list/components/packages_list_app_spec.js +++ b/spec/frontend/packages/list/components/packages_list_app_spec.js @@ -36,6 +36,7 @@ describe('packages_list_app', () => { resourceId: 'project_id', emptyListIllustration: 'helpSvg', emptyListHelpUrl, + packageHelpUrl: 'foo', }, filterQuery, }, diff --git a/spec/frontend/packages/list/components/packages_title_spec.js b/spec/frontend/packages/list/components/packages_title_spec.js new file mode 100644 index 00000000000..5e9ebd8ecb0 --- /dev/null +++ b/spec/frontend/packages/list/components/packages_title_spec.js @@ -0,0 +1,71 @@ +import { shallowMount } from '@vue/test-utils'; +import PackageTitle from '~/packages/list/components/package_title.vue'; +import TitleArea from '~/vue_shared/components/registry/title_area.vue'; +import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue'; +import { LIST_INTRO_TEXT, LIST_TITLE_TEXT } from '~/packages/list//constants'; + +describe('PackageTitle', () => { + let wrapper; + let store; + + const findTitleArea = () => wrapper.find(TitleArea); + const findMetadataItem = () => wrapper.find(MetadataItem); + + const mountComponent = (propsData = { packageHelpUrl: 'foo' }) => { + wrapper = shallowMount(PackageTitle, { + 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: LIST_TITLE_TEXT, + infoMessages: [{ text: LIST_INTRO_TEXT, link: 'foo' }], + }); + }); + }); + + 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 }) => { + beforeEach(() => { + mountComponent({ packagesCount, packageHelpUrl: 'foo' }); + }); + + it(`is ${exist} that it exists`, () => { + expect(findMetadataItem().exists()).toBe(exist); + }); + + if (exist) { + it('has the correct props', () => { + expect(findMetadataItem().props()).toMatchObject({ + icon: 'package', + text, + }); + }); + } + }); +}); diff --git a/spec/frontend/packages/list/stores/mutations_spec.js b/spec/frontend/packages/list/stores/mutations_spec.js index 563a3dabbb3..0d424a0c011 100644 --- a/spec/frontend/packages/list/stores/mutations_spec.js +++ b/spec/frontend/packages/list/stores/mutations_spec.js @@ -18,7 +18,6 @@ describe('Mutations Registry Store', () => { userCanDelete: '', emptyListIllustration: 'foo', emptyListHelpUrl: 'baz', - comingSoonJson: '{ "project_path": "gitlab-org/gitlab-test" }', }; const expectedState = { diff --git a/spec/frontend/packages/mock_data.js b/spec/frontend/packages/mock_data.js index b95d06428ff..d7494bf85d0 100644 --- a/spec/frontend/packages/mock_data.js +++ b/spec/frontend/packages/mock_data.js @@ -84,15 +84,15 @@ export const conanPackage = { package_channel: 'stable', package_username: 'conan+conan-package', }, + conan_package_name: 'conan-package', created_at: '2015-12-10', id: 3, - name: 'conan-package', + name: 'conan-package/1.0.0@conan+conan-package/stable', project_path: 'foo/bar/baz', projectPathName: 'foo/bar/baz', package_files: [], package_type: 'conan', project_id: 1, - recipe: 'conan-package/1.0.0@conan+conan-package/stable', updated_at: '2015-12-10', version: '1.0.0', _links, 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 index 6aaefed92d0..5faae5690db 100644 --- 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 @@ -52,27 +52,6 @@ exports[`packages_list_row renders 1`] = ` <!----> <div - class="gl-display-flex gl-align-items-center" - > - <gl-icon-stub - class="gl-ml-3 gl-mr-2 gl-min-w-0" - name="review-list" - size="16" - /> - - <gl-link-stub - class="gl-text-body gl-min-w-0" - data-testid="packages-row-project" - href="/foo/bar/baz" - > - <gl-truncate-stub - position="end" - text="foo/bar/baz" - /> - </gl-link-stub> - </div> - - <div class="d-flex align-items-center" data-testid="package-type" > @@ -86,6 +65,10 @@ exports[`packages_list_row renders 1`] = ` Maven </span> </div> + + <package-path-stub + path="foo/bar/baz" + /> </div> </div> </div> @@ -118,6 +101,7 @@ exports[`packages_list_row renders 1`] = ` > <gl-button-stub aria-label="Remove package" + buttontextclasses="" category="primary" data-testid="action-delete" icon="remove" 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 index 9a0c52cee47..acdf7c49ebd 100644 --- a/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap +++ b/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap @@ -32,7 +32,8 @@ exports[`publish_method renders 1`] = ` </gl-link-stub> <clipboard-button-stub - cssclass="gl-border-0 gl-py-0 gl-px-2" + category="tertiary" + size="small" text="sha-baz" title="Copy commit SHA" tooltipplacement="top" diff --git a/spec/frontend/packages/shared/components/package_list_row_spec.js b/spec/frontend/packages/shared/components/package_list_row_spec.js index f4eabf7bb67..0d0ea4e2122 100644 --- a/spec/frontend/packages/shared/components/package_list_row_spec.js +++ b/spec/frontend/packages/shared/components/package_list_row_spec.js @@ -1,6 +1,7 @@ import { 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 PackagePath from '~/packages/shared/components/package_path.vue'; import ListItem from '~/vue_shared/components/registry/list_item.vue'; import { packageList } from '../../mock_data'; @@ -11,7 +12,7 @@ describe('packages_list_row', () => { const [packageWithoutTags, packageWithTags] = packageList; const findPackageTags = () => wrapper.find(PackageTags); - const findProjectLink = () => wrapper.find('[data-testid="packages-row-project"]'); + const findPackagePath = () => wrapper.find(PackagePath); const findDeleteButton = () => wrapper.find('[data-testid="action-delete"]'); const findPackageType = () => wrapper.find('[data-testid="package-type"]'); @@ -63,8 +64,9 @@ describe('packages_list_row', () => { mountComponent({ isGroup: true }); }); - it('has project field', () => { - expect(findProjectLink().exists()).toBe(true); + it('has a package path component', () => { + expect(findPackagePath().exists()).toBe(true); + expect(findPackagePath().props()).toMatchObject({ path: 'foo/bar/baz' }); }); }); diff --git a/spec/frontend/packages/shared/components/package_path_spec.js b/spec/frontend/packages/shared/components/package_path_spec.js new file mode 100644 index 00000000000..40d455ac77c --- /dev/null +++ b/spec/frontend/packages/shared/components/package_path_spec.js @@ -0,0 +1,86 @@ +import { shallowMount } from '@vue/test-utils'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import PackagePath from '~/packages/shared/components/package_path.vue'; + +describe('PackagePath', () => { + let wrapper; + + const mountComponent = (propsData = { path: 'foo' }) => { + wrapper = shallowMount(PackagePath, { + propsData, + directives: { + GlTooltip: createMockDirective(), + }, + }); + }; + + const BASE_ICON = 'base-icon'; + const ROOT_LINK = 'root-link'; + const ROOT_CHEVRON = 'root-chevron'; + const ELLIPSIS_ICON = 'ellipsis-icon'; + const ELLIPSIS_CHEVRON = 'ellipsis-chevron'; + const LEAF_LINK = 'leaf-link'; + + const findItem = name => wrapper.find(`[data-testid="${name}"]`); + const findTooltip = w => getBinding(w.element, 'gl-tooltip'); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe.each` + path | rootUrl | shouldExist | shouldNotExist + ${'foo/bar'} | ${'/foo/bar'} | ${[]} | ${[ROOT_CHEVRON, ELLIPSIS_ICON, ELLIPSIS_CHEVRON, LEAF_LINK]} + ${'foo/bar/baz'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK]} | ${[ELLIPSIS_ICON, ELLIPSIS_CHEVRON]} + ${'foo/bar/baz/baz2'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK, ELLIPSIS_ICON, ELLIPSIS_CHEVRON]} | ${[]} + ${'foo/bar/baz/baz2/bar2'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK, ELLIPSIS_ICON, ELLIPSIS_CHEVRON]} | ${[]} + `('given path $path', ({ path, shouldExist, shouldNotExist, rootUrl }) => { + const pathPieces = path.split('/').slice(1); + const hasTooltip = shouldExist.includes(ELLIPSIS_ICON); + + beforeEach(() => { + mountComponent({ path }); + }); + + it('should have a base icon', () => { + expect(findItem(BASE_ICON).exists()).toBe(true); + }); + + it('should have a root link', () => { + const root = findItem(ROOT_LINK); + expect(root.exists()).toBe(true); + expect(root.attributes('href')).toBe(rootUrl); + }); + + if (hasTooltip) { + it('should have a tooltip', () => { + const tooltip = findTooltip(findItem(ELLIPSIS_ICON)); + expect(tooltip).toBeDefined(); + expect(tooltip.value).toMatchObject({ + title: path, + }); + }); + } + + if (shouldExist.length) { + it.each(shouldExist)(`should have %s`, element => { + expect(findItem(element).exists()).toBe(true); + }); + } + + if (shouldNotExist.length) { + it.each(shouldNotExist)(`should not have %s`, element => { + expect(findItem(element).exists()).toBe(false); + }); + } + + if (shouldExist.includes(LEAF_LINK)) { + it('the last link should be the last piece of the path', () => { + const leaf = findItem(LEAF_LINK); + expect(leaf.attributes('href')).toBe(`/${path}`); + expect(leaf.text()).toBe(pathPieces[pathPieces.length - 1]); + }); + } + }); +}); diff --git a/spec/frontend/packages/shared/utils_spec.js b/spec/frontend/packages/shared/utils_spec.js index 1fe90a4827f..3e4ce8eb323 100644 --- a/spec/frontend/packages/shared/utils_spec.js +++ b/spec/frontend/packages/shared/utils_spec.js @@ -37,7 +37,7 @@ describe('Packages shared utils', () => { ${'maven'} | ${'Maven'} ${'npm'} | ${'NPM'} ${'nuget'} | ${'NuGet'} - ${'pypi'} | ${'PyPi'} + ${'pypi'} | ${'PyPI'} ${'composer'} | ${'Composer'} ${'foo'} | ${null} `(`package type`, ({ packageType, expectedResult }) => { |