Skip to content

Commit

Permalink
Add TestSetupProvider for mocking SetupProvider more effectively
Browse files Browse the repository at this point in the history
  • Loading branch information
canac committed Sep 9, 2024
1 parent 6ee2a61 commit 7589602
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 93 deletions.
24 changes: 11 additions & 13 deletions src/components/Layouts/Primary/LogoLink/LogoLink.test.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import { render } from '@testing-library/react';
import { useSetupContext } from 'src/components/Setup/SetupProvider';
import { TestSetupProvider } from 'src/components/Setup/SetupProvider';
import { LogoLink } from './LogoLink';

jest.mock('src/components/Setup/SetupProvider');

describe('LogoLink', () => {
it('renders a link when not on the setup tour', () => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: false,
});

const { getByRole } = render(<LogoLink />);
const { getByRole } = render(
<TestSetupProvider>
<LogoLink />
</TestSetupProvider>,
);
expect(getByRole('link')).toBeInTheDocument();
});

it('does not render a link when on the setup tour', () => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: true,
});

const { queryByRole } = render(<LogoLink />);
const { queryByRole } = render(
<TestSetupProvider onSetupTour>
<LogoLink />
</TestSetupProvider>,
);
expect(queryByRole('link')).not.toBeInTheDocument();
});
});
22 changes: 7 additions & 15 deletions src/components/Layouts/Primary/NavBar/NavBar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ import { MockedProvider } from '@apollo/client/testing';
import { ThemeProvider } from '@mui/material/styles';
import { render } from '@testing-library/react';
import TestRouter from '__tests__/util/TestRouter';
import { useSetupContext } from 'src/components/Setup/SetupProvider';
import { TestSetupProvider } from 'src/components/Setup/SetupProvider';
import theme from 'src/theme';
import { getTopBarMultipleMock } from '../TopBar/TopBar.mock';
import { NavBar } from './NavBar';

jest.mock('src/components/Setup/SetupProvider');

