diff --git a/apps/app/src/app/pick/page.test.tsx b/apps/app/src/app/pick/page.test.tsx new file mode 100644 index 0000000..10c9676 --- /dev/null +++ b/apps/app/src/app/pick/page.test.tsx @@ -0,0 +1,36 @@ +import { afterEach, expect, it, vi } from 'vitest'; +import { act, cleanup, fireEvent, render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom/vitest'; +import PickPage from './page'; +const navigation = vi.hoisted(() => ({ session: 'first-session' })); +vi.mock('next/navigation', () => ({ useSearchParams: () => new URLSearchParams({ session: navigation.session }) })); +afterEach(() => { cleanup(); vi.unstubAllGlobals(); navigation.session = 'first-session'; }); + +it('allows a fresh pick after navigating from a completed session', async () => { + const fetch = vi.fn(() => Promise.resolve(new Response('{}'))); + vi.stubGlobal('fetch', fetch); + const view = render(); + await act(async () => { fireEvent.click(screen.getAllByRole('button')[0]); }); + expect(screen.getByText('Sent!')).toBeInTheDocument(); + navigation.session = 'second-session'; + view.rerender(); + expect(screen.queryByText('Sent!')).not.toBeInTheDocument(); + expect(screen.getAllByRole('button')).toHaveLength(3); + await act(async () => { fireEvent.click(screen.getAllByRole('button')[0]); }); + const submissions = fetch.mock.calls.filter((call) => (call as unknown as [string, RequestInit])[1]?.method === 'POST'); + expect(submissions).toHaveLength(2); + expect(JSON.parse((submissions[1] as unknown as [string, RequestInit])[1].body as string).sessionId).toBe('second-session'); +}); + +it('isolates a late failed request from the next session', async () => { + let reject!: (error: Error) => void; + const oldRequest = new Promise((_resolve, no) => { reject = no; }); + vi.stubGlobal('fetch', vi.fn((_url, options) => options.method === 'POST' ? oldRequest : Promise.resolve(new Response('{}')))); + const view = render(); + fireEvent.click(screen.getAllByRole('button')[0]); + navigation.session = 'second-session'; + view.rerender(); + await act(async () => { reject(new Error('Old session expired')); }); + expect(screen.queryByText('Something went wrong. Try again.')).not.toBeInTheDocument(); + expect(screen.getByText('Pick a Visualization')).toBeInTheDocument(); +}); diff --git a/apps/app/src/app/pick/page.tsx b/apps/app/src/app/pick/page.tsx index b43973b..f8f8c12 100644 --- a/apps/app/src/app/pick/page.tsx +++ b/apps/app/src/app/pick/page.tsx @@ -77,14 +77,18 @@ function pickRandom(arr: T[], n: number): T[] { export default function PickPageWrapper() { return (

Loading...

}> - +
); } -function PickPage() { +function SessionPickPage() { const searchParams = useSearchParams(); const sessionId = searchParams.get("session"); + return ; +} + +function PickPage({ sessionId }: { sessionId: string | null }) { const [picked, setPicked] = useState(false); const [error, setError] = useState("");