Skip to content

Commit

Permalink
Update test suite to use our new RTK query focused hooks
Browse files Browse the repository at this point in the history
implement basic tagging in RTK query endpoints for caching behavior

replace useHtApi hook usage with RTK query endpoint, remove unused useHtApi
hook

remove old browser setup worker which was not doing anything

reorganize the redux store

remove old profile slice
  • Loading branch information
dpgraham4401 committed Dec 19, 2023
1 parent 0b8bd07 commit 43f6ef4
Show file tree
Hide file tree
Showing 45 changed files with 676 additions and 842 deletions.
9 changes: 7 additions & 2 deletions client/src/components/Auth/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import React, { useEffect, useState } from 'react';
import { FloatingLabel, Form } from 'react-bootstrap';
import { useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { setCredentials, useAppDispatch, useAppSelector, useLoginMutation } from 'store';
import { selectAuthenticated } from 'store/userSlice/user.slice';
import {
selectAuthenticated,
setCredentials,
useAppDispatch,
useAppSelector,
useLoginMutation,
} from 'store';
import { z } from 'zod';

const loginSchema = z.object({
Expand Down
3 changes: 1 addition & 2 deletions client/src/components/Layout/PrivateRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { ReactElement } from 'react';
import { Navigate } from 'react-router-dom';
import { useAppSelector } from 'store';
import { selectAuthenticated } from 'store/userSlice/user.slice';
import { selectAuthenticated, useAppSelector } from 'store';

interface Props {
children: any;
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Layout/TopNav/TopNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, { useContext } from 'react';
import { Button, Dropdown } from 'react-bootstrap';
import { useDispatch, useSelector } from 'react-redux';
import { Link, useNavigate } from 'react-router-dom';
import { logout, selectAuthenticated } from 'store/userSlice/user.slice';
import { removeCredentials, selectAuthenticated } from 'store';

export function TopNav() {
const { showSidebar, setShowSidebar } = useContext<NavContextProps>(NavContext);
Expand All @@ -17,7 +17,7 @@ export function TopNav() {
if (!isAuthenticated) return null;

const handleLogout = () => {
dispatch(logout());
dispatch(removeCredentials());
navigation('/login');
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import '@testing-library/jest-dom';
import { ManifestFABs } from 'components/Manifest/Buttons/ManifestFABs';
import { ManifestFABs } from 'components/Manifest/Actions/ManifestFABs';
import { ManifestContext } from 'components/Manifest/ManifestForm';
import { ManifestStatus } from 'components/Manifest/manifestSchema';
import React from 'react';
import { cleanup, renderWithProviders, screen } from 'test-utils';
import { afterEach, describe, expect, test } from 'vitest';
import { ManifestContext } from 'components/Manifest/ManifestForm';
import { ManifestStatus } from 'components/Manifest/manifestSchema';

const TestComponent = ({
status,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ManifestEditBtn } from 'components/Manifest/Buttons/ManifestEditBtn';
import { ManifestSaveBtn } from 'components/Manifest/Buttons/ManifestSaveBtn';
import { ManifestEditBtn } from 'components/Manifest/Actions/ManifestEditBtn';
import { ManifestSaveBtn } from 'components/Manifest/Actions/ManifestSaveBtn';
import { ManifestContext } from 'components/Manifest/ManifestForm';
import { QuickSignBtn } from 'components/Manifest/QuickerSign';
import { FloatingActionBtn } from 'components/UI';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,51 @@
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
import React from 'react';
import '@testing-library/jest-dom';
import { HandlerSearchForm } from './HandlerSearchForm';
import { HaztrakProfileResponse } from 'store/userSlice/user.slice';
import { cleanup, renderWithProviders, screen } from 'test-utils';
import { afterAll, afterEach, beforeAll, describe, expect, test } from 'vitest';
import { createMockRcrainfoSite } from 'test-utils/fixtures';
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';
import { API_BASE_URL } from 'test-utils/mock/handlers';
import userEvent from '@testing-library/user-event';
import { userApiMocks } from 'test-utils/mock';
import { API_BASE_URL } from 'test-utils/mock/htApiMocks';
import { afterAll, afterEach, beforeAll, describe, expect, test } from 'vitest';
import { HandlerSearchForm } from './HandlerSearchForm';

const mockRcraSite1Id = 'VATEST111111111';
const mockRcraSite2Id = 'VATEST222222222';
const mockRcrainfoSite1Id = 'VATEST333333333';
const mockRcrainfoSite2Id = 'VATEST444444444';

const mockProfile: HaztrakProfileResponse = {
user: 'testuser1',
sites: [],
org: {
name: 'my org',
rcrainfoIntegrated: true,
id: '1234',
},
};

const mockRcrainfoSite1 = createMockRcrainfoSite({ epaSiteId: mockRcrainfoSite1Id });
const mockRcrainfoSite2 = createMockRcrainfoSite({ epaSiteId: mockRcrainfoSite2Id });
const mockRcraSite1 = createMockRcrainfoSite({ epaSiteId: mockRcraSite1Id });
const mockRcraSite2 = createMockRcrainfoSite({ epaSiteId: mockRcraSite2Id });
export const testURL = [
http.get(`${API_BASE_URL}/api/site/search`, (info) => {
export const mockHandlerSearches = [
http.get(`${API_BASE_URL}/api/site/search`, () => {
return HttpResponse.json([mockRcraSite1, mockRcraSite2], { status: 200 });
}),
http.get(`${API_BASE_URL}/api/rcra/handler/search`, (info) => {
http.get(`${API_BASE_URL}/api/rcra/handler/search`, () => {
return HttpResponse.json([mockRcrainfoSite1, mockRcrainfoSite2], { status: 200 });
}),
http.post(`${API_BASE_URL}/api/rcra/handler/search`, (info) => {
http.get(`${API_BASE_URL}/api/user/profile`, () => {
return HttpResponse.json({ ...mockProfile }, { status: 200 });
}),
http.post(`${API_BASE_URL}/api/rcra/handler/search`, () => {
return HttpResponse.json([mockRcrainfoSite1, mockRcrainfoSite2], { status: 200 });
}),
];

const server = setupServer(...testURL);
const server = setupServer(...userApiMocks, ...mockHandlerSearches);
afterEach(() => {
cleanup();
});
Expand All @@ -46,19 +61,7 @@ describe('HandlerSearchForm', () => {
});
test('retrieves rcra sites from haztrak and RCRAInfo', async () => {
renderWithProviders(
<HandlerSearchForm handleClose={() => undefined} handlerType="generator" />,
{
preloadedState: {
profile: {
user: 'testuser1',
org: {
name: 'my org',
rcrainfoIntegrated: true,
id: '1234',
},
},
},
}
<HandlerSearchForm handleClose={() => undefined} handlerType="generator" />
);
const epaId = screen.getByRole('combobox');
await userEvent.type(epaId, 'VATEST');
Expand All @@ -68,20 +71,19 @@ describe('HandlerSearchForm', () => {
expect(await screen.findByText(new RegExp(mockRcrainfoSite2Id, 'i'))).toBeInTheDocument();
});
test('retrieves rcra sites from haztrak if org not rcrainfo integrated', async () => {
renderWithProviders(
<HandlerSearchForm handleClose={() => undefined} handlerType="generator" />,
{
preloadedState: {
profile: {
user: 'testuser1',
org: {
name: 'my org',
rcrainfoIntegrated: false,
id: '1234',
},
server.use(
http.get(`${API_BASE_URL}/api/user/profile`, () => {
return HttpResponse.json(
{
...mockProfile,
org: { rcrainfoIntegrated: false },
},
},
}
{ status: 200 }
);
})
);
renderWithProviders(
<HandlerSearchForm handleClose={() => undefined} handlerType="generator" />
);
const epaId = screen.getByRole('combobox');
await userEvent.type(epaId, 'VATEST');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { RcrainfoSiteSearchBadge } from 'components/Manifest/Handler/Search/RcrainfoSiteSearchBadge';
import { ManifestContext, ManifestContextType } from 'components/Manifest/ManifestForm';
import { Manifest, SiteType, Transporter } from 'components/Manifest/manifestSchema';
import { RcraSite } from 'components/RcraSite';
Expand All @@ -12,13 +13,7 @@ import {
useFormContext,
} from 'react-hook-form';
import Select from 'react-select';
import {
selectHaztrakProfile,
useAppSelector,
useSearchRcrainfoSitesQuery,
useSearchRcraSitesQuery,
} from 'store';
import { RcrainfoSiteSearchBadge } from 'components/Manifest/Handler/Search/RcrainfoSiteSearchBadge';
import { useGetProfileQuery, useSearchRcrainfoSitesQuery, useSearchRcraSitesQuery } from 'store';

interface Props {
handleClose: () => void;
Expand All @@ -42,9 +37,13 @@ export function HandlerSearchForm({
const manifestMethods = useFormContext<Manifest>();
const [inputValue, setInputValue] = useState<string>('');
const [selectedHandler, setSelectedHandler] = useState<RcraSite | null>(null);
const { org } = useAppSelector(selectHaztrakProfile);
const { org } = useGetProfileQuery(undefined, {
selectFromResult: ({ data }) => {
return { org: data?.org };
},
});
const [skip, setSkip] = useState<boolean>(true);
const { data, error, isLoading } = useSearchRcraSitesQuery(
const { data } = useSearchRcraSitesQuery(
{
siteType: handlerType,
siteId: inputValue,
Expand Down
34 changes: 26 additions & 8 deletions client/src/components/Manifest/ManifestForm.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import { ErrorMessage } from '@hookform/error-message';
import { zodResolver } from '@hookform/resolvers/zod';
import { createSelector } from '@reduxjs/toolkit';
import { ManifestCancelBtn } from 'components/Manifest/Actions/ManifestCancelBtn';
import { ManifestEditBtn } from 'components/Manifest/Actions/ManifestEditBtn';
import { ManifestFABs } from 'components/Manifest/Actions/ManifestFABs';
import { ManifestSaveBtn } from 'components/Manifest/Actions/ManifestSaveBtn';
import { AdditionalInfoForm } from 'components/Manifest/AdditionalInfo';
import { ManifestCancelBtn } from 'components/Manifest/Buttons/ManifestCancelBtn';
import { ManifestEditBtn } from 'components/Manifest/Buttons/ManifestEditBtn';
import { ManifestFABs } from 'components/Manifest/Buttons/ManifestFABs';
import { ManifestSaveBtn } from 'components/Manifest/Buttons/ManifestSaveBtn';
import { UpdateRcra } from 'components/Manifest/UpdateRcra/UpdateRcra';
import { WasteLine } from 'components/Manifest/WasteLine/wasteLineSchema';
import { RcraSiteDetails } from 'components/RcraSite';
import { HtButton, HtCard, HtForm, InfoIconTooltip } from 'components/UI';
import React, { createContext, useEffect, useState } from 'react';
import React, { createContext, useEffect, useMemo, useState } from 'react';
import { Alert, Button, Col, Container, Form, Row, Stack } from 'react-bootstrap';
import { FormProvider, SubmitHandler, useFieldArray, useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify';
import { manifest } from 'services';
import {
selectHaztrakSiteEpaIds,
useAppSelector,
ProfileSlice,
useCreateManifestMutation,
useGetProfileQuery,
useSaveEManifestMutation,
useUpdateManifestMutation,
} from 'store';
Expand Down Expand Up @@ -239,8 +240,25 @@ export function ManifestForm({
manifestData?.status
);

const selectUserSiteIds = useMemo(
() =>
createSelector(
(res) => res.data,
(data: ProfileSlice) =>
!data ?? !data.sites
? []
: Object.values(data.sites).map((site) => site.handler.epaSiteId)
),
[]
);

const nextSigner = manifest.getNextSigner(manifestData);
const userSiteIds = useAppSelector(selectHaztrakSiteEpaIds);
const { userSiteIds } = useGetProfileQuery(undefined, {
selectFromResult: (result) => ({
...result,
userSiteIds: selectUserSiteIds(result),
}),
});
// Whether the user has permissions and manifest is in a state to be signed
const signAble = userSiteIds.includes(nextSigner?.epaSiteId ?? '');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,31 @@ import '@testing-library/jest-dom';
import { ManifestContext } from 'components/Manifest/ManifestForm';
import { Handler, RcraSiteType } from 'components/Manifest/manifestSchema';
import { QuickSignBtn } from 'components/Manifest/QuickerSign/index';
import { setupServer } from 'msw/node';
import React from 'react';
import { HaztrakProfileResponse } from 'store/userSlice/user.slice';
import { cleanup, renderWithProviders, screen } from 'test-utils';
import { createMockMTNHandler } from 'test-utils/fixtures';
import { afterEach, describe, expect, test } from 'vitest';
import { userApiMocks } from 'test-utils/mock';
import { afterAll, afterEach, beforeAll, describe, expect, test } from 'vitest';
import { undefined } from 'zod';

const mockProfile: HaztrakProfileResponse = {
user: 'testuser1',
sites: [],
org: {
name: 'my org',
rcrainfoIntegrated: true,
id: '1234',
},
};

const server = setupServer(...userApiMocks);
afterEach(() => {
cleanup();
});
beforeAll(() => server.listen());
afterAll(() => server.close()); // Disable API mocking after the tests are done.
afterEach(() => {
cleanup();
});
Expand Down Expand Up @@ -40,60 +59,12 @@ function TestComponent({
}

describe('QuickSignBtn', () => {
test('renders', () => {
const handlerId = 'TXD987654321';
const handler = createMockMTNHandler({ siteType: 'Generator', epaSiteId: handlerId });
renderWithProviders(
<TestComponent
handler={handler}
signingSite={{ epaSiteId: handlerId, siteType: 'generator' }}
status={'Scheduled'}
/>,
{
preloadedState: {
profile: {
user: 'testuser1',
org: {
rcrainfoIntegrated: true,
id: '123',
name: 'Test Org',
},
sites: {
TXD987654321: {
name: 'Test Site',
handler: handler,
permissions: { eManifest: 'signer' },
},
},
},
},
}
);
expect(screen.getByRole('button')).toBeInTheDocument();
});
test('is not disabled when user org is rcrainfo integrated', () => {
const unsigned_handler = createMockMTNHandler({
signed: false,
electronicSignaturesInfo: [],
});
renderWithProviders(<TestComponent siteType={'Generator'} handler={unsigned_handler} />, {
// Redux store state with an API user is required for this button to be active
preloadedState: {
profile: {
org: {
name: 'Test Org',
id: '123',
rcrainfoIntegrated: true,
},
user: 'username',
rcrainfoProfile: {
user: 'username',
phoneNumber: '1231231234',
apiUser: true,
},
},
},
});
renderWithProviders(<TestComponent siteType={'Generator'} handler={unsigned_handler} />);
expect(screen.queryByRole('button')).not.toBeInTheDocument();
});
test('is disabled when API user but already signed', () => {
Expand All @@ -108,20 +79,7 @@ describe('QuickSignBtn', () => {
siteType={'Tsdf'}
signingSite={{ epaSiteId: 'other_site', siteType: 'transporter' }}
handler={unsigned_handler}
/>,
// Redux store state with an API user is required for this button to be active
{
preloadedState: {
profile: {
user: 'username',
rcrainfoProfile: {
user: 'username',
phoneNumber: '1231231234',
apiUser: false,
},
},
},
}
/>
);
expect(screen.queryByRole('button')).not.toBeInTheDocument();
});
Expand Down
Loading

0 comments on commit 43f6ef4

Please sign in to comment.