fix: homepage incorrect data

Signed-off-by: Raul Kele <raulkeleblk@gmail.com>
This commit is contained in:
Raul Kele 2023-03-10 10:28:05 +02:00
parent 60ca6d21d5
commit ecff33fe01
5 changed files with 97 additions and 50 deletions

View File

@ -13,8 +13,9 @@ jest.mock('react-router-dom', () => ({
}));
const mockImageList = {
RepoListWithNewestImage: {
Results: [
GlobalSearch: {
Page: { TotalCount: 6, ItemCount: 3 },
Repos: [
{
Name: 'alpine',
Size: '2806985',
@ -65,28 +66,36 @@ const mockImageList = {
Count: 10
}
}
},
}
]
}
};
const mockImageListRecent = {
GlobalSearch: {
Page: { TotalCount: 6, ItemCount: 2 },
Repos: [
{
Name: 'centos',
Size: '369311301',
LastUpdated: '2022-08-23T00:20:40.144281895Z',
Name: 'alpine',
Size: '2806985',
LastUpdated: '2022-08-09T17:19:53.274069586Z',
NewestImage: {
Tag: 'latest',
Description: '',
IsSigned: true,
Description: 'w',
IsSigned: false,
Licenses: '',
Vendor: '',
Labels: '',
Vulnerabilities: {
MaxSeverity: 'NONE',
Count: 10
MaxSeverity: 'LOW',
Count: 7
}
}
},
{
Name: 'debian',
Size: '369311301',
LastUpdated: '2022-08-23T00:20:40.144281895Z',
Name: 'mongo',
Size: '231383863',
LastUpdated: '2022-08-02T01:30:49.193203152Z',
NewestImage: {
Tag: 'latest',
Description: '',
@ -95,25 +104,8 @@ const mockImageList = {
Vendor: '',
Labels: '',
Vulnerabilities: {
MaxSeverity: 'MEDIUM',
Count: 10
}
}
},
{
Name: 'mysql',
Size: '369311301',
LastUpdated: '2022-08-23T00:20:40.144281895Z',
NewestImage: {
Tag: 'latest',
Description: '',
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: '',
Vulnerabilities: {
MaxSeverity: 'UNKNOWN',
Count: 10
MaxSeverity: 'HIGH',
Count: 2
}
}
}
@ -132,7 +124,8 @@ afterEach(() => {
describe('Home component', () => {
it('fetches image data and renders popular, bookmarks and recently updated', async () => {
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } });
jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockImageList } });
jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockImageListRecent } });
render(<Home />);
await waitFor(() => expect(screen.getAllByText(/alpine/i)).toHaveLength(2));
await waitFor(() => expect(screen.getAllByText(/mongo/i)).toHaveLength(2));
@ -140,14 +133,16 @@ describe('Home component', () => {
});
it('renders signature icons', async () => {
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } });
jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockImageList } });
jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockImageListRecent } });
render(<Home />);
expect(await screen.findAllByTestId('unverified-icon')).toHaveLength(2);
expect(await screen.findAllByTestId('verified-icon')).toHaveLength(3);
});
it('renders vulnerability icons', async () => {
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } });
jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockImageList } });
jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockImageListRecent } });
render(<Home />);
expect(await screen.findAllByTestId('low-vulnerability-icon')).toHaveLength(2);
expect(await screen.findAllByTestId('high-vulnerability-icon')).toHaveLength(2);
@ -158,11 +153,12 @@ describe('Home component', () => {
jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} });
const error = jest.spyOn(console, 'error').mockImplementation(() => {});
render(<Home />);
await waitFor(() => expect(error).toBeCalledTimes(1));
await waitFor(() => expect(error).toBeCalledTimes(2));
});
it('should redirect to explore page when clicking view all popular', async () => {
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } });
jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockImageList } });
jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: mockImageListRecent } });
render(<Home />);
const viewAllButtons = await screen.findAllByText(/view all/i);
expect(viewAllButtons).toHaveLength(2);

View File

@ -99,7 +99,7 @@ function SearchSuggestion({ setSearchCurrentValue = () => {} }) {
const [searchQuery, setSearchQuery] = useState('');
const [suggestionData, setSuggestionData] = useState([]);
const [queryParams] = useSearchParams();
const search = queryParams.get('search');
const search = queryParams.get('search') || '';
const [isLoading, setIsLoading] = useState(false);
const [isFailedSearch, setIsFailedSearch] = useState(false);
const navigate = useNavigate();

View File

@ -8,6 +8,7 @@ import { mapToRepo } from 'utilities/objectModels';
import Loading from '../Shared/Loading';
import { useNavigate, createSearchParams } from 'react-router-dom';
import { sortByCriteria } from 'utilities/sortCriteria';
import { HOME_POPULAR_PAGE_SIZE, HOME_RECENT_PAGE_SIZE } from 'utilities/paginationConstants';
const useStyles = makeStyles(() => ({
gridWrapper: {
@ -60,29 +61,70 @@ const useStyles = makeStyles(() => ({
function Home() {
const [isLoading, setIsLoading] = useState(true);
const [homeData, setHomeData] = useState([]);
const [popularData, setPopularData] = useState([]);
const [recentData, setRecentData] = useState([]);
const navigate = useNavigate();
const abortController = useMemo(() => new AbortController(), []);
const classes = useStyles();
useEffect(() => {
window.scrollTo(0, 0);
const getPopularData = () => {
setIsLoading(true);
api
.get(`${host()}${endpoints.repoList()}`, abortController.signal)
.get(
`${host()}${endpoints.globalSearch({
searchQuery: '',
pageNumber: 1,
pageSize: HOME_POPULAR_PAGE_SIZE,
sortBy: sortByCriteria.downloads?.value
})}`,
abortController.signal
)
.then((response) => {
if (response.data && response.data.data) {
let repoList = response.data.data.RepoListWithNewestImage.Results;
let repoList = response.data.data.GlobalSearch.Repos;
let repoData = repoList.map((responseRepo) => {
return mapToRepo(responseRepo);
});
setHomeData(repoData);
setPopularData(repoData);
setIsLoading(false);
}
})
.catch((e) => {
console.error(e);
});
};
const getRecentData = () => {
setIsLoading(true);
api
.get(
`${host()}${endpoints.globalSearch({
searchQuery: '',
pageNumber: 1,
pageSize: HOME_RECENT_PAGE_SIZE,
sortBy: sortByCriteria.updateTime?.value
})}`,
abortController.signal
)
.then((response) => {
if (response.data && response.data.data) {
let repoList = response.data.data.GlobalSearch.Repos;
let repoData = repoList.map((responseRepo) => {
return mapToRepo(responseRepo);
});
setRecentData(repoData);
setIsLoading(false);
}
})
.catch((e) => {
console.error(e);
});
};
useEffect(() => {
window.scrollTo(0, 0);
getPopularData();
getRecentData();
return () => {
abortController.abort();
};
@ -94,8 +136,8 @@ function Home() {
const renderMostPopular = () => {
return (
homeData &&
homeData.slice(0, 3).map((item, index) => {
popularData &&
popularData.map((item, index) => {
return (
<RepoCard
name={item.name}
@ -120,8 +162,8 @@ function Home() {
const renderRecentlyUpdated = () => {
return (
homeData &&
homeData.slice(0, 2).map((item, index) => {
recentData &&
recentData.map((item, index) => {
return (
<RepoCard
name={item.name}

View File

@ -349,7 +349,7 @@ function TagDetails() {
{/* <BookmarkIcon sx={{color:"#52637A"}}/> */}
</Stack>
<Stack>
<Stack sx={{ width: { xs: '100%', md: 'auto' } }}>
<FormControl sx={{ m: '1', minWidth: '4.6875rem' }} className={classes.sortForm} size="small">
<InputLabel>OS/Arch</InputLabel>
{!isEmpty(selectedManifest) && (

View File

@ -1,6 +1,15 @@
const HEADER_SEARCH_PAGE_SIZE = 9;
const EXPLORE_PAGE_SIZE = 10;
const HOME_PAGE_SIZE = 10;
const HOME_POPULAR_PAGE_SIZE = 3;
const HOME_RECENT_PAGE_SIZE = 2;
const CVE_FIXEDIN_PAGE_SIZE = 5;
export { HEADER_SEARCH_PAGE_SIZE, EXPLORE_PAGE_SIZE, HOME_PAGE_SIZE, CVE_FIXEDIN_PAGE_SIZE };
export {
HEADER_SEARCH_PAGE_SIZE,
EXPLORE_PAGE_SIZE,
HOME_PAGE_SIZE,
CVE_FIXEDIN_PAGE_SIZE,
HOME_POPULAR_PAGE_SIZE,
HOME_RECENT_PAGE_SIZE
};