Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/packages/details/components/app_spec.js')
-rw-r--r--spec/frontend/packages/details/components/app_spec.js281
1 files changed, 281 insertions, 0 deletions
diff --git a/spec/frontend/packages/details/components/app_spec.js b/spec/frontend/packages/details/components/app_spec.js
new file mode 100644
index 00000000000..f535f3f5744
--- /dev/null
+++ b/spec/frontend/packages/details/components/app_spec.js
@@ -0,0 +1,281 @@
+import Vuex from 'vuex';
+import { mount, createLocalVue } from '@vue/test-utils';
+import { GlEmptyState, GlModal } from '@gitlab/ui';
+import stubChildren from 'helpers/stub_children';
+import Tracking from '~/tracking';
+import * as getters from '~/packages/details/store/getters';
+import PackagesApp from '~/packages/details/components/app.vue';
+import PackageTitle from '~/packages/details/components/package_title.vue';
+
+import * as SharedUtils from '~/packages/shared/utils';
+import { TrackingActions } from '~/packages/shared/constants';
+import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue';
+import PackageListRow from '~/packages/shared/components/package_list_row.vue';
+
+import DependencyRow from '~/packages/details/components/dependency_row.vue';
+import PackageHistory from '~/packages/details/components/package_history.vue';
+import AdditionalMetadata from '~/packages/details/components/additional_metadata.vue';
+import InstallationCommands from '~/packages/details/components/installation_commands.vue';
+
+import {
+ composerPackage,
+ conanPackage,
+ mavenPackage,
+ mavenFiles,
+ npmPackage,
+ npmFiles,
+ nugetPackage,
+} from '../../mock_data';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('PackagesApp', () => {
+ let wrapper;
+ let store;
+ const fetchPackageVersions = jest.fn();
+
+ function createComponent({
+ packageEntity = mavenPackage,
+ packageFiles = mavenFiles,
+ isLoading = false,
+ oneColumnView = false,
+ } = {}) {
+ store = new Vuex.Store({
+ state: {
+ isLoading,
+ packageEntity,
+ packageFiles,
+ canDelete: true,
+ destroyPath: 'destroy-package-path',
+ emptySvgPath: 'empty-illustration',
+ npmPath: 'foo',
+ npmHelpPath: 'foo',
+ projectName: 'bar',
+ oneColumnView,
+ },
+ actions: {
+ fetchPackageVersions,
+ },
+ getters,
+ });
+
+ wrapper = mount(PackagesApp, {
+ localVue,
+ store,
+ stubs: {
+ ...stubChildren(PackagesApp),
+ GlButton: false,
+ GlModal: false,
+ GlTab: false,
+ GlTabs: false,
+ GlTable: false,
+ },
+ });
+ }
+
+ const packageTitle = () => wrapper.find(PackageTitle);
+ const emptyState = () => wrapper.find(GlEmptyState);
+ const allFileRows = () => wrapper.findAll('.js-file-row');
+ const firstFileDownloadLink = () => wrapper.find('.js-file-download');
+ const deleteButton = () => wrapper.find('.js-delete-button');
+ const deleteModal = () => wrapper.find(GlModal);
+ const modalDeleteButton = () => wrapper.find({ ref: 'modal-delete-button' });
+ const versionsTab = () => wrapper.find('.js-versions-tab > a');
+ const packagesLoader = () => wrapper.find(PackagesListLoader);
+ const packagesVersionRows = () => wrapper.findAll(PackageListRow);
+ const noVersionsMessage = () => wrapper.find('[data-testid="no-versions-message"]');
+ const dependenciesTab = () => wrapper.find('.js-dependencies-tab > a');
+ const dependenciesCountBadge = () => wrapper.find('[data-testid="dependencies-badge"]');
+ const noDependenciesMessage = () => wrapper.find('[data-testid="no-dependencies-message"]');
+ const dependencyRows = () => wrapper.findAll(DependencyRow);
+ const findPackageHistory = () => wrapper.find(PackageHistory);
+ const findAdditionalMetadata = () => wrapper.find(AdditionalMetadata);
+ const findInstallationCommands = () => wrapper.find(InstallationCommands);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders the app and displays the package title', () => {
+ createComponent();
+
+ expect(packageTitle()).toExist();
+ });
+
+ it('renders an empty state component when no an invalid package is passed as a prop', () => {
+ createComponent({
+ packageEntity: {},
+ });
+
+ expect(emptyState()).toExist();
+ });
+
+ it('package history has the right props', () => {
+ createComponent();
+ expect(findPackageHistory().exists()).toBe(true);
+ expect(findPackageHistory().props('packageEntity')).toEqual(wrapper.vm.packageEntity);
+ expect(findPackageHistory().props('projectName')).toEqual(wrapper.vm.projectName);
+ });
+
+ it('additional metadata has the right props', () => {
+ createComponent();
+ expect(findAdditionalMetadata().exists()).toBe(true);
+ expect(findAdditionalMetadata().props('packageEntity')).toEqual(wrapper.vm.packageEntity);
+ });
+
+ it('installation commands has the right props', () => {
+ createComponent();
+ expect(findInstallationCommands().exists()).toBe(true);
+ expect(findInstallationCommands().props('packageEntity')).toEqual(wrapper.vm.packageEntity);
+ });
+
+ it('hides the files table if package type is COMPOSER', () => {
+ createComponent({ packageEntity: composerPackage });
+ expect(allFileRows().exists()).toBe(false);
+ });
+
+ it('renders a single file for an npm package as they only contain one file', () => {
+ createComponent({ packageEntity: npmPackage, packageFiles: npmFiles });
+
+ expect(allFileRows()).toExist();
+ expect(allFileRows()).toHaveLength(1);
+ });
+
+ it('renders multiple files for a package that contains more than one file', () => {
+ createComponent();
+
+ expect(allFileRows()).toExist();
+ expect(allFileRows()).toHaveLength(2);
+ });
+
+ it('allows the user to download a package file by rendering a download link', () => {
+ createComponent();
+
+ expect(allFileRows()).toExist();
+ expect(firstFileDownloadLink().vm.$attrs.href).toContain('download');
+ });
+
+ describe('deleting packages', () => {
+ beforeEach(() => {
+ createComponent();
+ deleteButton().trigger('click');
+ });
+
+ it('shows the delete confirmation modal when delete is clicked', () => {
+ expect(deleteModal()).toExist();
+ });
+ });
+
+ describe('versions', () => {
+ describe('api call', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('makes api request on first click of tab', () => {
+ versionsTab().trigger('click');
+
+ expect(fetchPackageVersions).toHaveBeenCalled();
+ });
+ });
+
+ it('displays the loader when state is loading', () => {
+ createComponent({ isLoading: true });
+
+ expect(packagesLoader().exists()).toBe(true);
+ });
+
+ it('displays the correct version count when the package has versions', () => {
+ createComponent({ packageEntity: npmPackage });
+
+ expect(packagesVersionRows()).toHaveLength(npmPackage.versions.length);
+ });
+
+ it('displays the no versions message when there are none', () => {
+ createComponent();
+
+ expect(noVersionsMessage().exists()).toBe(true);
+ });
+ });
+
+ describe('dependency links', () => {
+ it('does not show the dependency links for a non nuget package', () => {
+ createComponent();
+
+ expect(dependenciesTab().exists()).toBe(false);
+ });
+
+ it('shows the dependencies tab with 0 count when a nuget package with no dependencies', () => {
+ createComponent({
+ packageEntity: {
+ ...nugetPackage,
+ dependency_links: [],
+ },
+ });
+
+ return wrapper.vm.$nextTick(() => {
+ const dependenciesBadge = dependenciesCountBadge();
+
+ expect(dependenciesTab().exists()).toBe(true);
+ expect(dependenciesBadge.exists()).toBe(true);
+ expect(dependenciesBadge.text()).toBe('0');
+ expect(noDependenciesMessage().exists()).toBe(true);
+ });
+ });
+
+ it('renders the correct number of dependency rows for a nuget package', () => {
+ createComponent({ packageEntity: nugetPackage });
+
+ return wrapper.vm.$nextTick(() => {
+ const dependenciesBadge = dependenciesCountBadge();
+
+ expect(dependenciesTab().exists()).toBe(true);
+ expect(dependenciesBadge.exists()).toBe(true);
+ expect(dependenciesBadge.text()).toBe(nugetPackage.dependency_links.length.toString());
+ expect(dependencyRows()).toHaveLength(nugetPackage.dependency_links.length);
+ });
+ });
+ });
+
+ describe('tracking', () => {
+ let eventSpy;
+ let utilSpy;
+ const category = 'foo';
+
+ beforeEach(() => {
+ eventSpy = jest.spyOn(Tracking, 'event');
+ utilSpy = jest.spyOn(SharedUtils, 'packageTypeToTrackCategory').mockReturnValue(category);
+ });
+
+ it('tracking category calls packageTypeToTrackCategory', () => {
+ createComponent({ packageEntity: conanPackage });
+ expect(wrapper.vm.tracking.category).toBe(category);
+ expect(utilSpy).toHaveBeenCalledWith('conan');
+ });
+
+ it(`delete button on delete modal call event with ${TrackingActions.DELETE_PACKAGE}`, () => {
+ createComponent({ packageEntity: conanPackage });
+ deleteButton().trigger('click');
+ return wrapper.vm.$nextTick().then(() => {
+ modalDeleteButton().trigger('click');
+ expect(eventSpy).toHaveBeenCalledWith(
+ category,
+ TrackingActions.DELETE_PACKAGE,
+ expect.any(Object),
+ );
+ });
+ });
+
+ it(`file download link call event with ${TrackingActions.PULL_PACKAGE}`, () => {
+ createComponent({ packageEntity: conanPackage });
+
+ firstFileDownloadLink().vm.$emit('click');
+ expect(eventSpy).toHaveBeenCalledWith(
+ category,
+ TrackingActions.PULL_PACKAGE,
+ expect.any(Object),
+ );
+ });
+ });
+});