Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
7df4f855
Commit
7df4f855
authored
Aug 09, 2021
by
Nicolò Maria Mezzopera
Committed by
Natalia Tepluhina
Aug 09, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor and enable package files in package details
parent
9a8c2097
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
301 additions
and
98 deletions
+301
-98
app/assets/javascripts/packages_and_registries/package_registry/components/details/app.vue
...nd_registries/package_registry/components/details/app.vue
+63
-32
app/assets/javascripts/packages_and_registries/package_registry/components/details/package_files.vue
...ies/package_registry/components/details/package_files.vue
+15
-17
app/assets/javascripts/packages_and_registries/package_registry/graphql/mutations/destroy_package_file.mutation.graphql
...y/graphql/mutations/destroy_package_file.mutation.graphql
+5
-0
app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql
...egistry/graphql/queries/get_package_details.query.graphql
+2
-0
app/assets/javascripts/packages_and_registries/package_registry/pages/details.js
...packages_and_registries/package_registry/pages/details.js
+0
-1
spec/frontend/packages_and_registries/package_registry/components/details/app_spec.js
...egistries/package_registry/components/details/app_spec.js
+125
-3
spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js
...package_registry/components/details/package_files_spec.js
+56
-42
spec/frontend/packages_and_registries/package_registry/mock_data.js
...end/packages_and_registries/package_registry/mock_data.js
+35
-3
No files found.
app/assets/javascripts/packages_and_registries/package_registry/components/details/app.vue
View file @
7df4f855
...
...
@@ -20,13 +20,14 @@ import { numberToHumanSize } from '~/lib/utils/number_utils';
import
{
objectToQuery
}
from
'
~/lib/utils/url_utility
'
;
import
{
s__
,
__
}
from
'
~/locale
'
;
// import DependencyRow from '~/packages/details/components/dependency_row.vue';
// import PackageFiles from '~/packages/details/components/package_files.vue';
// import PackageListRow from '~/packages/shared/components/package_list_row.vue';
import
PackagesListLoader
from
'
~/packages/shared/components/packages_list_loader.vue
'
;
import
{
packageTypeToTrackCategory
}
from
'
~/packages/shared/utils
'
;
import
AdditionalMetadata
from
'
~/packages_and_registries/package_registry/components/details/additional_metadata.vue
'
;
import
InstallationCommands
from
'
~/packages_and_registries/package_registry/components/details/installation_commands.vue
'
;
import
PackageFiles
from
'
~/packages_and_registries/package_registry/components/details/package_files.vue
'
;
import
PackageHistory
from
'
~/packages_and_registries/package_registry/components/details/package_history.vue
'
;
import
PackageTitle
from
'
~/packages_and_registries/package_registry/components/details/package_title.vue
'
;
import
{
PACKAGE_TYPE_NUGET
,
PACKAGE_TYPE_COMPOSER
,
...
...
@@ -40,8 +41,12 @@ import {
SHOW_DELETE_SUCCESS_ALERT
,
FETCH_PACKAGE_DETAILS_ERROR_MESSAGE
,
DELETE_PACKAGE_ERROR_MESSAGE
,
DELETE_PACKAGE_FILE_ERROR_MESSAGE
,
DELETE_PACKAGE_FILE_SUCCESS_MESSAGE
,
}
from
'
~/packages_and_registries/package_registry/constants
'
;
import
destroyPackageMutation
from
'
~/packages_and_registries/package_registry/graphql/mutations/destroy_package.mutation.graphql
'
;
import
destroyPackageFileMutation
from
'
~/packages_and_registries/package_registry/graphql/mutations/destroy_package_file.mutation.graphql
'
;
import
getPackageDetails
from
'
~/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql
'
;
import
Tracking
from
'
~/tracking
'
;
...
...
@@ -55,17 +60,14 @@ export default {
GlTab
,
GlTabs
,
GlSprintf
,
PackageTitle
:
()
=>
import
(
'
~/packages_and_registries/package_registry/components/details/package_title.vue
'
),
TerraformTitle
:
()
=>
import
(
'
~/packages_and_registries/infrastructure_registry/components/details_title.vue
'
),
PackageTitle
,
PackagesListLoader
,
// PackageListRow,
// DependencyRow,
PackageHistory
,
AdditionalMetadata
,
InstallationCommands
,
//
PackageFiles,
PackageFiles
,
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
...
...
@@ -74,7 +76,6 @@ export default {
mixins
:
[
Tracking
.
mixin
()],
inject
:
[
'
packageId
'
,
'
titleComponent
'
,
'
projectName
'
,
'
canDelete
'
,
'
svgPath
'
,
...
...
@@ -123,7 +124,7 @@ export default {
};
},
packageFiles
()
{
return
this
.
packageEntity
.
packageFil
es
;
return
this
.
packageEntity
?.
packageFiles
?.
nod
es
;
},
isLoading
()
{
return
this
.
$apollo
.
queries
.
packageEntity
.
loading
;
...
...
@@ -133,7 +134,7 @@ export default {
},
tracking
()
{
return
{
category
:
packageTypeToTrackCategory
(
this
.
packageEntity
.
package
_t
ype
),
category
:
packageTypeToTrackCategory
(
this
.
packageEntity
.
package
T
ype
),
};
},
hasVersions
()
{
...
...
@@ -143,10 +144,10 @@ export default {
return
this
.
packageEntity
.
dependency_links
||
[];
},
showDependencies
()
{
return
this
.
packageEntity
.
package
_t
ype
===
PACKAGE_TYPE_NUGET
;
return
this
.
packageEntity
.
package
T
ype
===
PACKAGE_TYPE_NUGET
;
},
showFiles
()
{
return
this
.
packageEntity
?.
package
_t
ype
!==
PACKAGE_TYPE_COMPOSER
;
return
this
.
packageEntity
?.
package
T
ype
!==
PACKAGE_TYPE_COMPOSER
;
},
},
methods
:
{
...
...
@@ -158,19 +159,17 @@ export default {
// this.fetchPackageVersions();
}
},
deletePackage
()
{
return
this
.
$apollo
.
mutate
({
async
deletePackage
()
{
const
{
data
}
=
await
this
.
$apollo
.
mutate
({
mutation
:
destroyPackageMutation
,
variables
:
{
id
:
this
.
packageEntity
.
id
,
},
})
.
then
(({
data
})
=>
{
});
if
(
data
?.
destroyPackage
?.
errors
[
0
])
{
throw
data
.
destroyPackage
.
errors
[
0
];
}
});
},
async
confirmPackageDeletion
()
{
this
.
track
(
DELETE_PACKAGE_TRACKING_ACTION
);
...
...
@@ -195,6 +194,37 @@ export default {
});
}
},
async
deletePackageFile
(
id
)
{
try
{
const
{
data
}
=
await
this
.
$apollo
.
mutate
({
mutation
:
destroyPackageFileMutation
,
variables
:
{
id
,
},
awaitRefetchQueries
:
true
,
refetchQueries
:
[
{
query
:
getPackageDetails
,
variables
:
this
.
queryVariables
,
},
],
});
if
(
data
?.
destroyPackageFile
?.
errors
[
0
])
{
throw
data
.
destroyPackageFile
.
errors
[
0
];
}
createFlash
({
message
:
DELETE_PACKAGE_FILE_SUCCESS_MESSAGE
,
type
:
'
success
'
,
});
}
catch
(
error
)
{
createFlash
({
message
:
DELETE_PACKAGE_FILE_ERROR_MESSAGE
,
type
:
'
warning
'
,
captureError
:
true
,
error
,
});
}
},
handleFileDelete
(
file
)
{
this
.
track
(
REQUEST_DELETE_PACKAGE_FILE_TRACKING_ACTION
);
this
.
fileToDelete
=
{
...
file
};
...
...
@@ -202,7 +232,7 @@ export default {
},
confirmFileDelete
()
{
this
.
track
(
DELETE_PACKAGE_FILE_TRACKING_ACTION
);
//
this.deletePackageFile(this.fileToDelete.id);
this
.
deletePackageFile
(
this
.
fileToDelete
.
id
);
this
.
fileToDelete
=
null
;
},
},
...
...
@@ -245,7 +275,7 @@ export default {
/>
<div
v-else
class=
"packages-app"
>
<
component
:is=
"titleComponent"
:package-entity=
"packageEntity"
>
<
package-title
:package-entity=
"packageEntity"
>
<template
#delete-button
>
<gl-button
v-if=
"canDelete"
...
...
@@ -258,7 +288,7 @@ export default {
{{
__
(
'
Delete
'
)
}}
</gl-button>
</
template
>
</
component
>
</
package-title
>
<gl-tabs>
<gl-tab
:title=
"__('Detail')"
>
...
...
@@ -270,13 +300,12 @@ export default {
<additional-metadata
:package-entity=
"packageEntity"
/>
</div>
<
!-- <
package-files
<package-files
v-if=
"showFiles"
:package-files=
"packageFiles"
:can-delete="canDelete"
@
download-file=
"track($options.trackingActions.PULL_PACKAGE)"
@
delete-file=
"handleFileDelete"
/>
-->
/>
</gl-tab>
<gl-tab
v-if=
"showDependencies"
title-item-class=
"js-dependencies-tab"
>
...
...
@@ -288,11 +317,11 @@ export default {
</
template
>
<
template
v-if=
"packageDependencies.length > 0"
>
<dependency-row
<
!--
<
dependency-row
v-for=
"(dep, index) in packageDependencies"
:key=
"index"
:dependency=
"dep"
/>
/>
-->
</
template
>
<p
v-else
class=
"gl-mt-3"
data-testid=
"no-dependencies-message"
>
...
...
@@ -329,6 +358,7 @@ export default {
<gl-modal
ref=
"deleteModal"
modal-id=
"delete-modal"
data-testid=
"delete-modal"
:action-primary=
"$options.modal.packageDeletePrimaryAction"
:action-cancel=
"$options.modal.cancelAction"
@
primary=
"confirmPackageDeletion"
...
...
@@ -351,6 +381,7 @@ export default {
modal-id=
"delete-file-modal"
:action-primary=
"$options.modal.fileDeletePrimaryAction"
:action-cancel=
"$options.modal.cancelAction"
data-testid=
"delete-file-modal"
@
primary=
"confirmFileDelete"
@
canceled=
"track($options.trackingActions.CANCEL_DELETE_PACKAGE_FILE)"
>
...
...
app/assets/javascripts/packages_and_registries/package_registry/components/details/package_files.vue
View file @
7df4f855
...
...
@@ -22,17 +22,13 @@ export default {
FileSha
,
},
mixins
:
[
Tracking
.
mixin
()],
inject
:
[
'
canDelete
'
],
props
:
{
packageFiles
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
[],
},
canDelete
:
{
type
:
Boolean
,
default
:
false
,
required
:
false
,
},
},
computed
:
{
filesTableRows
()
{
...
...
@@ -43,6 +39,8 @@ export default {
}));
},
showCommitColumn
()
{
// note that this is always false for now since we do not return
// pipelines associated to files for performance concerns
return
this
.
filesTableRows
.
some
((
row
)
=>
Boolean
(
row
.
pipeline
?.
id
));
},
filesTableHeaderFields
()
{
...
...
@@ -80,7 +78,7 @@ export default {
return
numberToHumanSize
(
size
);
},
hasDetails
(
item
)
{
return
item
.
file
_sha256
||
item
.
file_md5
||
item
.
file_s
ha1
;
return
item
.
file
Sha256
||
item
.
fileMd5
||
item
.
fileS
ha1
;
},
},
i18n
:
{
...
...
@@ -107,32 +105,32 @@ export default {
@
click=
"toggleDetails"
/>
<gl-link
:href=
"item.download
_p
ath"
:href=
"item.download
P
ath"
class=
"gl-text-gray-500"
data-testid=
"download-link"
@
click=
"$emit('download-file')"
>
<file-icon
:file-name=
"item.file
_n
ame"
:file-name=
"item.file
N
ame"
css-classes=
"gl-relative file-icon"
class=
"gl-mr-1 gl-relative"
/>
<span>
{{
item
.
file
_n
ame
}}
</span>
<span>
{{
item
.
file
N
ame
}}
</span>
</gl-link>
</
template
>
<
template
#cell(commit)=
"{ item }"
>
<gl-link
v-if=
"item.pipeline && item.pipeline
.project
"
:href=
"item.pipeline.
project.commit_url
"
v-if=
"item.pipeline && item.pipeline"
:href=
"item.pipeline.
commitPath
"
class=
"gl-text-gray-500"
data-testid=
"commit-link"
>
{{
item
.
pipeline
.
git_commit_message
}}
</gl-link
>
{{
item
.
pipeline
.
sha
}}
</gl-link
>
</
template
>
<
template
#cell(created)=
"{ item }"
>
<time-ago-tooltip
:time=
"item.created
_a
t"
/>
<time-ago-tooltip
:time=
"item.created
A
t"
/>
</
template
>
<
template
#cell(actions)=
"{ item }"
>
...
...
@@ -151,13 +149,13 @@ export default {
class=
"gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-bg-gray-10 gl-rounded-base gl-inset-border-1-gray-100"
>
<file-sha
v-if=
"item.file
_s
ha256"
v-if=
"item.file
S
ha256"
data-testid=
"sha-256"
title=
"SHA-256"
:sha=
"item.file
_s
ha256"
:sha=
"item.file
S
ha256"
/>
<file-sha
v-if=
"item.file
_md5"
data-testid=
"md5"
title=
"MD5"
:sha=
"item.file_m
d5"
/>
<file-sha
v-if=
"item.file
_sha1"
data-testid=
"sha-1"
title=
"SHA-1"
:sha=
"item.file_s
ha1"
/>
<file-sha
v-if=
"item.file
Md5"
data-testid=
"md5"
title=
"MD5"
:sha=
"item.fileM
d5"
/>
<file-sha
v-if=
"item.file
Sha1"
data-testid=
"sha-1"
title=
"SHA-1"
:sha=
"item.fileS
ha1"
/>
</div>
</
template
>
</gl-table>
...
...
app/assets/javascripts/packages_and_registries/package_registry/graphql/mutations/destroy_package_file.mutation.graphql
0 → 100644
View file @
7df4f855
mutation
destroyPackageFile
(
$id
:
PackagesPackageFileID
!)
{
destroyPackageFile
(
input
:
{
id
:
$id
})
{
errors
}
}
app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql
View file @
7df4f855
...
...
@@ -38,6 +38,8 @@ query getPackageDetails($id: ID!) {
fileSha1
fileSha256
size
createdAt
downloadPath
}
}
metadata
{
...
...
app/assets/javascripts/packages_and_registries/package_registry/pages/details.js
View file @
7df4f855
...
...
@@ -18,7 +18,6 @@ export default () => {
apolloProvider
,
provide
:
{
canDelete
:
parseBoolean
(
canDelete
),
titleComponent
:
'
PackageTitle
'
,
...
datasetOptions
,
},
render
(
createElement
)
{
...
...
spec/frontend/packages_and_registries/package_registry/components/details/app_spec.js
View file @
7df4f855
import
{
GlEmptyState
,
GlModal
}
from
'
@gitlab/ui
'
;
import
{
GlEmptyState
}
from
'
@gitlab/ui
'
;
import
{
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
nextTick
}
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
import
{
useMockLocationHelper
}
from
'
helpers/mock_window_location_helper
'
;
...
...
@@ -10,13 +11,19 @@ import createFlash from '~/flash';
import
AdditionalMetadata
from
'
~/packages_and_registries/package_registry/components/details/additional_metadata.vue
'
;
import
PackagesApp
from
'
~/packages_and_registries/package_registry/components/details/app.vue
'
;
import
InstallationCommands
from
'
~/packages_and_registries/package_registry/components/details/installation_commands.vue
'
;
import
PackageFiles
from
'
~/packages_and_registries/package_registry/components/details/package_files.vue
'
;
import
PackageHistory
from
'
~/packages_and_registries/package_registry/components/details/package_history.vue
'
;
import
PackageTitle
from
'
~/packages_and_registries/package_registry/components/details/package_title.vue
'
;
import
{
FETCH_PACKAGE_DETAILS_ERROR_MESSAGE
,
DELETE_PACKAGE_ERROR_MESSAGE
,
PACKAGE_TYPE_COMPOSER
,
DELETE_PACKAGE_FILE_SUCCESS_MESSAGE
,
DELETE_PACKAGE_FILE_ERROR_MESSAGE
,
}
from
'
~/packages_and_registries/package_registry/constants
'
;
import
destroyPackageMutation
from
'
~/packages_and_registries/package_registry/graphql/mutations/destroy_package.mutation.graphql
'
;
import
destroyPackageFileMutation
from
'
~/packages_and_registries/package_registry/graphql/mutations/destroy_package_file.mutation.graphql
'
;
import
getPackageDetails
from
'
~/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql
'
;
import
{
packageDetailsQuery
,
...
...
@@ -24,6 +31,9 @@ import {
emptyPackageDetailsQuery
,
packageDestroyMutation
,
packageDestroyMutationError
,
packageFiles
,
packageDestroyFileMutation
,
packageDestroyFileMutationError
,
}
from
'
../../mock_data
'
;
jest
.
mock
(
'
~/flash
'
);
...
...
@@ -50,12 +60,14 @@ describe('PackagesApp', () => {
function
createComponent
({
resolver
=
jest
.
fn
().
mockResolvedValue
(
packageDetailsQuery
()),
mutationResolver
=
jest
.
fn
().
mockResolvedValue
(
packageDestroyMutation
()),
fileDeleteMutationResolver
=
jest
.
fn
().
mockResolvedValue
(
packageDestroyFileMutation
()),
}
=
{})
{
localVue
.
use
(
VueApollo
);
const
requestHandlers
=
[
[
getPackageDetails
,
resolver
],
[
destroyPackageMutation
,
mutationResolver
],
[
destroyPackageFileMutation
,
fileDeleteMutationResolver
],
];
apolloProvider
=
createMockApollo
(
requestHandlers
);
...
...
@@ -63,7 +75,15 @@ describe('PackagesApp', () => {
localVue
,
apolloProvider
,
provide
,
stubs
:
{
PackageTitle
},
stubs
:
{
PackageTitle
,
GlModal
:
{
template
:
'
<div></div>
'
,
methods
:
{
show
:
jest
.
fn
(),
},
},
},
});
}
...
...
@@ -72,8 +92,10 @@ describe('PackagesApp', () => {
const
findPackageHistory
=
()
=>
wrapper
.
findComponent
(
PackageHistory
);
const
findAdditionalMetadata
=
()
=>
wrapper
.
findComponent
(
AdditionalMetadata
);
const
findInstallationCommands
=
()
=>
wrapper
.
findComponent
(
InstallationCommands
);
const
findDeleteModal
=
()
=>
wrapper
.
find
Component
(
GlModal
);
const
findDeleteModal
=
()
=>
wrapper
.
find
ByTestId
(
'
delete-modal
'
);
const
findDeleteButton
=
()
=>
wrapper
.
findByTestId
(
'
delete-package
'
);
const
findPackageFiles
=
()
=>
wrapper
.
findComponent
(
PackageFiles
);
const
findDeleteFileModal
=
()
=>
wrapper
.
findByTestId
(
'
delete-file-modal
'
);
afterEach
(()
=>
{
wrapper
.
destroy
();
...
...
@@ -240,4 +262,104 @@ describe('PackagesApp', () => {
});
});
});
describe
(
'
package files
'
,
()
=>
{
it
(
'
renders the package files component and has the right props
'
,
async
()
=>
{
const
expectedFile
=
{
...
packageFiles
()[
0
]
};
// eslint-disable-next-line no-underscore-dangle
delete
expectedFile
.
__typename
;
createComponent
();
await
waitForPromises
();
expect
(
findPackageFiles
().
exists
()).
toBe
(
true
);
expect
(
findPackageFiles
().
props
(
'
packageFiles
'
)[
0
]).
toMatchObject
(
expectedFile
);
});
it
(
'
does not render the package files table when the package is composer
'
,
async
()
=>
{
createComponent
({
resolver
:
jest
.
fn
()
.
mockResolvedValue
(
packageDetailsQuery
({
packageType
:
PACKAGE_TYPE_COMPOSER
})),
});
await
waitForPromises
();
expect
(
findPackageFiles
().
exists
()).
toBe
(
false
);
});
describe
(
'
deleting a file
'
,
()
=>
{
const
[
fileToDelete
]
=
packageFiles
();
const
doDeleteFile
=
()
=>
{
findPackageFiles
().
vm
.
$emit
(
'
delete-file
'
,
fileToDelete
);
findDeleteFileModal
().
vm
.
$emit
(
'
primary
'
);
return
waitForPromises
();
};
it
(
'
opens a confirmation modal
'
,
async
()
=>
{
createComponent
();
await
waitForPromises
();
findPackageFiles
().
vm
.
$emit
(
'
delete-file
'
,
fileToDelete
);
await
nextTick
();
expect
(
findDeleteFileModal
().
exists
()).
toBe
(
true
);
});
it
(
'
confirming on the modal deletes the file and shows a success message
'
,
async
()
=>
{
const
resolver
=
jest
.
fn
().
mockResolvedValue
(
packageDetailsQuery
());
createComponent
({
resolver
});
await
waitForPromises
();
await
doDeleteFile
();
expect
(
createFlash
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
message
:
DELETE_PACKAGE_FILE_SUCCESS_MESSAGE
,
}),
);
// we are re-fetching the package details, so we expect the resolver to have been called twice
expect
(
resolver
).
toHaveBeenCalledTimes
(
2
);
});
describe
(
'
errors
'
,
()
=>
{
it
(
'
shows an error when the mutation request fails
'
,
async
()
=>
{
createComponent
({
fileDeleteMutationResolver
:
jest
.
fn
().
mockRejectedValue
()
});
await
waitForPromises
();
await
doDeleteFile
();
expect
(
createFlash
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
message
:
DELETE_PACKAGE_FILE_ERROR_MESSAGE
,
}),
);
});
it
(
'
shows an error when the mutation request returns an error payload
'
,
async
()
=>
{
createComponent
({
fileDeleteMutationResolver
:
jest
.
fn
()
.
mockResolvedValue
(
packageDestroyFileMutationError
()),
});
await
waitForPromises
();
await
doDeleteFile
();
expect
(
createFlash
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
message
:
DELETE_PACKAGE_FILE_ERROR_MESSAGE
,
}),
);
});
});
});
});
});
spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js
View file @
7df4f855
import
{
GlDropdown
,
GlButton
}
from
'
@gitlab/ui
'
;
import
{
mount
}
from
'
@vue/test-utils
'
;
import
{
nextTick
}
from
'
vue
'
;
import
stubChildren
from
'
helpers/stub_children
'
;
import
{
npmFiles
,
mavenFiles
}
from
'
jest/packages/mock_data
'
;
import
component
from
'
~/packages_and_registries/package_registry/components/details/package_files.vue
'
;
import
{
mountExtended
,
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
{
packageFiles
as
packageFilesMock
}
from
'
jest/packages_and_registries/package_registry/mock_data
'
;
import
PackageFiles
from
'
~/packages_and_registries/package_registry/components/details/package_files.vue
'
;
import
FileIcon
from
'
~/vue_shared/components/file_icon.vue
'
;
import
TimeAgoTooltip
from
'
~/vue_shared/components/time_ago_tooltip.vue
'
;
describe
(
'
Package Files
'
,
()
=>
{
let
wrapper
;
const
findAllRows
=
()
=>
wrapper
.
findAll
(
'
[data-testid="file-row"
'
);
const
findFirstRow
=
()
=>
findAllRows
().
at
(
0
);
const
findSecondRow
=
()
=>
findAllRows
().
at
(
1
);
const
findFirstRowDownloadLink
=
()
=>
findFirstRow
().
find
(
'
[data-testid="download-link"]
'
);
const
findFirstRowCommitLink
=
()
=>
findFirstRow
().
find
(
'
[data-testid="commit-link"]
'
);
const
findSecondRowCommitLink
=
()
=>
findSecondRow
().
find
(
'
[data-testid="commit-link"]
'
);
const
findFirstRowFileIcon
=
()
=>
findFirstRow
().
find
(
FileIcon
);
const
findFirstRowCreatedAt
=
()
=>
findFirstRow
().
find
(
TimeAgoTooltip
);
const
findFirstActionMenu
=
()
=>
findFirstRow
().
findComponent
(
GlDropdown
);
const
findActionMenuDelete
=
()
=>
findFirstActionMenu
().
find
(
'
[data-testid="delete-file"]
'
);
const
findAllRows
=
()
=>
wrapper
.
findAll
ByTestId
(
'
file-row
'
);
const
findFirstRow
=
()
=>
extendedWrapper
(
findAllRows
().
at
(
0
)
);
const
findSecondRow
=
()
=>
extendedWrapper
(
findAllRows
().
at
(
1
)
);
const
findFirstRowDownloadLink
=
()
=>
findFirstRow
().
find
ByTestId
(
'
download-link
'
);
const
findFirstRowCommitLink
=
()
=>
findFirstRow
().
find
ByTestId
(
'
commit-link
'
);
const
findSecondRowCommitLink
=
()
=>
findSecondRow
().
find
ByTestId
(
'
commit-link
'
);
const
findFirstRowFileIcon
=
()
=>
findFirstRow
().
find
Component
(
FileIcon
);
const
findFirstRowCreatedAt
=
()
=>
findFirstRow
().
find
Component
(
TimeAgoTooltip
);
const
findFirstActionMenu
=
()
=>
extendedWrapper
(
findFirstRow
().
findComponent
(
GlDropdown
)
);
const
findActionMenuDelete
=
()
=>
findFirstActionMenu
().
find
ByTestId
(
'
delete-file
'
);
const
findFirstToggleDetailsButton
=
()
=>
findFirstRow
().
findComponent
(
GlButton
);
const
findFirstRowShaComponent
=
(
id
)
=>
wrapper
.
find
(
`[data-testid="
${
id
}
"]`
);
const
findFirstRowShaComponent
=
(
id
)
=>
wrapper
.
find
ByTestId
(
id
);
const
createComponent
=
({
packageFiles
=
npmFiles
,
canDelete
=
true
}
=
{})
=>
{
wrapper
=
mount
(
component
,
{
const
files
=
packageFilesMock
();
const
[
file
]
=
files
;
const
createComponent
=
({
packageFiles
=
[
file
],
canDelete
=
true
}
=
{})
=>
{
wrapper
=
mountExtended
(
PackageFiles
,
{
provide
:
{
canDelete
},
propsData
:
{
packageFiles
,
canDelete
,
},
stubs
:
{
...
stubChildren
(
component
),
...
stubChildren
(
PackageFiles
),
GlTable
:
false
,
},
});
...
...
@@ -38,7 +41,6 @@ describe('Package Files', () => {
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
=
null
;
});
describe
(
'
rows
'
,
()
=>
{
...
...
@@ -49,7 +51,7 @@ describe('Package Files', () => {
});
it
(
'
renders multiple files for a package that contains more than one file
'
,
()
=>
{
createComponent
({
packageFiles
:
mavenF
iles
});
createComponent
({
packageFiles
:
f
iles
});
expect
(
findAllRows
()).
toHaveLength
(
2
);
});
...
...
@@ -65,7 +67,7 @@ describe('Package Files', () => {
it
(
'
has the correct attrs bound
'
,
()
=>
{
createComponent
();
expect
(
findFirstRowDownloadLink
().
attributes
(
'
href
'
)).
toBe
(
npmFiles
[
0
].
download_p
ath
);
expect
(
findFirstRowDownloadLink
().
attributes
(
'
href
'
)).
toBe
(
file
.
downloadP
ath
);
});
it
(
'
emits "download-file" event on click
'
,
()
=>
{
...
...
@@ -87,7 +89,7 @@ describe('Package Files', () => {
it
(
'
has the correct props bound
'
,
()
=>
{
createComponent
();
expect
(
findFirstRowFileIcon
().
props
(
'
fileName
'
)).
toBe
(
npmFiles
[
0
].
file_n
ame
);
expect
(
findFirstRowFileIcon
().
props
(
'
fileName
'
)).
toBe
(
file
.
fileN
ame
);
});
});
...
...
@@ -101,35 +103,47 @@ describe('Package Files', () => {
it
(
'
has the correct props bound
'
,
()
=>
{
createComponent
();
expect
(
findFirstRowCreatedAt
().
props
(
'
time
'
)).
toBe
(
npmFiles
[
0
].
created_a
t
);
expect
(
findFirstRowCreatedAt
().
props
(
'
time
'
)).
toBe
(
file
.
createdA
t
);
});
});
describe
(
'
commit
'
,
()
=>
{
const
withPipeline
=
{
...
file
,
pipelines
:
[
{
sha
:
'
sha
'
,
id
:
1
,
commitPath
:
'
commitPath
'
,
},
],
};
describe
(
'
when package file has a pipeline associated
'
,
()
=>
{
it
(
'
exists
'
,
()
=>
{
createComponent
();
createComponent
(
{
packageFiles
:
[
withPipeline
]
}
);
expect
(
findFirstRowCommitLink
().
exists
()).
toBe
(
true
);
});
it
(
'
the link points to the commit
url
'
,
()
=>
{
createComponent
();
it
(
'
the link points to the commit
path
'
,
()
=>
{
createComponent
(
{
packageFiles
:
[
withPipeline
]
}
);
expect
(
findFirstRowCommitLink
().
attributes
(
'
href
'
)).
toBe
(
npmFiles
[
0
].
pipelines
[
0
].
project
.
commit_url
,
withPipeline
.
pipelines
[
0
].
commitPath
,
);
});
it
(
'
the text is
git_commit_message
'
,
()
=>
{
createComponent
();
it
(
'
the text is
the pipeline sha
'
,
()
=>
{
createComponent
(
{
packageFiles
:
[
withPipeline
]
}
);
expect
(
findFirstRowCommitLink
().
text
()).
toBe
(
npmFiles
[
0
].
pipelines
[
0
].
git_commit_message
);
expect
(
findFirstRowCommitLink
().
text
()).
toBe
(
withPipeline
.
pipelines
[
0
].
sha
);
});
});
describe
(
'
when package file has no pipeline associated
'
,
()
=>
{
it
(
'
does not exist
'
,
()
=>
{
createComponent
(
{
packageFiles
:
mavenFiles
}
);
createComponent
();
expect
(
findFirstRowCommitLink
().
exists
()).
toBe
(
false
);
});
...
...
@@ -137,7 +151,7 @@ describe('Package Files', () => {
describe
(
'
when only one file lacks an associated pipeline
'
,
()
=>
{
it
(
'
renders the commit when it exists and not otherwise
'
,
()
=>
{
createComponent
({
packageFiles
:
[
npmFiles
[
0
],
mavenFiles
[
0
]
]
});
createComponent
({
packageFiles
:
[
withPipeline
,
file
]
});
expect
(
findFirstRowCommitLink
().
exists
()).
toBe
(
true
);
expect
(
findSecondRowCommitLink
().
exists
()).
toBe
(
false
);
...
...
@@ -166,7 +180,7 @@ describe('Package Files', () => {
findActionMenuDelete
().
vm
.
$emit
(
'
click
'
);
const
[[{
id
}]]
=
wrapper
.
emitted
(
'
delete-file
'
);
expect
(
id
).
toBe
(
npmFiles
[
0
]
.
id
);
expect
(
id
).
toBe
(
file
.
id
);
});
});
});
...
...
@@ -193,10 +207,10 @@ describe('Package Files', () => {
});
it
(
'
is hidden when no details is present
'
,
()
=>
{
const
[{
...
noShaFile
}]
=
npmFiles
;
noShaFile
.
file
_s
ha256
=
null
;
noShaFile
.
file
_m
d5
=
null
;
noShaFile
.
file
_s
ha1
=
null
;
const
{
...
noShaFile
}
=
file
;
noShaFile
.
file
S
ha256
=
null
;
noShaFile
.
file
M
d5
=
null
;
noShaFile
.
file
S
ha1
=
null
;
createComponent
({
packageFiles
:
[
noShaFile
]
});
expect
(
findFirstToggleDetailsButton
().
exists
()).
toBe
(
false
);
...
...
@@ -229,9 +243,9 @@ describe('Package Files', () => {
it
.
each
`
selector | title | sha
${
'
sha-256
'
}
|
${
'
SHA-256
'
}
|
${
'
file
_s
ha256
'
}
${
'
md5
'
}
|
${
'
MD5
'
}
|
${
'
file
_m
d5
'
}
${
'
sha-1
'
}
|
${
'
SHA-1
'
}
|
${
'
file_sha1
'
}
${
'
sha-256
'
}
|
${
'
SHA-256
'
}
|
${
'
file
S
ha256
'
}
${
'
md5
'
}
|
${
'
MD5
'
}
|
${
'
file
M
d5
'
}
${
'
sha-1
'
}
|
${
'
SHA-1
'
}
|
${
'
be93151dc23ac34a82752444556fe79b32c7a1ad
'
}
`
(
'
has a $title row
'
,
async
({
selector
,
title
,
sha
})
=>
{
createComponent
();
...
...
@@ -244,8 +258,8 @@ describe('Package Files', () => {
});
it
(
'
does not display a row when the data is missing
'
,
async
()
=>
{
const
[{
...
missingMd5
}]
=
npmFiles
;
missingMd5
.
file
_m
d5
=
null
;
const
{
...
missingMd5
}
=
file
;
missingMd5
.
file
M
d5
=
null
;
createComponent
({
packageFiles
:
[
missingMd5
]
});
...
...
spec/frontend/packages_and_registries/package_registry/mock_data.js
View file @
7df4f855
...
...
@@ -29,11 +29,13 @@ export const packagePipelines = (extend) => [
export
const
packageFiles
=
()
=>
[
{
id
:
'
gid://gitlab/Packages::PackageFile/118
'
,
fileMd5
:
null
,
fileMd5
:
'
fileMd5
'
,
fileName
:
'
foo-1.0.1.tgz
'
,
fileSha1
:
'
be93151dc23ac34a82752444556fe79b32c7a1ad
'
,
fileSha256
:
null
,
fileSha256
:
'
fileSha256
'
,
size
:
'
409600
'
,
createdAt
:
'
2020-08-17T14:23:32Z
'
,
downloadPath
:
'
downloadPath
'
,
__typename
:
'
PackageFile
'
,
},
{
...
...
@@ -43,6 +45,8 @@ export const packageFiles = () => [
fileSha1
:
'
be93151dc23ac34a82752444556fe79b32c7a1ss
'
,
fileSha256
:
null
,
size
:
'
409600
'
,
createdAt
:
'
2020-08-17T14:23:32Z
'
,
downloadPath
:
'
downloadPath
'
,
__typename
:
'
PackageFile
'
,
},
];
...
...
@@ -90,7 +94,7 @@ export const nugetMetadata = () => ({
projectUrl
:
'
projectUrl
'
,
});
export
const
packageDetailsQuery
=
()
=>
({
export
const
packageDetailsQuery
=
(
extendPackage
)
=>
({
data
:
{
package
:
{
...
packageData
(),
...
...
@@ -114,6 +118,7 @@ export const packageDetailsQuery = () => ({
__typename
:
'
PackageFileConnection
'
,
},
__typename
:
'
PackageDetailsType
'
,
...
extendPackage
,
},
},
});
...
...
@@ -133,6 +138,7 @@ export const packageDestroyMutation = () => ({
},
},
});
export
const
packageDestroyMutationError
=
()
=>
({
data
:
{
destroyPackage
:
null
,
...
...
@@ -151,3 +157,29 @@ export const packageDestroyMutationError = () => ({
},
],
});
export
const
packageDestroyFileMutation
=
()
=>
({
data
:
{
destroyPackageFile
:
{
errors
:
[],
},
},
});
export
const
packageDestroyFileMutationError
=
()
=>
({
data
:
{
destroyPackageFile
:
null
,
},
errors
:
[
{
message
:
"
The resource that you are attempting to access does not exist or you don't have permission to perform this action
"
,
locations
:
[
{
line
:
2
,
column
:
3
,
},
],
path
:
[
'
destroyPackageFile
'
],
},
],
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment