diff --git a/client/src/components/App/App.tsx b/client/src/components/App/App.tsx index e77059783..4cba8cc75 100644 --- a/client/src/components/App/App.tsx +++ b/client/src/components/App/App.tsx @@ -56,10 +56,6 @@ const App: FC = () => { } }; - if (!testSuites || testSuites.length === 0) { - return <>; - } - return ( { + const testSuitesExist = !!testSuites && testSuites.length > 0; return createBrowserRouter( [ { path: '/', element: ( - + {testSuitesExist ? : } ), }, @@ -22,10 +25,10 @@ export const router = (testSuites: TestSuite[]) => { path: ':test_suite_id', element: , loader: ({ params }) => { - if (testSuites.length === 0) return <>; + if (!testSuitesExist) return ; const suiteId: string = params.test_suite_id || ''; const suite = testSuites.find((suite) => suite.id === suiteId); - return ; + return suite ? : ; }, }, { diff --git a/client/src/components/LandingPage/LandingPage.tsx b/client/src/components/LandingPage/LandingPage.tsx index 3d3435d7b..265611e28 100644 --- a/client/src/components/LandingPage/LandingPage.tsx +++ b/client/src/components/LandingPage/LandingPage.tsx @@ -15,6 +15,7 @@ import infernoLogo from '~/images/inferno_logo.png'; import SelectionPanel from '~/components/_common/SelectionPanel/SelectionPanel'; import lightTheme from '~/styles/theme'; import useStyles from './styles'; +import SelectionSkeleton from '../Skeletons/SelectionSkeletion'; export interface LandingPageProps { testSuites: TestSuite[] | undefined; @@ -128,17 +129,24 @@ const LandingPage: FC = ({ testSuites }) => { py={4} sx={{ backgroundColor: lightTheme.palette.common.grayLightest }} > - - testSuite1.title.localeCompare(testSuite2.title) - )} - setSelection={setSelected} - submitAction={() => - startTestingClick(testSuites?.find((suite: TestSuite) => suite.id === testSuiteChosen)) - } - submitText="Select Suite" - /> + {testSuites ? ( + + testSuite1.title.localeCompare(testSuite2.title) + )} + setSelection={setSelected} + submitAction={() => + startTestingClick( + testSuites?.find((suite: TestSuite) => suite.id === testSuiteChosen) + ) + } + submitText="Select Suite" + /> + ) : ( + + )} ); diff --git a/client/src/components/Skeletons/AppSkeleton.tsx b/client/src/components/Skeletons/AppSkeleton.tsx index 1c853761d..104b7d1f1 100644 --- a/client/src/components/Skeletons/AppSkeleton.tsx +++ b/client/src/components/Skeletons/AppSkeleton.tsx @@ -11,7 +11,7 @@ const AppSkeleton: FC> = () => { const windowIsSmall = useAppStore((state) => state.windowIsSmall); return ( - +
> = () => { return windowIsSmall ? ( <> ) : ( - + diff --git a/client/src/components/Skeletons/FooterSkeleton.tsx b/client/src/components/Skeletons/FooterSkeleton.tsx index bc90e6056..c4b4f67fd 100644 --- a/client/src/components/Skeletons/FooterSkeleton.tsx +++ b/client/src/components/Skeletons/FooterSkeleton.tsx @@ -16,6 +16,7 @@ const FooterSkeleton: FC> = () => { maxHeight: `${footerHeight}px`, backgroundColor: 'white', }} + data-testid="footerSkeleton" > diff --git a/client/src/components/Skeletons/HeaderSkeleton.tsx b/client/src/components/Skeletons/HeaderSkeleton.tsx index 75598cfef..3328c717f 100644 --- a/client/src/components/Skeletons/HeaderSkeleton.tsx +++ b/client/src/components/Skeletons/HeaderSkeleton.tsx @@ -16,6 +16,7 @@ const HeaderSkeleton: FC> = () => { minHeight: `${headerHeight}px`, // For responsive screens maxHeight: `${headerHeight}px`, // For responsive screens }} + data-testid="headerSkeleton" > {/* Home button */} diff --git a/client/src/components/Skeletons/LandingPageSkeleton.tsx b/client/src/components/Skeletons/LandingPageSkeleton.tsx new file mode 100644 index 000000000..1229b2ab9 --- /dev/null +++ b/client/src/components/Skeletons/LandingPageSkeleton.tsx @@ -0,0 +1,65 @@ +import React, { FC } from 'react'; +import { Box, Container, Skeleton } from '@mui/material'; +import { useAppStore } from '~/store/app'; +import SelectionSkeleton from '~/components/Skeletons/SelectionSkeletion'; +import useStyles from '~/components/LandingPage/styles'; +import lightTheme from '~/styles/theme'; + +const LandingPageSkeleton: FC> = () => { + const { classes } = useStyles(); + const windowIsSmall = useAppStore((state) => state.windowIsSmall); + + return ( + + + + + + + + + + + + + + + + ); +}; + +export default LandingPageSkeleton; diff --git a/client/src/components/Skeletons/SelectionSkeletion.tsx b/client/src/components/Skeletons/SelectionSkeletion.tsx new file mode 100644 index 000000000..60d441afe --- /dev/null +++ b/client/src/components/Skeletons/SelectionSkeletion.tsx @@ -0,0 +1,48 @@ +import React, { FC } from 'react'; +import { Box, Paper, Skeleton } from '@mui/material'; +import { useAppStore } from '~/store/app'; +import useStyles from '~/components/_common/SelectionPanel/styles'; + +const SelectionSkeleton: FC> = () => { + const { classes } = useStyles(); + const windowIsSmall = useAppStore((state) => state.windowIsSmall); + const optionCount = 3; + + const optionSkeleton = ( + + ); + + const skeletonList = []; + for (let index = 0; index < optionCount; index++) { + skeletonList.push(
{optionSkeleton}
); + } + + return ( + + + + + + + + {skeletonList} + + + + + + + + ); +}; + +export default SelectionSkeleton; diff --git a/client/src/components/Skeletons/SuiteOptionsPageSkeleton.tsx b/client/src/components/Skeletons/SuiteOptionsPageSkeleton.tsx new file mode 100644 index 000000000..fa2229b16 --- /dev/null +++ b/client/src/components/Skeletons/SuiteOptionsPageSkeleton.tsx @@ -0,0 +1,64 @@ +import React, { FC } from 'react'; +import { Box, Container, Skeleton } from '@mui/material'; +import { useAppStore } from '~/store/app'; +import SelectionSkeleton from '~/components/Skeletons/SelectionSkeletion'; +import useStyles from '~/components/SuiteOptionsPage/styles'; +import lightTheme from '~/styles/theme'; + +const SuiteOptionsPageSkeleton: FC> = () => { + const { classes } = useStyles(); + const windowIsSmall = useAppStore((state) => state.windowIsSmall); + const textLineCount = 10; + + const textLineSkeleton = ( + + ); + + const skeletonList = []; + for (let index = 0; index < textLineCount; index++) { + skeletonList.push(
{textLineSkeleton}
); + } + + return ( + + + + + + + {skeletonList} + + + + + + + + + ); +}; + +export default SuiteOptionsPageSkeleton; diff --git a/client/src/components/Skeletons/TestSessionSkeleton.tsx b/client/src/components/Skeletons/TestSessionSkeleton.tsx index caee8e665..a83cc4ad9 100644 --- a/client/src/components/Skeletons/TestSessionSkeleton.tsx +++ b/client/src/components/Skeletons/TestSessionSkeleton.tsx @@ -34,7 +34,7 @@ const TestSessionSkeleton: FC> = () => { } return ( - + diff --git a/client/src/components/Skeletons/__tests__/Skeletons.test.tsx b/client/src/components/Skeletons/__tests__/Skeletons.test.tsx index f19f38be1..5452dda99 100644 --- a/client/src/components/Skeletons/__tests__/Skeletons.test.tsx +++ b/client/src/components/Skeletons/__tests__/Skeletons.test.tsx @@ -1,12 +1,15 @@ import React from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { SnackbarProvider } from 'notistack'; import ThemeProvider from 'components/ThemeProvider'; import AppSkeleton from 'components/Skeletons/AppSkeleton'; import DrawerSkeleton from 'components/Skeletons/DrawerSkeleton'; import FooterSkeleton from 'components/Skeletons/FooterSkeleton'; import HeaderSkeleton from 'components/Skeletons/HeaderSkeleton'; +import LandingPageSkeleton from 'components/Skeletons/LandingPageSkeleton'; +import SelectionSkeleton from 'components/Skeletons/SelectionSkeletion'; +import SuiteOptionsPageSkeleton from 'components/Skeletons/SuiteOptionsPageSkeleton'; import TestSessionSkeleton from 'components/Skeletons/TestSessionSkeleton'; describe('Skeleton Components', () => { @@ -20,6 +23,39 @@ describe('Skeleton Components', () => { ); + + const skeletonElement = screen.getByTestId('appSkeleton'); + expect(skeletonElement).toBeInTheDocument(); + }); + + it('renders Landing Page Skeleton', () => { + render( + + + + + + + + ); + + const skeletonElement = screen.getByTestId('landingPageSkeleton'); + expect(skeletonElement).toBeInTheDocument(); + }); + + it('renders Suite Options Page Skeleton', () => { + render( + + + + + + + + ); + + const skeletonElement = screen.getByTestId('suiteOptionsPageSkeleton'); + expect(skeletonElement).toBeInTheDocument(); }); it('renders Drawer Skeleton', () => { @@ -32,6 +68,9 @@ describe('Skeleton Components', () => { ); + + const skeletonElement = screen.getByTestId('drawerSkeleton'); + expect(skeletonElement).toBeInTheDocument(); }); it('renders Footer Skeleton', () => { @@ -44,6 +83,9 @@ describe('Skeleton Components', () => { ); + + const skeletonElement = screen.getByTestId('footerSkeleton'); + expect(skeletonElement).toBeInTheDocument(); }); it('renders Header Skeleton', () => { @@ -56,6 +98,9 @@ describe('Skeleton Components', () => { ); + + const skeletonElement = screen.getByTestId('headerSkeleton'); + expect(skeletonElement).toBeInTheDocument(); }); it('renders TestSessionSkeleton Skeleton', () => { @@ -68,5 +113,23 @@ describe('Skeleton Components', () => { ); + + const skeletonElement = screen.getByTestId('testSessionSkeleton'); + expect(skeletonElement).toBeInTheDocument(); + }); + + it('renders Selection Skeleton', () => { + render( + + + + + + + + ); + + const skeletonElement = screen.getByTestId('selectionSkeleton'); + expect(skeletonElement).toBeInTheDocument(); }); }); diff --git a/client/src/components/SuiteOptionsPage/SuiteOptionsPage.tsx b/client/src/components/SuiteOptionsPage/SuiteOptionsPage.tsx index 67564763e..37bdf2daf 100644 --- a/client/src/components/SuiteOptionsPage/SuiteOptionsPage.tsx +++ b/client/src/components/SuiteOptionsPage/SuiteOptionsPage.tsx @@ -16,6 +16,7 @@ import SelectionPanel from '~/components/_common/SelectionPanel/SelectionPanel'; import useStyles from './styles'; import { basePath } from '~/api/infernoApiService'; import remarkGfm from 'remark-gfm'; +import SelectionSkeleton from '~/components/Skeletons/SelectionSkeletion'; export interface SuiteOptionsPageProps { testSuite?: TestSuite; @@ -180,15 +181,19 @@ const SuiteOptionsPage: FC = ({ testSuite }) => { sx={{ backgroundColor: lightTheme.palette.common.grayLightest }} > - createTestSession(selectedSuiteOptions)} - submitText="Start Testing" - /> + {testSuite?.suite_options ? ( + createTestSession(selectedSuiteOptions)} + submitText="Start Testing" + /> + ) : ( + + )}