feat: [AH-667]: add unit test coverage for version details page > artifact details tab (#3433)

* feat: [AH-667]: add unit test coverage for version details page > artifact details tab
This commit is contained in:
Shivanand Sonnad 2025-02-14 11:34:08 +00:00 committed by Harness
parent 186751ec6c
commit ff82bd4b0d
13 changed files with 1118 additions and 54 deletions

View File

@ -0,0 +1,246 @@
/*
* Copyright 2024 Harness, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react'
import copy from 'clipboard-copy'
import userEvent from '@testing-library/user-event'
import { getByTestId, getByText, render, waitFor } from '@testing-library/react'
import { useGetDockerArtifactLayersQuery, useGetDockerArtifactManifestQuery } from '@harnessio/react-har-service-client'
import { getTableColumn } from '@ar/utils/testUtils/utils'
import ArTestWrapper from '@ar/utils/testUtils/ArTestWrapper'
import VersionDetailsPage from '../../VersionDetailsPage'
import {
mockDockerArtifactLayers,
mockDockerArtifactManifest,
mockDockerManifestList,
mockDockerVersionList,
mockDockerVersionSummary
} from './__mockData__'
const mockHistoryPush = jest.fn()
// eslint-disable-next-line jest-no-mock
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush
})
}))
jest.mock('clipboard-copy', () => ({
__esModule: true,
default: jest.fn()
}))
jest.mock('@harnessio/react-har-service-client', () => ({
useGetArtifactVersionSummaryQuery: jest.fn().mockImplementation(() => ({
data: { content: mockDockerVersionSummary },
error: null,
isLoading: false,
refetch: jest.fn()
})),
useGetDockerArtifactManifestsQuery: jest.fn().mockImplementation(() => ({
data: { content: mockDockerManifestList },
error: null,
isLoading: false,
refetch: jest.fn()
})),
getAllArtifactVersions: jest.fn().mockImplementation(
() =>
new Promise(success => {
success({ content: mockDockerVersionList })
})
),
useGetDockerArtifactLayersQuery: jest.fn().mockImplementation(() => ({
data: { content: mockDockerArtifactLayers },
error: null,
isLoading: false,
refetch: jest.fn()
})),
useGetDockerArtifactManifestQuery: jest.fn().mockImplementation(() => ({
data: { content: mockDockerArtifactManifest },
error: null,
isLoading: false,
refetch: jest.fn()
}))
}))
describe('Verify Docker Version Artifact Details Tab', () => {
beforeAll(() => {
jest.clearAllMocks()
})
test('Verify Sub Tabs', async () => {
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}
queryParams={{
digest: 'sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d',
detailsTab: 'layers'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
expect(getByTestId(container, 'layers')).toBeInTheDocument()
expect(getByTestId(container, 'manifest')).toBeInTheDocument()
const manifestTab = getByTestId(container, 'manifest')
await userEvent.click(manifestTab)
expect(mockHistoryPush).toHaveBeenCalledWith(
'/registries/1/artifacts/1/versions/1/artifact_details?digest=sha256%3A144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d&detailsTab=manifest'
)
const layersTab = getByTestId(container, 'layers')
await userEvent.click(layersTab)
expect(mockHistoryPush).toHaveBeenCalledWith(
'/registries/1/artifacts/1/versions/1/artifact_details?digest=sha256%3A144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d&detailsTab=layers'
)
})
test('Verify Layers Tab', async () => {
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}
queryParams={{
digest: 'sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d',
detailsTab: 'layers'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
expect(container).toHaveTextContent('versionDetails.artifactDetails.layers.imageLayers')
const getTableRowColumn = (row: number, col: number) => getTableColumn(row, col) as HTMLElement
const data = mockDockerArtifactLayers.data.layers?.[0]
const row = 1
expect(getTableRowColumn(row, 1)).toHaveTextContent(row.toString())
expect(getTableRowColumn(row, 2)).toHaveTextContent(data?.command as string)
expect(getTableRowColumn(row, 3)).toHaveTextContent(data?.size as string)
const copyColumn = getTableRowColumn(row, 4)
const copyBtn = copyColumn.querySelector('[data-icon="code-copy"]') as HTMLElement
expect(copyBtn).toBeInTheDocument()
await userEvent.click(copyBtn)
expect(copy).toHaveBeenCalledWith(data?.command)
})
test('should show error message if failed to load layers data', async () => {
const refetchFn = jest.fn()
;(useGetDockerArtifactLayersQuery as jest.Mock).mockImplementation(() => ({
data: null,
error: { message: 'Failed to fetch artifact details' },
isLoading: false,
refetch: refetchFn
}))
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}
queryParams={{
digest: 'sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d',
detailsTab: 'layers'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
expect(getByText(container, 'Failed to fetch artifact details')).toBeInTheDocument()
const retryBtn = container.querySelector('button[aria-label=Retry]')
expect(retryBtn).toBeInTheDocument()
await userEvent.click(retryBtn!)
await waitFor(() => {
expect(refetchFn).toHaveBeenCalled()
})
})
test('Verify Manifest Tab', async () => {
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}
queryParams={{
digest: 'sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d',
detailsTab: 'manifest'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
expect(container).toHaveTextContent('versionDetails.artifactDetails.tabs.manifest')
const copyBtn = container.querySelector('[data-icon="code-copy"]') as HTMLElement
expect(copyBtn).toBeInTheDocument()
await userEvent.click(copyBtn)
expect(copy).toHaveBeenCalledWith(mockDockerArtifactManifest.data.manifest)
})
test('should show error message if failed to load manifest data', async () => {
const refetchFn = jest.fn()
;(useGetDockerArtifactManifestQuery as jest.Mock).mockImplementation(() => ({
data: null,
error: { message: 'Failed to fetch artifact details' },
isLoading: false,
refetch: refetchFn
}))
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}
queryParams={{
digest: 'sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d',
detailsTab: 'manifest'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
expect(getByText(container, 'Failed to fetch artifact details')).toBeInTheDocument()
const retryBtn = container.querySelector('button[aria-label=Retry]')
expect(retryBtn).toBeInTheDocument()
await userEvent.click(retryBtn!)
await waitFor(() => {
expect(refetchFn).toHaveBeenCalled()
})
})
})

View File

@ -20,6 +20,7 @@ import { getByTestId, render, waitFor } from '@testing-library/react'
import {
type DockerManifestDetails,
getAllArtifactVersions,
useGetArtifactVersionSummaryQuery,
useGetDockerArtifactManifestsQuery
} from '@harnessio/react-har-service-client'
@ -29,7 +30,12 @@ import { testSelectChange } from '@ar/utils/testUtils/utils'
import ArTestWrapper from '@ar/utils/testUtils/ArTestWrapper'
import VersionDetailsPage from '../../VersionDetailsPage'
import { mockDockerManifestList, mockDockerVersionList, mockDockerVersionSummary } from './__mockData__'
import {
mockDockerManifestList,
mockDockerVersionList,
mockDockerVersionSummary,
mockDockerVersionSummaryWithoutSscaAndStoData
} from './__mockData__'
const mockHistoryPush = jest.fn()
// eslint-disable-next-line jest-no-mock
@ -124,7 +130,7 @@ describe('Verify DockerVersionHeader component render', () => {
await testSelectChange(versionSelector, '1.0.1', data.version)
await waitFor(() => {
expect(mockHistoryPush).toHaveBeenLastCalledWith('/registries/artifacts/versions/1.0.1')
expect(mockHistoryPush).toHaveBeenCalledWith('/registries/artifacts/versions/1.0.1')
})
})
@ -262,4 +268,80 @@ describe('Verify DockerVersionHeader component render', () => {
const selectPopover = dialogs[0] as HTMLElement
expect(selectPopover).toHaveTextContent('No items found')
})
test('verify tab navigation with ssca and sto data', async () => {
const { container } = render(
<ArTestWrapper
queryParams={{
digest: 'sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
const overviewTab = container.querySelector('div[data-tab-id=overview]')
await userEvent.click(overviewTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/overview?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const artifactDetailsTab = container.querySelector('div[data-tab-id=artifact_details]')
await userEvent.click(artifactDetailsTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/artifact_details?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const sscaTab = container.querySelector('div[data-tab-id=supply_chain]')
await userEvent.click(sscaTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/artifact-sources/67a5dccf6d75916b0c3ea1b5/artifacts/67a5dccf6d75916b0c3ea1b6/supply_chain?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const stoTab = container.querySelector('div[data-tab-id=security_tests]')
await userEvent.click(stoTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/pipelines/HARNESS_ARTIFACT_SCAN_PIPELINE/executions/Tbi7s6nETjmOMKU3Qrnm7A/security_tests?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
})
test('verify tab navigation with ssca and sto data', async () => {
;(useGetArtifactVersionSummaryQuery as jest.Mock).mockImplementation(() => ({
data: { content: mockDockerVersionSummaryWithoutSscaAndStoData },
error: null,
isLoading: false,
refetch: jest.fn()
}))
const { container } = render(
<ArTestWrapper
queryParams={{
digest: 'sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
const overviewTab = container.querySelector('div[data-tab-id=overview]')
await userEvent.click(overviewTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/overview?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const artifactDetailsTab = container.querySelector('div[data-tab-id=artifact_details]')
await userEvent.click(artifactDetailsTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/artifact_details?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const sscaTab = container.querySelector('div[data-tab-id=supply_chain]')
await userEvent.click(sscaTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/supply_chain?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const stoTab = container.querySelector('div[data-tab-id=security_tests]')
await userEvent.click(stoTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/security_tests?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
})
})

View File

@ -21,6 +21,7 @@ import {
useGetDockerArtifactDetailsQuery,
useGetDockerArtifactIntegrationDetailsQuery
} from '@harnessio/react-har-service-client'
import { downloadSbom } from '@harnessio/react-ssca-manager-client'
import ArTestWrapper from '@ar/utils/testUtils/ArTestWrapper'
@ -34,10 +35,31 @@ import {
mockDockerArtifactDetails,
mockDockerArtifactIntegrationDetails,
mockDockerManifestList,
mockDockerSbomData,
mockDockerVersionList,
mockDockerVersionSummary
} from './__mockData__'
const mockHistoryPush = jest.fn()
// eslint-disable-next-line jest-no-mock
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush
})
}))
const showErrorToast = jest.fn()
jest.mock('@harnessio/uicore', () => ({
...jest.requireActual('@harnessio/uicore'),
useToaster: jest.fn().mockImplementation(() => ({
showSuccess: jest.fn(),
showError: showErrorToast,
clear: jest.fn()
}))
}))
jest.mock('@harnessio/react-har-service-client', () => ({
useGetArtifactVersionSummaryQuery: jest.fn().mockImplementation(() => ({
data: { content: mockDockerVersionSummary },
@ -71,6 +93,15 @@ jest.mock('@harnessio/react-har-service-client', () => ({
}))
}))
jest.mock('@harnessio/react-ssca-manager-client', () => ({
downloadSbom: jest.fn().mockImplementation(
() =>
new Promise(success => {
success({ content: mockDockerSbomData })
})
)
}))
describe('Verify docker version overview page', () => {
beforeAll(() => {
jest.clearAllMocks()
@ -99,12 +130,24 @@ describe('Verify docker version overview page', () => {
expect(deploymentCard).toHaveTextContent(data.deploymentsDetails?.totalDeployment?.toString() as string)
expect(deploymentCard).toHaveTextContent(data.buildDetails?.pipelineDisplayName as string)
expect(deploymentCard).toHaveTextContent(data.buildDetails?.pipelineExecutionId as string)
await userEvent.click(deploymentCard)
await waitFor(() => {
expect(mockHistoryPush).toHaveBeenCalledWith(
'/registries/1/artifacts/1/versions/1/deployments?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
})
const sscaCard = getByTestId(container, 'integration-supply-chain-card')
expect(sscaCard).toBeInTheDocument()
expect(sscaCard).toHaveTextContent(data.sbomDetails?.componentsCount?.toString() as string)
expect(sscaCard).toHaveTextContent(Number(data.sbomDetails?.avgScore).toFixed(2) as string)
expect(getByText(sscaCard, 'versionDetails.cards.supplyChain.downloadSbom')).toBeInTheDocument()
await userEvent.click(sscaCard)
await waitFor(() => {
expect(mockHistoryPush).toHaveBeenCalledWith(
'/registries/1/artifacts/1/versions/1/artifact-sources/67a5dccf6d75916b0c3ea1b5/artifacts/67a5dccf6d75916b0c3ea1b6/supply_chain?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
})
const securityTestsCard = getByTestId(container, 'integration-security-tests-card')
expect(securityTestsCard).toBeInTheDocument()
@ -113,6 +156,62 @@ describe('Verify docker version overview page', () => {
expect(securityTestsCard).toHaveTextContent(data.stoDetails?.high?.toString() as string)
expect(securityTestsCard).toHaveTextContent(data.stoDetails?.medium?.toString() as string)
expect(securityTestsCard).toHaveTextContent(data.stoDetails?.low?.toString() as string)
await userEvent.click(securityTestsCard)
await waitFor(() => {
expect(mockHistoryPush).toHaveBeenCalledWith(
'/registries/1/artifacts/1/versions/1/pipelines/HARNESS_ARTIFACT_SCAN_PIPELINE/executions/Tbi7s6nETjmOMKU3Qrnm7A/security_tests?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
})
})
test('Verify action button on ssca card', async () => {
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'overview'
}}
queryParams={{ digest: 'sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d' }}>
<VersionDetailsPage />
</ArTestWrapper>
)
expect(getByTestId(container, 'integration-cards')).toBeInTheDocument()
const sscaCard = getByTestId(container, 'integration-supply-chain-card')
const downloadSbomBtn = getByText(sscaCard, 'versionDetails.cards.supplyChain.downloadSbom')
expect(downloadSbomBtn).toBeInTheDocument()
await userEvent.click(downloadSbomBtn)
await waitFor(() => {
expect(downloadSbom).toHaveBeenCalledWith({ 'orchestration-id': 'yw0D70fiTqetxx0HIyvEUQ', org: '', project: '' })
})
// empty response scenario
;(downloadSbom as jest.Mock).mockImplementationOnce(
() =>
new Promise(success => {
success({ content: { sbom: null } })
})
)
await userEvent.click(downloadSbomBtn)
await waitFor(() => {
expect(showErrorToast).toHaveBeenCalledWith('versionDetails.cards.supplyChain.SBOMDataNotAvailable')
})
// error scenario
;(downloadSbom as jest.Mock).mockImplementationOnce(
() =>
new Promise((_, reject) => {
reject({ message: 'error message' })
})
)
await userEvent.click(downloadSbomBtn)
await waitFor(() => {
expect(showErrorToast).toHaveBeenCalledWith('error message')
})
})
test('should show error message if failed to load integration data', async () => {

View File

@ -18,6 +18,8 @@ import type {
ArtifactVersionSummaryResponseResponse,
DockerArtifactDetailIntegrationResponseResponse,
DockerArtifactDetailResponseResponse,
DockerArtifactManifestResponseResponse,
DockerLayersResponseResponse,
DockerManifestsResponseResponse,
ListArtifactVersion,
ListArtifactVersionResponseResponse
@ -86,6 +88,15 @@ export const mockDockerVersionSummary: ArtifactVersionSummaryResponseResponse =
status: 'SUCCESS'
}
export const mockDockerVersionSummaryWithoutSscaAndStoData: ArtifactVersionSummaryResponseResponse = {
data: {
imageName: 'maven-app',
packageType: 'DOCKER',
version: '1.0.0'
},
status: 'SUCCESS'
}
export const mockDockerVersionList: ListArtifactVersionResponseResponse = {
data: {
artifactVersions: [
@ -238,3 +249,80 @@ export const mockDockerArtifactIntegrationDetails: DockerArtifactDetailIntegrati
},
status: 'SUCCESS'
}
export const mockDockerArtifactLayers: DockerLayersResponseResponse = {
data: {
digest: 'sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d',
layers: [
{
command: '/bin/sh -c #(nop) ADD file:6fef7a4ab2de57c438dad76949e7eb87cfb1ea6f45b0f2423f71188efdaa0d8e in /',
size: '40.07 MB'
},
{
command: '/bin/sh -c #(nop) CMD ["/bin/bash"]',
size: '0 B'
},
{
command:
'/bin/sh -c set -eux; \tmicrodnf install \t\tgzip \t\ttar \t\t\t\tbinutils \t\tfreetype fontconfig \t; \tmicrodnf clean all',
size: '13.63 MB'
},
{
command: '/bin/sh -c #(nop) ENV JAVA_HOME=/usr/java/openjdk-17',
size: '0 B'
},
{
command:
'/bin/sh -c #(nop) ENV PATH=/usr/java/openjdk-17/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
size: '0 B'
},
{
command: '/bin/sh -c #(nop) ENV LANG=C.UTF-8',
size: '0 B'
},
{
command: '/bin/sh -c #(nop) ENV JAVA_VERSION=17.0.2',
size: '0 B'
},
{
command:
'/bin/sh -c set -eux; \t\tarch="$(objdump="$(command -v objdump)" \u0026\u0026 objdump --file-headers "$objdump" | awk -F \'[:,]+[[:space:]]+\' \'$1 == "architecture" { print $2 }\')"; \tcase "$arch" in \t\t\'i386:x86-64\') \t\t\tdownloadUrl=\'https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_linux-x64_bin.tar.gz\'; \t\t\tdownloadSha256=\'0022753d0cceecacdd3a795dd4cea2bd7ffdf9dc06e22ffd1be98411742fbb44\'; \t\t\t;; \t\t\'aarch64\') \t\t\tdownloadUrl=\'https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_linux-aarch64_bin.tar.gz\'; \t\t\tdownloadSha256=\'13bfd976acf8803f862e82c7113fb0e9311ca5458b1decaef8a09ffd91119fa4\'; \t\t\t;; \t\t*) echo \u003e\u00262 "error: unsupported architecture: \'$arch\'"; exit 1 ;; \tesac; \t\tcurl -fL -o openjdk.tgz "$downloadUrl"; \techo "$downloadSha256 *openjdk.tgz" | sha256sum --strict --check -; \t\tmkdir -p "$JAVA_HOME"; \ttar --extract \t\t--file openjdk.tgz \t\t--directory "$JAVA_HOME" \t\t--strip-components 1 \t\t--no-same-owner \t; \trm openjdk.tgz*; \t\trm -rf "$JAVA_HOME/lib/security/cacerts"; \tln -sT /etc/pki/ca-trust/extracted/java/cacerts "$JAVA_HOME/lib/security/cacerts"; \t\tln -sfT "$JAVA_HOME" /usr/java/default; \tln -sfT "$JAVA_HOME" /usr/java/latest; \tfor bin in "$JAVA_HOME/bin/"*; do \t\tbase="$(basename "$bin")"; \t\t[ ! -e "/usr/bin/$base" ]; \t\talternatives --install "/usr/bin/$base" "$base" "$bin" 20000; \tdone; \t\tjava -Xshare:dump; \t\tfileEncoding="$(echo \'System.out.println(System.getProperty("file.encoding"))\' | jshell -s -)"; [ "$fileEncoding" = \'UTF-8\' ]; rm -rf ~/.java; \tjavac --version; \tjava --version',
size: '177.73 MB'
},
{
command: '/bin/sh -c #(nop) CMD ["jshell"]',
size: '0 B'
},
{
command: 'WORKDIR /app',
size: '93 B'
},
{
command: 'COPY target/mavensampleapp-1.0.0.jar app.jar # buildkit',
size: '14.98 MB'
},
{
command: 'EXPOSE map[8080/tcp:{}]',
size: '0 B'
},
{
command: 'ENTRYPOINT ["java" "-jar" "app.jar"]',
size: '0 B'
}
],
osArch: 'linux/arm64'
},
status: 'SUCCESS'
}
export const mockDockerArtifactManifest: DockerArtifactManifestResponseResponse = {
data: {
manifest:
'{\n "schemaVersion": 2,\n "mediaType": "application/vnd.docker.distribution.manifest.v2+json",\n "config": {\n "mediaType": "application/vnd.docker.container.image.v1+json",\n "digest": "sha256:f152582e19dbda7e3fb677e83af07fb60b05a56757b15edd8915aef2191aad62",\n "size": 4682\n },\n "layers": [\n {\n "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",\n "digest": "sha256:416105dc84fc8cf66df5d2c9f81570a2cc36a6cae58aedd4d58792f041f7a2f5",\n "size": 42018977\n },\n {\n "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",\n "digest": "sha256:fe66142579ff5bb0bb5cf989222e2bc77a97dcbd0283887dec04d5b9dfd48cfa",\n "size": 14294224\n },\n {\n "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",\n "digest": "sha256:1250d2aa493e8744c8f6cb528c8a882c14b6d7ff0af6862bbbfe676f60ea979e",\n "size": 186363988\n },\n {\n "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",\n "digest": "sha256:6a92a853917fafa754249a4f309e5c34caae0ee5df4369dc1c9383d7cd1b395e",\n "size": 93\n },\n {\n "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",\n "digest": "sha256:b2e80a78034b601c2513a1b00947bda6c6cda46a95e217b954ed84f5b1b5c0fe",\n "size": 15712414\n }\n ]\n}'
},
status: 'SUCCESS'
}
export const mockDockerSbomData = {
sbom: 'Test Data'
}

View File

@ -0,0 +1,202 @@
/*
* Copyright 2024 Harness, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react'
import copy from 'clipboard-copy'
import userEvent from '@testing-library/user-event'
import { useGetArtifactFilesQuery } from '@harnessio/react-har-service-client'
import { getByText, queryByText, render, waitFor } from '@testing-library/react'
import { getTableColumn } from '@ar/utils/testUtils/utils'
import ArTestWrapper from '@ar/utils/testUtils/ArTestWrapper'
import VersionDetailsPage from '../../VersionDetailsPage'
import { mockGenericArtifactFiles, mockGenericVersionList, mockGenericVersionSummary } from './__mockData__'
const mockHistoryPush = jest.fn()
// eslint-disable-next-line jest-no-mock
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush
})
}))
jest.mock('clipboard-copy', () => ({
__esModule: true,
default: jest.fn()
}))
jest.mock('@harnessio/react-har-service-client', () => ({
useGetArtifactVersionSummaryQuery: jest.fn().mockImplementation(() => ({
data: { content: mockGenericVersionSummary },
error: null,
isLoading: false,
refetch: jest.fn()
})),
getAllArtifactVersions: jest.fn().mockImplementation(
() =>
new Promise(success => {
success({ content: mockGenericVersionList })
})
),
useGetArtifactFilesQuery: jest.fn().mockImplementation(() => ({
data: { content: mockGenericArtifactFiles },
error: null,
isLoading: false,
refetch: jest.fn()
}))
}))
describe('Verify Generic Artifact Version Artifact Details Tab', () => {
test('verify file list table', async () => {
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
expect(container).toBeInTheDocument()
const getTableRowColumn = (row: number, col: number) => getTableColumn(row, col) as HTMLElement
const data = mockGenericArtifactFiles.files[0]
const row = 1
expect(getTableRowColumn(row, 1)).toHaveTextContent(data.name)
expect(getTableRowColumn(row, 2)).toHaveTextContent(data?.size as string)
const column3Content = getTableRowColumn(row, 3)
data.checksums.forEach(async each => {
const [checksum, value] = each.split(': ')
const btn = getByText(column3Content, `copy ${checksum}`)
await userEvent.click(btn)
expect(copy).toHaveBeenCalledWith(value)
})
const copyColumn = getTableRowColumn(row, 4)
expect(copyColumn).toHaveTextContent('copy')
const copyBtn = copyColumn.querySelector('[data-icon="code-copy"]') as HTMLElement
expect(copyBtn).toBeInTheDocument()
await userEvent.click(copyBtn)
expect(copy).toHaveBeenCalledWith(data?.downloadCommand)
})
test('verify pagination and sorting actions', async () => {
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
const nextPageBtn = getByText(container, 'Next')
await userEvent.click(nextPageBtn)
expect(useGetArtifactFilesQuery).toHaveBeenLastCalledWith({
artifact: '1/+',
queryParams: { page: 0, size: 50, sort_field: 'updatedAt', sort_order: 'DESC' },
registry_ref: 'undefined/1/+',
version: '1'
})
const fileNameSortIcon = getByText(container, 'versionDetails.artifactFiles.table.columns.name').nextSibling
?.firstChild as HTMLElement
await userEvent.click(fileNameSortIcon)
await waitFor(() => {
expect(useGetArtifactFilesQuery).toHaveBeenLastCalledWith({
artifact: '1/+',
queryParams: { page: 0, size: 50, sort_field: 'updatedAt', sort_order: 'DESC' },
registry_ref: 'undefined/1/+',
version: '1'
})
})
})
test('verify error message', async () => {
const mockRefetchFn = jest.fn().mockImplementation(() => undefined)
;(useGetArtifactFilesQuery as jest.Mock).mockImplementationOnce(() => {
return {
data: null,
loading: false,
error: { message: 'error message' },
refetch: mockRefetchFn
}
})
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
const errorText = getByText(container, 'error message')
expect(errorText).toBeInTheDocument()
const retryBtn = getByText(container, 'Retry')
expect(retryBtn).toBeInTheDocument()
await userEvent.click(retryBtn)
expect(mockRefetchFn).toHaveBeenCalled()
})
test('verify with empty pagination response', async () => {
const mockRefetchFn = jest.fn().mockImplementation(() => undefined)
;(useGetArtifactFilesQuery as jest.Mock).mockImplementationOnce(() => {
return {
data: { content: { files: mockGenericArtifactFiles.files } },
loading: false,
error: null,
refetch: mockRefetchFn
}
})
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
const nextPageBtn = queryByText(container, 'Next')
expect(nextPageBtn).not.toBeInTheDocument()
})
})

View File

@ -17,6 +17,8 @@
import type {
ArtifactDetailResponseResponse,
ArtifactVersionSummaryResponseResponse,
FileDetail,
FileDetailResponseResponse,
ListArtifactVersion,
ListArtifactVersionResponseResponse
} from '@harnessio/react-har-service-client'
@ -119,3 +121,31 @@ export const mockGenericArtifactDetails: ArtifactDetailResponseResponse = {
},
status: 'SUCCESS'
}
export const mockGenericArtifactFiles: FileDetailResponseResponse = {
files: [
{
checksums: [
'SHA-512: ebfd0613c1c298d97fd7743ecd731b96a9c0a7f7cdbfdd9f19ec4682f9b4ceb400420a6191c9671bfb3e1cc5a9fef873ea1ad78f1b30794989a0fdb591f847cd',
'SHA-256: cc5ac7831841b65901c5578a47d6b125259f9a4364d1d73b0b5d8891ad3b7d34',
'SHA-1: b0e3200eb5eaca07d773916e306cd1ed9866d3a4',
'MD5: cc576cbab9119ad7589cae7b57146af6'
],
createdAt: '1738258177381',
downloadCommand:
"curl --location 'https://pkg.qa.harness.io/generic/iWnhltqOT7GFt7R-F_zP7Q/generic-registry/artifact:v1:image.png' --header 'x-api-key: \u003cAPI_KEY\u003e' -J -O",
name: 'image.png',
size: '170.18KB'
},
{
createdAt: '1738085520008',
name: 'hello.yaml',
size: '2.79MB'
} as FileDetail
],
itemCount: 2,
pageCount: 4,
pageIndex: 0,
pageSize: 50,
status: 'SUCCESS'
}

View File

@ -1,22 +0,0 @@
/*
* Copyright 2024 Harness, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react'
import DeploymentsContent from '@ar/pages/version-details/components/DeploymentsContent/DeploymentsContent'
export default function GenericArtifactDeploymentsPage() {
return <DeploymentsContent />
}

View File

@ -0,0 +1,119 @@
/*
* Copyright 2024 Harness, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react'
import copy from 'clipboard-copy'
import userEvent from '@testing-library/user-event'
import { getByText, render, waitFor } from '@testing-library/react'
import { useGetHelmArtifactManifestQuery } from '@harnessio/react-har-service-client'
import ArTestWrapper from '@ar/utils/testUtils/ArTestWrapper'
import { prettifyManifestJSON } from '../../utils'
import VersionDetailsPage from '../../VersionDetailsPage'
import { mockHelmArtifactManifest, mockHelmVersionList, mockHelmVersionSummary } from './__mockData__'
const mockHistoryPush = jest.fn()
// eslint-disable-next-line jest-no-mock
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush
})
}))
jest.mock('clipboard-copy', () => ({
__esModule: true,
default: jest.fn()
}))
jest.mock('@harnessio/react-har-service-client', () => ({
useGetArtifactVersionSummaryQuery: jest.fn().mockImplementation(() => ({
data: { content: mockHelmVersionSummary },
error: null,
isLoading: false,
refetch: jest.fn()
})),
getAllArtifactVersions: jest.fn().mockImplementation(
() =>
new Promise(success => {
success({ content: mockHelmVersionList })
})
),
useGetHelmArtifactManifestQuery: jest.fn().mockImplementation(() => ({
data: { content: mockHelmArtifactManifest },
error: null,
isLoading: false,
refetch: jest.fn()
}))
}))
describe('Verify Helm Version Artifact Details Tab', () => {
beforeAll(() => {
jest.clearAllMocks()
})
test('Verify Manifest', async () => {
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
expect(container).toHaveTextContent('versionDetails.artifactDetails.tabs.manifest')
const copyBtn = container.querySelector('[data-icon="code-copy"]') as HTMLElement
expect(copyBtn).toBeInTheDocument()
await userEvent.click(copyBtn)
expect(copy).toHaveBeenCalledWith(prettifyManifestJSON(mockHelmArtifactManifest.data.manifest))
})
test('should show error message if failed to load manifest data', async () => {
const refetchFn = jest.fn()
;(useGetHelmArtifactManifestQuery as jest.Mock).mockImplementation(() => ({
data: null,
error: { message: 'Failed to fetch artifact details' },
isLoading: false,
refetch: refetchFn
}))
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
expect(getByText(container, 'Failed to fetch artifact details')).toBeInTheDocument()
const retryBtn = container.querySelector('button[aria-label=Retry]')
expect(retryBtn).toBeInTheDocument()
await userEvent.click(retryBtn!)
await waitFor(() => {
expect(refetchFn).toHaveBeenCalled()
})
})
})

View File

@ -17,6 +17,7 @@
import type {
ArtifactVersionSummaryResponseResponse,
HelmArtifactDetailResponseResponse,
HelmArtifactManifestResponseResponse,
ListArtifactVersion,
ListArtifactVersionResponseResponse
} from '@harnessio/react-har-service-client'
@ -128,3 +129,11 @@ export const mockHelmArtifactDetails: HelmArtifactDetailResponseResponse = {
},
status: 'SUCCESS'
}
export const mockHelmArtifactManifest: HelmArtifactManifestResponseResponse = {
data: {
manifest:
'{"schemaVersion":2,"config":{"mediaType":"application/vnd.cncf.helm.config.v1+json","digest":"sha256:3d3ca122368140982b0a494f4f357fff2fa9894f9adcc8809fa8e74e2a327d94","size":161},"layers":[{"mediaType":"application/vnd.cncf.helm.chart.content.v1.tar+gzip","digest":"sha256:a8b12f90950f22927e8c2e4f3e9b32655ae5287e95ae801662cef7cf66bd9be3","size":8062}],"annotations":{"org.opencontainers.image.created":"2024-10-25T18:43:34+05:30","org.opencontainers.image.description":"A Helm chart for deploying harness-delegate","org.opencontainers.image.title":"production","org.opencontainers.image.version":"1.0.15"}}'
},
status: 'SUCCESS'
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2024 Harness, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react'
import { Layout } from '@harnessio/uicore'
import DeploymentsCard from '@ar/pages/version-details/components/DeploymentsCard/DeploymentsCard'
export default function HelmVersionOverviewCards() {
return (
<Layout.Horizontal width="100%" spacing="medium">
<DeploymentsCard prodCount={10} nonProdCount={12} pipelineName="TestPipeline" executionId="1234566" />
</Layout.Horizontal>
)
}

View File

@ -0,0 +1,172 @@
/*
* Copyright 2024 Harness, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react'
import copy from 'clipboard-copy'
import userEvent from '@testing-library/user-event'
import { getByText, render } from '@testing-library/react'
import { useGetArtifactFilesQuery } from '@harnessio/react-har-service-client'
import { getTableColumn } from '@ar/utils/testUtils/utils'
import ArTestWrapper from '@ar/utils/testUtils/ArTestWrapper'
import VersionDetailsPage from '../../VersionDetailsPage'
import { mockMavenArtifactFiles, mockMavenVersionList, mockMavenVersionSummary } from './__mockData__'
const mockHistoryPush = jest.fn()
// eslint-disable-next-line jest-no-mock
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush
})
}))
jest.mock('clipboard-copy', () => ({
__esModule: true,
default: jest.fn()
}))
jest.mock('@harnessio/react-har-service-client', () => ({
useGetArtifactVersionSummaryQuery: jest.fn().mockImplementation(() => ({
data: { content: mockMavenVersionSummary },
error: null,
isLoading: false,
refetch: jest.fn()
})),
getAllArtifactVersions: jest.fn().mockImplementation(
() =>
new Promise(success => {
success({ content: mockMavenVersionList })
})
),
useGetArtifactFilesQuery: jest.fn().mockImplementation(() => ({
data: { content: mockMavenArtifactFiles },
error: null,
isLoading: false,
refetch: jest.fn()
}))
}))
describe('Verify Maven Artifact Version Artifact Details Tab', () => {
test('verify file list table', async () => {
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
expect(container).toBeInTheDocument()
const getTableRowColumn = (row: number, col: number) => getTableColumn(row, col) as HTMLElement
const data = mockMavenArtifactFiles.files[0]
const row = 1
expect(getTableRowColumn(row, 1)).toHaveTextContent(data.name)
expect(getTableRowColumn(row, 2)).toHaveTextContent(data?.size as string)
const column3Content = getTableRowColumn(row, 3)
data.checksums.forEach(async each => {
const [checksum, value] = each.split(': ')
const btn = getByText(column3Content, `copy ${checksum}`)
await userEvent.click(btn)
expect(copy).toHaveBeenCalledWith(value)
})
const copyColumn = getTableRowColumn(row, 4)
expect(copyColumn).toHaveTextContent('copy')
const copyBtn = copyColumn.querySelector('[data-icon="code-copy"]') as HTMLElement
expect(copyBtn).toBeInTheDocument()
await userEvent.click(copyBtn)
expect(copy).toHaveBeenCalledWith(data?.downloadCommand)
})
test('verify pagination and sorting actions', async () => {
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
const nextPageBtn = getByText(container, 'Next')
await userEvent.click(nextPageBtn)
expect(useGetArtifactFilesQuery).toHaveBeenLastCalledWith({
artifact: '1/+',
queryParams: { page: 0, size: 50, sort_field: 'updatedAt', sort_order: 'DESC' },
registry_ref: 'undefined/1/+',
version: '1'
})
const fileNameSortIcon = getByText(container, 'versionDetails.artifactFiles.table.columns.name').nextSibling
?.firstChild as HTMLElement
await userEvent.click(fileNameSortIcon)
expect(useGetArtifactFilesQuery).toHaveBeenLastCalledWith({
artifact: '1/+',
queryParams: { page: 0, size: 50, sort_field: 'updatedAt', sort_order: 'DESC' },
registry_ref: 'undefined/1/+',
version: '1'
})
})
test('verify error message', async () => {
const mockRefetchFn = jest.fn().mockImplementation(() => undefined)
;(useGetArtifactFilesQuery as jest.Mock).mockImplementationOnce(() => {
return {
data: null,
loading: false,
error: { message: 'error message' },
refetch: mockRefetchFn
}
})
const { container } = render(
<ArTestWrapper
path="/registries/:repositoryIdentifier/artifacts/:artifactIdentifier/versions/:versionIdentifier/:versionTab"
pathParams={{
repositoryIdentifier: '1',
artifactIdentifier: '1',
versionIdentifier: '1',
versionTab: 'artifact_details'
}}>
<VersionDetailsPage />
</ArTestWrapper>
)
const errorText = getByText(container, 'error message')
expect(errorText).toBeInTheDocument()
const retryBtn = getByText(container, 'Retry')
expect(retryBtn).toBeInTheDocument()
await userEvent.click(retryBtn)
expect(mockRefetchFn).toHaveBeenCalled()
})
})

View File

@ -17,6 +17,7 @@
import type {
ArtifactDetailResponseResponse,
ArtifactVersionSummaryResponseResponse,
FileDetailResponseResponse,
ListArtifactVersion,
ListArtifactVersionResponseResponse
} from '@harnessio/react-har-service-client'
@ -121,3 +122,65 @@ export const mockMavenArtifactDetails: ArtifactDetailResponseResponse = {
},
status: 'SUCCESS'
}
export const mockMavenArtifactFiles: FileDetailResponseResponse = {
files: [
{
checksums: [
'SHA-512: 43b206d0651f2748d685c9ed63942091fe529a0c838effeb15b3d21139a5c25f1086bad9e2df57a3032bf1cf26837b7cfe504f7b033d872a6d2d41d311aba882',
'SHA-256: 04cf2f4ad947a81667690d64059ee29d3edc0d74649f82df489565c6cc1edcc0',
'SHA-1: 475741bfe798caedd27a1c2580ea211aeba32521',
'MD5: 5eb4f955706b83204f7d4dbbdecdb0e6'
],
createdAt: '1738316037624',
downloadCommand:
"curl --location 'https://pkg.qa.harness.io/maven/iWnhltqOT7GFt7R-F_zP7Q/maven-up-1/junit/junit/3.8.1/junit-3.8.1.jar.sha1' --header 'x-api-key: \u003cIDENTITY_TOKEN\u003e' -O",
name: 'junit-3.8.1.jar.sha1',
size: '40.00B'
},
{
checksums: [
'SHA-512: cfc89ca8303af5c04c75a73db181b61a34371b9e0dcc59e4d746190ac2e7636f0b257303ebef4db9a2cd980d192ab8879c91d84682d472b03fd3b9a732f184b6',
'SHA-256: ab9b2ba5775492d85d45240f6f12e5880eb0ce26385fd80a1083e3b4ded402c2',
'SHA-1: 11c996e14e70c07f6758f325838ea07e3bdf0742',
'MD5: 4f215459aacbaaac97d02c29c41b2a57'
],
createdAt: '1738316032125',
downloadCommand:
"curl --location 'https://pkg.qa.harness.io/maven/iWnhltqOT7GFt7R-F_zP7Q/maven-up-1/junit/junit/3.8.1/junit-3.8.1.pom.sha1' --header 'x-api-key: \u003cIDENTITY_TOKEN\u003e' -O",
name: 'junit-3.8.1.pom.sha1',
size: '58.00B'
},
{
checksums: [
'SHA-512: 8e6f9fa5eb3ba93a8b1b5a39e01a81c142b33078264dbd0a2030d60dd26735407249a12e66f5cdcab8056e93a5687124fe66e741c233b4c7a06cc8e49f82e98b',
'SHA-256: b58e459509e190bed737f3592bc1950485322846cf10e78ded1d065153012d70',
'SHA-1: 99129f16442844f6a4a11ae22fbbee40b14d774f',
'MD5: 1f40fb782a4f2cf78f161d32670f7a3a'
],
createdAt: '1738152520460',
downloadCommand:
"curl --location 'https://pkg.qa.harness.io/maven/iWnhltqOT7GFt7R-F_zP7Q/maven-up-1/junit/junit/3.8.1/junit-3.8.1.jar' --header 'x-api-key: \u003cIDENTITY_TOKEN\u003e' -O",
name: 'junit-3.8.1.jar',
size: '118.23KB'
},
{
checksums: [
'SHA-512: d43bddd7228b108eab508871d64725a730f6f159b0cee0e25a62df61f5362dc4c3e7c3413b5562b22e20934b40b5d994c1b1f66fec0e1a340613913e05203396',
'SHA-256: e68f33343d832398f3c8aa78afcd808d56b7c1020de4d3ad8ce47909095ee904',
'SHA-1: 16d74791c801c89b0071b1680ea0bc85c93417bb',
'MD5: 50b40cb7342f52b702e6337d5debf1ae'
],
createdAt: '1738152517836',
downloadCommand:
"curl --location 'https://pkg.qa.harness.io/maven/iWnhltqOT7GFt7R-F_zP7Q/maven-up-1/junit/junit/3.8.1/junit-3.8.1.pom' --header 'x-api-key: \u003cIDENTITY_TOKEN\u003e' -O",
name: 'junit-3.8.1.pom',
size: '998.00B'
}
],
itemCount: 4,
pageCount: 1,
pageIndex: 0,
pageSize: 50,
status: 'SUCCESS'
}

View File

@ -39,7 +39,7 @@ import type { DockerVersionDetailsQueryParams } from '../../DockerVersion/types'
import css from './VersionDetailsTab.module.scss'
export default function VersionDetailsTabs(): JSX.Element {
const [tab, setTab] = useState(VersionDetailsTab.OVERVIEW)
const [tab, setTab] = useState('')
const routes = useRoutes()
const history = useHistory()
@ -109,7 +109,11 @@ export default function VersionDetailsTabs(): JSX.Element {
routeDefinitions.toARVersionDetailsTab({ ...versionDetailsTabWithSSCADetailsPathParams }),
routeDefinitions.toARVersionDetailsTab({ ...versionDetailsTabWithPipelineDetailsPathParams })
]}>
<VersionDetailsTabWidget onInit={setTab} packageType={data.packageType as RepositoryPackageType} tab={tab} />
<VersionDetailsTabWidget
onInit={setTab}
packageType={data.packageType as RepositoryPackageType}
tab={tab as VersionDetailsTab}
/>
</RouteProvider>
</Switch>
</>