Skip to content

Commit

Permalink
Frontend unit test expansion (#772)
Browse files Browse the repository at this point in the history
* add shadcn init with config

* implement topnav component with tailwind

* add button component

* move Ht* components to a 'legacyUi' directory

* update primary color

* add dropdown menu

* add Dropdown menu component, implement in top navigation bar, fix private route redirect user to desired URL on successful authentication

* add sheet component

* add separator UI component

* add sheet UI component and modify compose and IDE configs, vitest UI now inlcudes the coverage report (since we're not using it anywhere else)

* convert sidebar sheet to use tailwind and our internal component library

* rename HaztrakSite directory to Site directory

* add RcraProfile unit tests

* add About feature spec file

* add spec file for RegisterHero

* ignore config files in vitest coverage

* add router props to renderWithProvider mock

* add unit test for Private Route

* add unit tests for useAuth hook

* WasteLineTable unit tests

* WasteRowActions test file

* initial manifest details test suite

* ManifestList test suite

* add initial profile test suite

* siteDetails unit tests
  • Loading branch information
dpgraham4401 authored Aug 16, 2024
1 parent 85ec774 commit dbb6697
Show file tree
Hide file tree
Showing 133 changed files with 2,767 additions and 505 deletions.
15 changes: 0 additions & 15 deletions .idea/runConfigurations/Vitest_Coverage.xml

This file was deleted.

2 changes: 1 addition & 1 deletion .idea/runConfigurations/Vitest_UI.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions client/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { ErrorBoundary } from '~/components/Error';
import { Notifications } from '~/components/Notifications/Notifications';
import { HtSpinner } from '~/components/UI';
import { HtSpinner } from 'app/components/legacyUi';
import React, { ReactElement, Suspense } from 'react';
import { Container } from 'react-bootstrap';
import { RouterProvider } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { ErrorBoundary } from '~/components/Error';
import { Notifications } from '~/components/Notifications/Notifications';
import { router } from '~/routes';
import './App.scss';
import './globals.css';

const GlobalSpinner = () => (
<Container fluid className="d-flex justify-content-center align-items-center vh-100">
Expand Down
22 changes: 3 additions & 19 deletions client/app/components/Auth/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { zodResolver } from '@hookform/resolvers/zod';
import React, { useEffect, useState } from 'react';
import { HtForm, HtSpinner } from 'app/components/legacyUi';
import React from 'react';
import { FloatingLabel, Form } from 'react-bootstrap';
import { useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { z } from 'zod';
import { HtForm, HtSpinner } from '~/components/UI';
import { useAuth } from '~/hooks/useAuth/useAuth';

const loginSchema = z.object({
Expand All @@ -16,33 +15,18 @@ type LoginSchema = z.infer<typeof loginSchema>;

export function LoginForm() {
const {
user,
login: { login, isLoading, error },
} = useAuth();
const [loginError, setLoginError] = useState<string | undefined>(undefined);
const navigate = useNavigate();
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<LoginSchema>({ resolver: zodResolver(loginSchema) });

useEffect(() => {
if (user) {
navigate('/');
}
}, [user]);

async function onSubmit({ username, password }: LoginSchema) {
login({ username, password });
}

useEffect(() => {
if (error) {
setLoginError('Error logging in');
}
}, [error]);

return (
<HtForm onSubmit={handleSubmit(onSubmit)}>
<HtForm.Group>
Expand Down Expand Up @@ -71,7 +55,7 @@ export function LoginForm() {
<span>Login </span>
{isLoading && <HtSpinner size="lg" className="text-reset" />}
</button>
{loginError && <div className="alert alert-danger mt-3 mb-0">{loginError}</div>}
{error && <div className="alert alert-danger mt-3 mb-0">{error.message}</div>}
</HtForm>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import { GeneratorStatusAreaChart } from './GeneratorStatusAreaChart';
import { describe, it } from 'vitest';

// This is a awful, dummy test we're using to run out dummy charts
describe('GeneratorStatusAreaChart', () => {
it('renders without crashing', () => {
render(<GeneratorStatusAreaChart />);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import { ManifestCountBarChart } from './ManifestCountBarChart';
import { describe, it } from 'vitest';

// This is a awful, dummy test we're using to run out dummy charts
describe('ManifestCountBarChart', () => {
it('renders without crashing', () => {
render(<ManifestCountBarChart />);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ManifestStatusPieChart } from '~/components/Charts';
import { describe, it } from 'vitest';
import { renderWithProviders } from '~/mocks';

// This is a awful, dummy test we're using to run out dummy charts
describe('ManifestStatusPieChart', () => {
it('renders the pie without crashing', async () => {
renderWithProviders(<ManifestStatusPieChart />);
});
});
2 changes: 1 addition & 1 deletion client/app/components/Help/HaztrakLicense.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HtCard } from 'app/components/legacyUi';
import React from 'react';
import { HtCard } from '~/components/UI';

export function HaztrakLicense() {
return (
Expand Down
30 changes: 10 additions & 20 deletions client/app/components/Layout/Nav/NavItem.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { faArrowUpRightFromSquare } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import colors from 'tailwindcss/colors';
import { NavContext, NavContextProps } from '~/components/Layout/Root';
import { Route } from '~/components/Layout/Sidebar/SidebarRoutes';
import React, { useContext } from 'react';
import { Link } from 'react-router-dom';
import { NavLink } from 'react-bootstrap';
import { LuExternalLink } from 'react-icons/lu';
import { Button } from '~/components/ui';

interface NavItemProps {
route: Route;
Expand All @@ -19,22 +19,12 @@ export function NavItem({ route, targetBlank }: NavItemProps) {
};

return (
<NavLink
className="text-decoration-none text-dark py-2 d-flex align-items-center "
as={Link}
to={route.url}
target={targetBlank ? '_blank' : undefined}
onClick={toggleSidebar}
>
<FontAwesomeIcon icon={route.icon} className="me-2 text-primary ms-2" size="lg" />
<span className=" mb-0">{route.text}</span>
{route.external && (
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="text-danger pb-2 ms-1"
size="xs"
/>
)}
</NavLink>
<Button asChild variant="link">
<Link to={route.url} target={targetBlank ? '_blank' : undefined} onClick={toggleSidebar}>
<route.icon color={colors.cyan[700]} size={24} className="tw-me-3" />
<span className="tw-text-lg tw-text-black">{route.text}</span>
{route.external && <LuExternalLink className="tw-m-2 tw-text-destructive" />}
</Link>
</Button>
);
}
9 changes: 5 additions & 4 deletions client/app/components/Layout/Nav/NavSection.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import { NavItem } from '~/components/Layout/Nav/NavItem';
import { RoutesSection } from '~/components/Layout/Sidebar/SidebarRoutes';
import React from 'react';
import { Separator } from '~/components/ui/Separator/Separator';

interface SidebarSectionProps {
section: RoutesSection;
}

export function NavSection({ section }: SidebarSectionProps) {
return (
<>
<hr className="my-0" />
<p className="text-secondary mt-1 mb-1">{section.name}</p>
<div className="tw-mt-8">
<Separator />
<p className="tw-text-primary">{section.name}</p>
{section.routes.map((route) => {
return (
<div key={route.id}>
<NavItem route={route} />
</div>
);
})}
</>
</div>
);
}
2 changes: 1 addition & 1 deletion client/app/components/Layout/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { HtSpinner } from 'app/components/legacyUi';
import React, { createContext, Dispatch, SetStateAction, Suspense, useState } from 'react';
import { Container } from 'react-bootstrap';
import { Outlet } from 'react-router-dom';
import { ErrorBoundary } from '~/components/Error';
import { HtSpinner } from '~/components/UI';
import { Sidebar } from './Sidebar/Sidebar';
import { TopNav } from './TopNav/TopNav';

Expand Down
57 changes: 26 additions & 31 deletions client/app/components/Layout/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,40 @@ import { NavSection } from '~/components/Layout/Nav/NavSection';
import { NavItem } from '~/components/Layout/Nav/NavItem';
import { NavContext, NavContextProps } from '~/components/Layout/Root';
import React, { ReactElement, useContext } from 'react';
import { Nav, Offcanvas } from 'react-bootstrap';
import { useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { RootState } from '~/store';
import { routes } from './SidebarRoutes';
import { Sheet, SheetContent, SheetHeader, SheetTitle } from '~/components/ui';

/** Vertical sidebar for navigation that disappears when the viewport is small*/
export function Sidebar(): ReactElement | null {
const authUser = useSelector((state: RootState) => state.auth.user);
const { showSidebar, setShowSidebar } = useContext<NavContextProps>(NavContext);

if (!authUser) return null;
return (
<Offcanvas show={showSidebar} onHide={setShowSidebar}>
<Offcanvas.Header closeButton>
<Offcanvas.Title>
<Link to="/" className="navbar-brand ps-1 mb-0">
<img
src={logo}
alt="haztrak logo, hazardous waste tracking made easy."
width={200}
height={'auto'}
/>
</Link>
</Offcanvas.Title>
</Offcanvas.Header>
<Offcanvas.Body>
<nav className="sb-sidenav" id="sidenavAccordion">
<Nav className="flex-column">
{routes.map((route) => {
if (typeof route === 'object' && 'routes' in route) {
return <NavSection key={route.id} section={route} />;
} else if (typeof route === 'object' && 'url' in route) {
return <NavItem key={route.id} route={route} />;
}
})}
</Nav>
<Sheet open={showSidebar} onOpenChange={setShowSidebar}>
<SheetContent side="left">
<SheetHeader>
<SheetTitle asChild>
<Link to="/" className="tw-flex tw-justify-center">
<img
src={logo}
alt="haztrak logo, hazardous waste tracking made easy."
width={200}
height={'auto'}
className=""
/>
</Link>
</SheetTitle>
</SheetHeader>
<nav>
{routes.map((route) => {
if (typeof route === 'object' && 'routes' in route) {
return <NavSection key={route.id} section={route} />;
} else if (typeof route === 'object' && 'url' in route) {
return <NavItem key={route.id} route={route} />;
}
})}
</nav>
</Offcanvas.Body>
</Offcanvas>
</SheetContent>
</Sheet>
);
}
34 changes: 15 additions & 19 deletions client/app/components/Layout/Sidebar/SidebarRoutes.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { faGithub } from '@fortawesome/free-brands-svg-icons';
import {
faCircleQuestion,
faFileLines,
faLocationDot,
faNetworkWired,
faRecycle,
faTachometerAlt,
} from '@fortawesome/free-solid-svg-icons';
import { LuFactory, LuFileCode2, LuHelpCircle } from 'react-icons/lu';
import { IconType } from 'react-icons';
import { TbBinaryTree } from 'react-icons/tb';
import { RiGovernmentFill } from 'react-icons/ri';
import { IoIosDocument } from 'react-icons/io';
import { FaGithub } from 'react-icons/fa';

export interface Route {
id: string;
icon: IconProp;
icon: IconType;
text: string;
url: string;
description?: string;
Expand All @@ -21,14 +17,14 @@ export interface Route {
export interface RoutesSection {
name: string;
id: string;
icon?: IconProp;
icon?: IconType;
routes: Route[];
}

export const routes: (Route | RoutesSection)[] = [
{
id: 'Dashboard',
icon: faTachometerAlt,
icon: TbBinaryTree,
text: 'Dashboard',
url: '/',
},
Expand All @@ -38,13 +34,13 @@ export const routes: (Route | RoutesSection)[] = [
routes: [
{
id: 'mySites',
icon: faLocationDot,
icon: LuFactory,
text: 'My Sites',
url: '/site',
},
{
id: 'rcraInfo',
icon: faRecycle,
icon: RiGovernmentFill,
text: 'RCRAInfo',
url: import.meta.env.DEV ? 'https://rcrainfopreprod.epa.gov' : 'https://rcrainfo.epa.gov',
description: 'RCRAInfo',
Expand All @@ -58,7 +54,7 @@ export const routes: (Route | RoutesSection)[] = [
routes: [
{
id: 'My Manifests',
icon: faFileLines,
icon: IoIosDocument,
text: 'My Manifests',
url: '/manifest',
description: 'All hazardous waste manifest',
Expand All @@ -71,22 +67,22 @@ export const routes: (Route | RoutesSection)[] = [
routes: [
{
id: 'About',
icon: faCircleQuestion,
icon: LuHelpCircle,
text: 'About',
url: '/about',
description: 'About Haztrak',
},
{
id: 'openApi',
icon: faNetworkWired,
icon: LuFileCode2,
text: 'OpenAPI Docs',
url: `${import.meta.env.VITE_HT_API_URL}/api/schema/swagger-ui`,
description: 'API Documentation',
external: true,
},
{
id: 'reportAnIssue',
icon: faGithub,
icon: FaGithub,
text: 'Report an Issue',
url: `${import.meta.env.VITE_GITHUB_URL}/issues`,
description: 'API Documentation',
Expand Down
Loading

0 comments on commit dbb6697

Please sign in to comment.