diff --git a/.github/workflows/end-to-end-test.yml b/.github/workflows/end-to-end-test.yml
index a74408be..0fa65d6c 100644
--- a/.github/workflows/end-to-end-test.yml
+++ b/.github/workflows/end-to-end-test.yml
@@ -81,7 +81,7 @@ jobs:
- name: Install go
uses: actions/setup-go@v3
with:
- go-version: 1.20.x
+ go-version: 1.21.x
- name: Checkout zot repo
uses: actions/checkout@v3
diff --git a/src/__tests__/TagPage/VulnerabilitiesDetails.test.js b/src/__tests__/TagPage/VulnerabilitiesDetails.test.js
index 5c980ca5..7b13ff2d 100644
--- a/src/__tests__/TagPage/VulnerabilitiesDetails.test.js
+++ b/src/__tests__/TagPage/VulnerabilitiesDetails.test.js
@@ -510,23 +510,15 @@ afterEach(() => {
describe('Vulnerabilties page', () => {
it('renders the vulnerabilities if there are any', async () => {
- let getCall = jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockCVEList } });
- for (let i=0; i<21; i++) {
- getCall.mockResolvedValueOnce({ status: 200, data: { data: mockCVEFixed.pageNotFixed } });
- }
- getCall.mockResolvedValue({ status: 200, data: { data: mockCVEList } });
+ jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockCVEList } });
render();
await waitFor(() => expect(screen.getAllByText('Vulnerabilities')).toHaveLength(1));
await waitFor(() => expect(screen.getAllByText('Total 5')).toHaveLength(1));
- await waitFor(() => expect(screen.getAllByText(/Fixed in/)).toHaveLength(20));
+ await waitFor(() => expect(screen.getAllByText(/CVE/)).toHaveLength(20));
});
it('sends filtered query if user types in the search bar', async () => {
- let getCall = jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockCVEList } });
- for (let i=0; i<21; i++) {
- getCall.mockResolvedValueOnce({ status: 200, data: { data: mockCVEFixed.pageNotFixed } });
- }
- getCall.mockResolvedValue({ status: 200, data: { data: mockCVEList } });
+ jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockCVEList } });
render();
const cveSearchInput = screen.getByPlaceholderText(/search/i);
jest.spyOn(api, 'get').mockRejectedValueOnce({ status: 200, data: { data: mockCVEListFiltered } });
@@ -536,11 +528,7 @@ describe('Vulnerabilties page', () => {
});
it('should have a collapsable search bar', async () => {
- let getCall = jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockCVEList } })
- for (let i=0; i<21; i++) {
- getCall.mockResolvedValueOnce({ status: 200, data: { data: mockCVEFixed.pageNotFixed } });
- }
- getCall.mockResolvedValue({ status: 200, data: { data: mockCVEList } });
+ jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockCVEList } });
render();
const cveSearchInput = screen.getByPlaceholderText(/search/i);
const expandSearch = cveSearchInput.parentElement.parentElement.parentElement.parentElement.childNodes[0];
@@ -566,6 +554,8 @@ describe('Vulnerabilties page', () => {
jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockCVEList } })
.mockResolvedValue({ status: 200, data: { data: mockCVEFixed.pageNotFixed } });
render();
+ const expandListBtn = await screen.findAllByTestId('ViewAgendaIcon');
+ fireEvent.click(expandListBtn[0]);
await waitFor(() => expect(screen.getAllByText(/Description/)).toHaveLength(20));
await waitFor(() =>
expect(screen.getAllByText(/CPAN 2.28 allows Signature Verification Bypass./i)).toHaveLength(1)
@@ -587,12 +577,13 @@ describe('Vulnerabilties page', () => {
.mockResolvedValueOnce({ status: 200, data: { data: mockCVEFixed.pageTwo } });
render();
await waitFor(() => expect(screen.getAllByText('Vulnerabilities')).toHaveLength(1));
+ const expandListBtn = await screen.findAllByTestId('KeyboardArrowRightIcon');
+ fireEvent.click(expandListBtn[1]);
await waitFor(() => expect(screen.getByText('1.0.16')).toBeInTheDocument());
- await waitFor(() => expect(screen.getAllByText(/load more/i).length).toBeGreaterThan(0));
- const nrLoadButtons = screen.getAllByText(/load more/i).length
- const loadMoreBtn = screen.getAllByText(/load more/i)[0];
+ await waitFor(() => expect(screen.getAllByText(/Load more/).length).toBe(1));
+ const loadMoreBtn = screen.getAllByText(/Load more/)[0];
await fireEvent.click(loadMoreBtn);
- await waitFor(() => expect(screen.getAllByText(/load more/i).length).toBe(nrLoadButtons-1));
+ await waitFor(() => expect(loadMoreBtn).not.toBeInTheDocument());
expect(await screen.findByText('latest')).toBeInTheDocument();
});
@@ -600,11 +591,7 @@ describe('Vulnerabilties page', () => {
const xlsxMock = jest.createMockFromModule('xlsx');
xlsxMock.writeFile = jest.fn();
- let getCall = jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockCVEList } });
- for (let i=0; i<21; i++) {
- getCall.mockResolvedValueOnce({ status: 200, data: { data: mockCVEFixed.pageNotFixed } });
- }
- getCall.mockResolvedValueOnce({ status: 200, data: { data: mockCVEList } });
+ jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockCVEList } });
render();
await waitFor(() => expect(screen.getAllByText('Vulnerabilities')).toHaveLength(1));
const downloadBtn = await screen.findAllByTestId('DownloadIcon');
@@ -631,13 +618,12 @@ describe('Vulnerabilties page', () => {
getCall.mockResolvedValueOnce({ status: 200, data: { data: mockCVEList } });
render();
await waitFor(() => expect(screen.getAllByText('Vulnerabilities')).toHaveLength(1));
+ const expandListBtn = await screen.findAllByTestId('ViewAgendaIcon');
+ fireEvent.click(expandListBtn[0]);
await waitFor(() => expect(screen.getAllByText('Fixed in')).toHaveLength(20));
const collapseListBtn = await screen.findAllByTestId('ViewHeadlineIcon');
fireEvent.click(collapseListBtn[0]);
expect(await screen.findByText('Fixed in')).not.toBeVisible();
- const expandListBtn = await screen.findAllByTestId('ViewAgendaIcon');
- fireEvent.click(expandListBtn[0]);
- await waitFor(() => expect(screen.getAllByText('Fixed in')).toHaveLength(20));
});
it('should handle fixed CVE query errors', async () => {
@@ -648,6 +634,8 @@ describe('Vulnerabilties page', () => {
render();
await waitFor(() => expect(screen.getAllByText('Vulnerabilities')).toHaveLength(1));
const error = jest.spyOn(console, 'error').mockImplementation(() => {});
+ const expandListBtn = await screen.findAllByTestId('ViewAgendaIcon');
+ fireEvent.click(expandListBtn[0]);
await waitFor(() => expect(screen.getAllByText(/not fixed/i).length).toBeGreaterThan(0));
await waitFor(() => expect(error).toBeCalled());
});
diff --git a/src/components/Shared/VulnerabilityCard.jsx b/src/components/Shared/VulnerabilityCard.jsx
index c201c789..423eed22 100644
--- a/src/components/Shared/VulnerabilityCard.jsx
+++ b/src/components/Shared/VulnerabilityCard.jsx
@@ -123,9 +123,10 @@ function VulnerabilitiyCard(props) {
// pagination props
const [pageNumber, setPageNumber] = useState(1);
const [isEndOfList, setIsEndOfList] = useState(false);
+ const [loadMoreInfo, setLoadMoreInfo] = useState(false);
const getPaginatedResults = () => {
- if (isEndOfList) {
+ if (!openCVE || (!loadMoreInfo && !isEmpty(fixedInfo)) || isEndOfList) {
return;
}
setLoadingFixed(true);
@@ -148,11 +149,13 @@ function VulnerabilitiyCard(props) {
);
}
setLoadingFixed(false);
+ setLoadMoreInfo(false);
})
.catch((e) => {
console.error(e);
setIsEndOfList(true);
setLoadingFixed(false);
+ setLoadMoreInfo(false);
});
};
@@ -161,7 +164,7 @@ function VulnerabilitiyCard(props) {
return () => {
abortController.abort();
};
- }, [pageNumber]);
+ }, [openCVE, pageNumber, loadMoreInfo]);
useEffect(() => {
setOpenCVE(expand);
@@ -169,6 +172,7 @@ function VulnerabilitiyCard(props) {
const loadMore = () => {
if (loadingFixed || isEndOfList) return;
+ setLoadMoreInfo(true);
setPageNumber((pageNumber) => pageNumber + 1);
};
diff --git a/src/components/Tag/Tabs/VulnerabilitiesDetails.jsx b/src/components/Tag/Tabs/VulnerabilitiesDetails.jsx
index 38c1a614..76fb17cd 100644
--- a/src/components/Tag/Tabs/VulnerabilitiesDetails.jsx
+++ b/src/components/Tag/Tabs/VulnerabilitiesDetails.jsx
@@ -165,7 +165,7 @@ function VulnerabilitiesDetails(props) {
const [anchorExport, setAnchorExport] = useState(null);
const openExport = Boolean(anchorExport);
- const [selectedViewMore, setSelectedViewMore] = useState(true);
+ const [selectedViewMore, setSelectedViewMore] = useState(false);
const getCVERequestName = () => {
return digest !== '' ? `${name}@${digest}` : `${name}:${tag}`;