Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Zustandification™️ #11527

Merged
merged 6 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions services/ui-src/src/components/app/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import { act } from "react-dom/test-utils";
import { axe } from "jest-axe";
// utils
import {
mockStateUser,
mockNoUser,
mockNoUserStore,
RouterWrappedComponent,
mockUseStore,
} from "utils/testing/setupJest";
import { useUser, UserProvider } from "utils";
import { UserProvider, useStore } from "utils";
//components
import { App } from "components";

jest.mock("utils/auth/useUser");
const mockedUseUser = useUser as jest.MockedFunction<typeof useUser>;
jest.mock("utils/state/useStore");
const mockedUseStore = useStore as jest.MockedFunction<typeof useStore>;
mockedUseStore.mockReturnValue(mockUseStore);

const appComponent = (
<RouterWrappedComponent>
Expand All @@ -24,15 +25,14 @@ const appComponent = (

describe("Test App", () => {
test("App is visible", async () => {
mockedUseUser.mockReturnValue(mockStateUser);
await act(async () => {
await render(appComponent);
});
expect(screen.getByTestId("app-container")).toBeVisible();
});

test("App renders local logins if there is no user", async () => {
mockedUseUser.mockReturnValue(mockNoUser);
mockedUseStore.mockReturnValue(mockNoUserStore);
await act(async () => {
await render(appComponent);
});
Expand Down
12 changes: 9 additions & 3 deletions services/ui-src/src/components/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useContext, useEffect } from "react";
import { useLocation, Route, Routes } from "react-router-dom";
import { ErrorBoundary } from "react-error-boundary";
// components
Expand All @@ -21,12 +21,18 @@ import {
fireTealiumPageView,
isApparentReportPage,
makeMediaQueryClasses,
useUser,
UserContext,
useStore,
} from "utils";

export const App = () => {
const mqClasses = makeMediaQueryClasses();
const { logout, user, showLocalLogins } = useUser();

// state management
const context = useContext(UserContext);
const { logout } = context;
const { user, showLocalLogins } = useStore();

const { pathname, key } = useLocation();
const isExportPage = pathname.includes("/export");

Expand Down
43 changes: 31 additions & 12 deletions services/ui-src/src/components/app/AppRoutes.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@ import { createMemoryHistory } from "history";
// components
import { AppRoutes } from "components";
// utils
import { useUser, UserProvider } from "utils";
import { UserProvider, useStore } from "utils";
import {
mockAdminUser,
mockAdminUserStore,
mockBannerStore,
mockLDFlags,
mockStateUser,
mockStateUserNoReports,
mockStateUserStore,
mockStateUserStoreNoReports,
} from "utils/testing/setupJest";
// verbiage
import notFoundVerbiage from "verbiage/pages/not-found";

jest.mock("utils/auth/useUser");
const mockedUseUser = useUser as jest.MockedFunction<typeof useUser>;
jest.mock("utils/state/useStore");
const mockedUseStore = useStore as jest.MockedFunction<typeof useStore>;

mockLDFlags.setDefault({ mlrReport: true });

Expand All @@ -34,7 +35,10 @@ const tempScroll = window.HTMLElement.prototype.scrollIntoView;
describe("Test AppRoutes for admin-specific routes", () => {
beforeEach(async () => {
window.HTMLElement.prototype.scrollIntoView = function () {};
mockedUseUser.mockReturnValue(mockAdminUser);
mockedUseStore.mockReturnValue({
...mockAdminUserStore,
...mockBannerStore,
});
history = createMemoryHistory();
history.push("/admin");
await act(async () => {
Expand All @@ -52,7 +56,10 @@ describe("Test AppRoutes for admin-specific routes", () => {

describe("Test AppRoutes for non-admin-specific routes", () => {
beforeEach(async () => {
mockedUseUser.mockReturnValue(mockStateUser);
mockedUseStore.mockReturnValue({
...mockStateUserStore,
...mockBannerStore,
});
history = createMemoryHistory();
history.push("/admin");
await act(async () => {
Expand All @@ -68,7 +75,10 @@ describe("Test AppRoutes for non-admin-specific routes", () => {

describe("Test AppRoutes for non-admin-specific routes", () => {
beforeEach(async () => {
mockedUseUser.mockReturnValue(mockStateUser);
mockedUseStore.mockReturnValue({
...mockStateUserStore,
...mockBannerStore,
});
history = createMemoryHistory();
history.push("/admin");
await act(async () => {
Expand All @@ -84,7 +94,10 @@ describe("Test AppRoutes for non-admin-specific routes", () => {

describe("Test AppRoutes 404 handling", () => {
beforeEach(async () => {
mockedUseUser.mockReturnValue(mockStateUser);
mockedUseStore.mockReturnValue({
...mockStateUserStore,
...mockBannerStore,
});
history = createMemoryHistory();
history.push("/obviously-fake-route");
await act(async () => {
Expand All @@ -100,7 +113,10 @@ describe("Test AppRoutes 404 handling", () => {
describe("Test AppRoutes for MCPAR report-specific routes", () => {
beforeEach(async () => {
window.HTMLElement.prototype.scrollIntoView = function () {};
mockedUseUser.mockReturnValue(mockStateUser);
mockedUseStore.mockReturnValue({
...mockStateUserStore,
...mockBannerStore,
});
history = createMemoryHistory();
history.push("/mcpar");
await act(async () => {
Expand All @@ -119,7 +135,10 @@ describe("Test AppRoutes for MCPAR report-specific routes", () => {
describe("Test AppRoutes for state users without report-specific access", () => {
beforeEach(async () => {
window.HTMLElement.prototype.scrollIntoView = function () {};
mockedUseUser.mockReturnValue(mockStateUserNoReports);
mockedUseStore.mockReturnValue({
...mockStateUserStoreNoReports,
...mockBannerStore,
});
history = createMemoryHistory();
history.push("/mlr");
await act(async () => {
Expand Down
9 changes: 6 additions & 3 deletions services/ui-src/src/components/app/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ import {
} from "components";
// utils
import { ReportRoute, ReportType } from "types";
import { ScrollToTopComponent, useUser } from "utils";
import { ScrollToTopComponent, useStore } from "utils";
import { Fragment, useContext } from "react";
import { Flex, Spinner } from "@chakra-ui/react";

export const AppRoutes = () => {
const { userIsAdmin, userReports } = useUser().user ?? {};
const mlrReport = useFlags()?.mlrReport;
const { userIsAdmin, userReports } = useStore().user ?? {};
const { report, contextIsLoaded } = useContext(ReportContext);

// LaunchDarkly
const mlrReport = useFlags()?.mlrReport;

// determine if the user has access to specific reports
const userReportAccess = {
MCPAR: userReports?.includes("MCPAR") || userIsAdmin,
Expand Down
14 changes: 7 additions & 7 deletions services/ui-src/src/components/cards/TemplateCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { TemplateCard } from "components";
// utils
import {
mockLDFlags,
mockStateUser,
mockStateUserNoReports,
mockStateUserStore,
mockStateUserStoreNoReports,
RouterWrappedComponent,
} from "utils/testing/setupJest";
import { useUser } from "utils";
import { useStore } from "utils";
// verbiage
import verbiage from "verbiage/pages/home";

Expand All @@ -23,8 +23,8 @@ jest.mock("utils/other/useBreakpoint", () => ({
})),
}));

jest.mock("utils/auth/useUser");
const mockedUseUser = useUser as jest.MockedFunction<typeof useUser>;
jest.mock("utils/state/useStore");
const mockedUseStore = useStore as jest.MockedFunction<typeof useStore>;

const mockUseNavigate = jest.fn();

Expand Down Expand Up @@ -79,15 +79,15 @@ describe("Test MCPAR TemplateCard", () => {
});

test("MCPAR TemplateCard navigates to next route on link click", async () => {
mockedUseUser.mockReturnValue(mockStateUser);
mockedUseStore.mockReturnValue(mockStateUserStore);
const templateCardLink = screen.getByText(mcparTemplateVerbiage.link.text)!;
await userEvent.click(templateCardLink);
const expectedRoute = mcparTemplateVerbiage.link.route;
await expect(mockUseNavigate).toHaveBeenCalledWith(expectedRoute);
});

test("'Enter MCPAR' button is disabled for user with no access to this report", async () => {
mockedUseUser.mockReturnValue(mockStateUserNoReports);
mockedUseStore.mockReturnValue(mockStateUserStoreNoReports);
const templateCardLink = screen.getByText(mcparTemplateVerbiage.link.text)!;
expect(templateCardLink).toBeDisabled;
});
Expand Down
20 changes: 10 additions & 10 deletions services/ui-src/src/components/drawers/ReportDrawer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { axe } from "jest-axe";
//components
import { ReportDrawer } from "components";
import {
mockAdminUser,
mockAdminUserStore,
mockCompletedQualityMeasuresEntity,
mockDrawerForm,
mockEmptyDrawerForm,
mockModalDrawerReportPageVerbiage,
mockStateUser,
mockStateUserStore,
RouterWrappedComponent,
} from "utils/testing/setupJest";
// utils
import { useUser } from "utils";
import { useStore } from "utils";
// constants
import { closeText, saveAndCloseText } from "../../constants";

Expand All @@ -25,8 +25,8 @@ const mockDrawerDisclosure = {
onClose: mockOnClose,
};

jest.mock("utils/auth/useUser");
const mockedUseUser = useUser as jest.MockedFunction<typeof useUser>;
jest.mock("utils/state/useStore");
const mockedUseStore = useStore as jest.MockedFunction<typeof useStore>;

const drawerComponent = (
<RouterWrappedComponent>
Expand All @@ -45,13 +45,13 @@ describe("Test ReportDrawer rendering", () => {
jest.clearAllMocks();
});
it("Should render save text for state user", async () => {
mockedUseUser.mockReturnValue(mockStateUser);
mockedUseStore.mockReturnValue(mockStateUserStore);
render(drawerComponent);
expect(screen.getByText(saveAndCloseText)).toBeVisible();
});

it("Should not render save text for admin user", async () => {
mockedUseUser.mockReturnValue(mockAdminUser);
mockedUseStore.mockReturnValue(mockAdminUserStore);
render(drawerComponent);
expect(screen.queryByText(saveAndCloseText)).not.toBeInTheDocument();
});
Expand All @@ -72,7 +72,7 @@ describe("Test ReportDrawerWithoutFormFields rendering", () => {
jest.clearAllMocks();
});
it("Should render save text for state user", async () => {
mockedUseUser.mockReturnValue(mockStateUser);
mockedUseStore.mockReturnValue(mockStateUserStore);
render(drawerComponentWithoutFormFields);
expect(
screen.getByText(mockModalDrawerReportPageVerbiage.drawerNoFormMessage)
Expand All @@ -82,7 +82,7 @@ describe("Test ReportDrawerWithoutFormFields rendering", () => {

describe("Test ReportDrawer fill form and close", () => {
beforeEach(() => {
mockedUseUser.mockReturnValue(mockStateUser);
mockedUseStore.mockReturnValue(mockStateUserStore);
render(drawerComponent);
});
afterEach(() => {
Expand Down Expand Up @@ -116,7 +116,7 @@ describe("Test ReportDrawer fill form and close", () => {

describe("Test ReportDrawer accessibility", () => {
it("Should not have basic accessibility issues", async () => {
mockedUseUser.mockReturnValue(mockStateUser);
mockedUseStore.mockReturnValue(mockStateUserStore);
const { container } = render(drawerComponent);
const results = await axe(container);
expect(results).toHaveNoViolations();
Expand Down
4 changes: 2 additions & 2 deletions services/ui-src/src/components/drawers/ReportDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { MouseEventHandler } from "react";
import { Box, Button, Flex, Text, Spinner } from "@chakra-ui/react";
import { Drawer, Form } from "components";
// utils
import { useUser } from "utils";
import { useStore } from "utils";
// types
import {
AnyObject,
Expand All @@ -27,7 +27,7 @@ export const ReportDrawer = ({
...props
}: Props) => {
// determine if fields should be disabled (based on admin and read-only roles)
const { userIsAdmin, userIsReadOnly } = useUser().user ?? {};
const { userIsAdmin, userIsReadOnly } = useStore().user ?? {};
const buttonText =
userIsAdmin || userIsReadOnly ? closeText : saveAndCloseText;
const formFieldsExist = form.fields.length;
Expand Down
4 changes: 2 additions & 2 deletions services/ui-src/src/components/fields/ChoiceListField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
getAutosaveFields,
labelTextWithOptional,
parseCustomHtml,
useUser,
useStore,
} from "utils";
import {
AnyObject,
Expand Down Expand Up @@ -45,7 +45,7 @@ export const ChoiceListField = ({
const { entities, entityType, updateEntities, selectedEntity } =
useContext(EntityContext);
const { full_name, state, userIsAdmin, userIsReadOnly } =
useUser().user ?? {};
useStore().user ?? {};
// get form context and register field
const form = useFormContext();
const fieldIsRegistered = name in form.getValues();
Expand Down
Loading
Loading