const router = {
query: { accountListId: 'abc' },
isReady: true,
Expand All @@ -18,15 +16,19 @@ const router = {

interface TestComponentProps {
openMobile?: boolean;
onSetupTour?: boolean;
}

const TestComponent: React.FC<TestComponentProps> = ({
openMobile = false,
onSetupTour,
}) => (
<ThemeProvider theme={theme}>
<TestRouter router={router}>
<MockedProvider mocks={mocks} addTypename={false}>
<NavBar onMobileClose={onMobileClose} openMobile={openMobile} />
<TestSetupProvider onSetupTour={onSetupTour}>
<NavBar onMobileClose={onMobileClose} openMobile={openMobile} />
</TestSetupProvider>
</MockedProvider>
</TestRouter>
</ThemeProvider>
Expand All @@ -36,12 +38,6 @@ const onMobileClose = jest.fn();
const mocks = [getTopBarMultipleMock()];

describe('NavBar', () => {
beforeEach(() => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: false,
});
});

it('default', () => {
const { queryByTestId } = render(<TestComponent />);

Expand All @@ -60,11 +56,7 @@ describe('NavBar', () => {
});

it('hides links during the setup tour', () => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: true,
});

const { queryByRole } = render(<TestComponent openMobile />);
const { queryByRole } = render(<TestComponent openMobile onSetupTour />);

expect(
queryByRole('button', { name: 'Dashboard' }),
Expand Down
24 changes: 10 additions & 14 deletions src/components/Layouts/Primary/NavBar/NavTools/NavTools.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,35 @@ import { MockedProvider } from '@apollo/client/testing';
import { ThemeProvider } from '@mui/material/styles';
import { render, waitFor } from '@testing-library/react';
import TestRouter from '__tests__/util/TestRouter';
import { useSetupContext } from 'src/components/Setup/SetupProvider';
import { TestSetupProvider } from 'src/components/Setup/SetupProvider';
import theme from 'src/theme';
import { getTopBarMultipleMock } from '../../TopBar/TopBar.mock';
import { NavTools } from './NavTools';

jest.mock('src/components/Setup/SetupProvider');

const router = {
query: { accountListId: 'abc' },
isReady: true,
push: jest.fn(),
};

const TestComponent = () => (
interface TestComponentProps {
onSetupTour?: boolean;
}

const TestComponent: React.FC<TestComponentProps> = ({ onSetupTour }) => (
<ThemeProvider theme={theme}>
<TestRouter router={router}>
<MockedProvider mocks={[getTopBarMultipleMock()]} addTypename={false}>
<NavTools />
<TestSetupProvider onSetupTour={onSetupTour}>
<NavTools />
</TestSetupProvider>
</MockedProvider>
</TestRouter>
</ThemeProvider>
);

describe('NavTools', () => {
it('default', async () => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: false,
});

const { findByText, getByTestId, getByText } = render(<TestComponent />);

expect(getByTestId('NavTools')).toBeInTheDocument();
Expand All @@ -40,11 +40,7 @@ describe('NavTools', () => {
});

it('hides links during the setup tour', async () => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: true,
});

const { queryByText, getByTestId } = render(<TestComponent />);
const { queryByText, getByTestId } = render(<TestComponent onSetupTour />);

expect(getByTestId('NavTools')).toBeInTheDocument();
expect(queryByText('Add')).not.toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,34 @@ import userEvent from '@testing-library/user-event';
import { signOut } from 'next-auth/react';
import TestRouter from '__tests__/util/TestRouter';
import TestWrapper from '__tests__/util/TestWrapper';
import { useSetupContext } from 'src/components/Setup/SetupProvider';
import { TestSetupProvider } from 'src/components/Setup/SetupProvider';
import theme from '../../../../../../theme';
import { getTopBarMock } from '../../../TopBar/TopBar.mock';
import { ProfileMenuPanel } from './ProfileMenuPanel';

jest.mock('src/components/Setup/SetupProvider');

const router = {
pathname: '/accountLists/[accountListId]/test',
query: { accountListId: '1' },
push: jest.fn(),
};

const TestComponent = () => (
interface TestComponentProps {
onSetupTour?: boolean;
}

const TestComponent: React.FC<TestComponentProps> = ({ onSetupTour }) => (
<ThemeProvider theme={theme}>
<TestWrapper mocks={[getTopBarMock()]}>
<TestRouter router={router}>
<ProfileMenuPanel />
<TestSetupProvider onSetupTour={onSetupTour}>
<ProfileMenuPanel />
</TestSetupProvider>
</TestRouter>
</TestWrapper>
</ThemeProvider>
);

describe('ProfileMenuPanelForNavBar', () => {
beforeEach(() => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: false,
});
});

it('default', () => {
const { getByTestId } = render(<TestComponent />);

Expand Down Expand Up @@ -86,12 +84,8 @@ describe('ProfileMenuPanelForNavBar', () => {
});

it('hides links during the setup tour', async () => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: true,
});

const { findByTestId, getByRole, getByTestId, queryByText } = render(
<TestComponent />,
<TestComponent onSetupTour />,
);

userEvent.click(await findByTestId('accountListSelectorButton'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@ import { session } from '__tests__/fixtures/session';
import TestRouter from '__tests__/util/TestRouter';
import TestWrapper from '__tests__/util/TestWrapper';
import { render, waitFor } from '__tests__/util/testingLibraryReactMock';
import { useSetupContext } from 'src/components/Setup/SetupProvider';
import { TestSetupProvider } from 'src/components/Setup/SetupProvider';
import theme from '../../../../../../theme';
import {
getTopBarMock,
getTopBarMockWithMultipleAccountLists,
} from '../../TopBar.mock';
import ProfileMenu from './ProfileMenu';

jest.mock('src/components/Setup/SetupProvider');

const mockEnqueue = jest.fn();

jest.mock('notistack', () => ({
Expand Down Expand Up @@ -48,25 +46,26 @@ const routerNoAccountListId = {
interface TestComponentProps {
router?: Partial<NextRouter>;
mocks?: MockedResponse[];
onSetupTour?: boolean;
}

const TestComponent: React.FC<TestComponentProps> = ({ router, mocks }) => (
const TestComponent: React.FC<TestComponentProps> = ({
router,
mocks,
onSetupTour,
}) => (
<ThemeProvider theme={theme}>
<TestWrapper mocks={mocks ?? [getTopBarMock()]}>
<TestRouter router={router ?? defaultRouter}>
<ProfileMenu />
<TestSetupProvider onSetupTour={onSetupTour}>
<ProfileMenu />
</TestSetupProvider>
</TestRouter>
</TestWrapper>
</ThemeProvider>
);

describe('ProfileMenu', () => {
beforeEach(() => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: false,
});
});

it('default', async () => {
const { getByTestId, getByRole, getByText, findByText } = render(
<TestComponent />,
Expand Down Expand Up @@ -175,12 +174,8 @@ describe('ProfileMenu', () => {
});

it('hides links during the setup tour', async () => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: true,
});

const { findByText, getByRole, getByTestId, queryByText } = render(
<TestComponent router={routerNoAccountListId} />,
<TestComponent router={routerNoAccountListId} onSetupTour />,
);

expect(await findByText('John Smith')).toBeInTheDocument();
Expand Down
30 changes: 13 additions & 17 deletions src/components/Layouts/Primary/TopBar/TopBar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import { ThemeProvider } from '@mui/material/styles';
import { render } from '@testing-library/react';
import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { useSetupContext } from 'src/components/Setup/SetupProvider';
import { TestSetupProvider } from 'src/components/Setup/SetupProvider';
import theme from '../../../../theme';
import { getNotificationsMocks } from './Items/NotificationMenu/NotificationMenu.mock';
import TopBar from './TopBar';
import { getTopBarMultipleMock } from './TopBar.mock';

jest.mock('src/components/Setup/SetupProvider');

const accountListId = 'accountListId';
const onMobileNavOpen = jest.fn();

Expand All @@ -33,18 +31,24 @@ jest.mock('notistack', () => ({
},
}));

const TestComponent = () => (
interface TestComponentProps {
onSetupTour?: boolean;
}

const TestComponent: React.FC<TestComponentProps> = ({ onSetupTour }) => (
<SnackbarProvider>
<ThemeProvider theme={theme}>
<TestRouter router={router}>
<MockedProvider
mocks={[getTopBarMultipleMock(), ...getNotificationsMocks()]}
addTypename={false}
>
<TopBar
accountListId={accountListId}
onMobileNavOpen={onMobileNavOpen}
/>
<TestSetupProvider onSetupTour={onSetupTour}>
<TopBar
accountListId={accountListId}
onMobileNavOpen={onMobileNavOpen}
/>
</TestSetupProvider>
</MockedProvider>
</TestRouter>
</ThemeProvider>
Expand All @@ -53,22 +57,14 @@ const TestComponent = () => (

describe('TopBar', () => {
it('default', () => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: false,
});

const { getByTestId, getByText } = render(<TestComponent />);

expect(getByTestId('TopBar')).toBeInTheDocument();
expect(getByText('Dashboard')).toBeInTheDocument();
});

it('hides links during the setup tour', () => {
(useSetupContext as jest.MockedFn<typeof useSetupContext>).mockReturnValue({
onSetupTour: true,
});

const { queryByText } = render(<TestComponent />);
const { queryByText } = render(<TestComponent onSetupTour />);

expect(queryByText('Dashboard')).not.toBeInTheDocument();
});
Expand Down
17 changes: 15 additions & 2 deletions src/components/Setup/SetupProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useRouter } from 'next/router';
import React, {
PropsWithChildren,
ReactNode,
createContext,
useContext,
Expand Down Expand Up @@ -43,13 +44,13 @@ const setupPages = new Set([
'/accountLists/[accountListId]/setup/finish',
]);

interface Props {
interface SetupProviderProps {
children: ReactNode;
}

// This context component ensures that users have gone through the setup process
// and provides the setup state to the rest of the application
export const SetupProvider: React.FC<Props> = ({ children }) => {
export const SetupProvider: React.FC<SetupProviderProps> = ({ children }) => {
const { data } = useSetupStageQuery();
const { push, pathname } = useRouter();

Expand Down Expand Up @@ -99,3 +100,15 @@ export const SetupProvider: React.FC<Props> = ({ children }) => {
</SetupContext.Provider>
);
};

// This provider is meant for use in tests. It lets tests easily override the
// onSetupTour without needing to mock useSetupProvider or the pathname and
// SetupStage GraphQL query.
export const TestSetupProvider: React.FC<PropsWithChildren<SetupContext>> = ({
children,
onSetupTour,
}) => (
<SetupContext.Provider value={{ onSetupTour }}>
{children}
</SetupContext.Provider>
);

0 comments on commit 7589602

Please sign in to comment.