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("");