Skip to content

Commit

Permalink
add getter, setter to useUrl hook for tree url parameter and modify A…
Browse files Browse the repository at this point in the history
…pp.tsx to automatically set tree to '0' if no tree is specified
  • Loading branch information
dpgraham4401 committed Sep 18, 2024
1 parent bbc4593 commit da253c3
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 1 deletion.
20 changes: 20 additions & 0 deletions src/App.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import '@testing-library/jest-dom';
import App from '@/App';
import { useUrl } from '@/hooks';
import useTreeStore from '@/store';
import { notFirstTimeMock, renderWithProviders } from '@/test-utils';
import { cleanup, screen, waitFor } from '@testing-library/react';
Expand Down Expand Up @@ -49,6 +50,11 @@ afterAll(() => {

describe('App', () => {
notFirstTimeMock();
vi.mock('@/hooks', async (importOriginal) => ({
...(await importOriginal<typeof import('@/hooks')>()),
useUrl: vi.fn().mockReturnValue({ pathParam: 'test', setTreeParam: vi.fn() }),
}));

test('shows a spinner while waiting for config', () => {
server.use(
http.get('/default.json', async () => {
Expand All @@ -70,29 +76,34 @@ describe('App', () => {
renderWithProviders(<TestComponent />);
expect(screen.getByTestId('spinner')).toBeInTheDocument();
});

test('renders a title if provided', async () => {
const title = 'Zee bananas';
vi.stubEnv('VITE_APP_TITLE', title);
renderWithProviders(<TestComponent />);
await waitFor(() => expect(screen.queryByTestId('spinner')).not.toBeInTheDocument());
expect(screen.getByText(title)).toBeInTheDocument();
});

test('defaults title to "The Manifest Game"', async () => {
renderWithProviders(<TestComponent />);
await waitFor(() => expect(screen.queryByTestId('spinner')).not.toBeInTheDocument());
expect(screen.getByText('The Manifest Game')).toBeInTheDocument();
});

test('minimap is visible by default', async () => {
renderWithProviders(<TestComponent />);
await waitFor(() => expect(screen.queryByTestId('spinner')).not.toBeInTheDocument());
expect(screen.getByTestId(/minimap/i)).toBeInTheDocument();
});

test('Throws an error if there is an error fetching the config', async () => {
server.use(http.get('/default.json', () => HttpResponse.error()));
renderWithProviders(<TestComponent />);
await waitFor(() => expect(screen.queryByTestId('spinner')).not.toBeInTheDocument());
expect(screen.getByText(/Error/i)).toBeInTheDocument();
});

test('the help content is closed onClicking the close button', async () => {
const user = userEvent.setup();
useTreeStore.setState({ helpIsOpen: true });
Expand All @@ -103,4 +114,13 @@ describe('App', () => {
await user.click(closeButton);
expect(screen.getByTestId('offcanvas')).not.toBeVisible();
});

test('application sets the tree query parameter if not set', async () => {
const setTreeParam = vi.fn();
// @ts-expect-error - only mocking necessary hook returned objects
vi.mocked(useUrl).mockReturnValue({ pathParam: 'test', setTreeParam });
renderWithProviders(<TestComponent />);
await waitFor(() => expect(screen.queryByTestId('spinner')).not.toBeInTheDocument());
expect(setTreeParam).toHaveBeenCalledWith('0');
});
});
9 changes: 8 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { OffCanvas } from '@/components/OffCanvas/OffCanvas';
import { Spinner } from '@/components/Spinner/Spinner';
import { Tree } from '@/components/Tree/Tree';
import { useDecisionTree, useFetchConfig, useHelp, useUrl } from '@/hooks';
import { useEffect } from 'react';

/**
* App - responsible for rendering the decision tree
Expand All @@ -13,10 +14,16 @@ import { useDecisionTree, useFetchConfig, useHelp, useUrl } from '@/hooks';
export default function App() {
const title = import.meta.env.VITE_APP_TITLE ?? 'The Manifest Game';
const { config, isLoading: configIsLoading, error: configError } = useFetchConfig(defaultTree);
const { pathParam } = useUrl();
const { pathParam, treeParam, setTreeParam } = useUrl();
const { nodes, edges } = useDecisionTree(config, pathParam);
const { helpIsOpen, hideHelp } = useHelp();

useEffect(() => {
if (!treeParam) {
setTreeParam('0');
}
}, [treeParam, setTreeParam]);

return (
<>
<Header treeTitle={title} />
Expand Down
11 changes: 11 additions & 0 deletions src/hooks/useUrl/useUrl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { useLocation, useSearchParams } from 'react-router-dom';
export interface UsesPathReturn {
pathParam: string;
setPathParam: (pathId: string) => void;
treeParam: string;
setTreeParam: (treeId: string) => void;
pathname: string;
copyTreeUrlToClipboard: () => void;
}
Expand All @@ -15,6 +17,7 @@ export interface UsesPathReturn {
export const useUrl = () => {
const [urlQueryParams, setUrlQueryParams] = useSearchParams();
const [pathParam, setPathParam] = useState<string | null | undefined>(urlQueryParams.get('path'));
const [treeParam, setTreeParam] = useState<string | null | undefined>(urlQueryParams.get('tree'));
const { pathname } = useLocation();
const { path } = useDecisions();

Expand All @@ -24,6 +27,12 @@ export const useUrl = () => {
setPathParam(pathId);
};

const setUrlTreeId = (treeId: string) => {
urlQueryParams.set('tree', treeId);
setUrlQueryParams(urlQueryParams);
setTreeParam(treeId);
};

const copyUrl = () => {
if (path.length < 1) return;
setUrlPathId(path[path.length - 1].selected);
Expand All @@ -35,6 +44,8 @@ export const useUrl = () => {
return {
pathParam,
setPathParam: setUrlPathId,
treeParam,
setTreeParam: setUrlTreeId,
pathname,
copyTreeUrlToClipboard: copyUrl,
} as UsesPathReturn;
Expand Down

0 comments on commit da253c3

Please sign in to comment.