Files
padhle/testing-doc.md
2026-09-15 04:08:55 -04:00

9.0 KiB
Raw Permalink Blame History

padhle — Frontend Manual Testing Plan

Goal: test the application through the browser (frontend only) and verify every feature that was built, changed, or hardened. Setup: backend on :3001, frontend dev server on :5173, local Supabase running (npx supabase start). Recommended browsers: test in a normal window and an incognito window side-by-side (incognito = clean anonymous identity).


0. Before you start — launch

Step Do this Expected
0.1 Terminal 1: cd backend && npm run dev Backend on :3001
0.2 Terminal 2: cd frontend && npm run dev Frontend opens http://localhost:5173
0.3 Open http://localhost:5173 in incognito App loads; no sign-in wall — you're in the app (sidebar, selectors, chat input visible)

⚠️ If you don't have a Supabase/backend running, backend calls for sign-in/chat will fail with a connection error banner. The anonymous flow also needs the backend for chat. If a real AI key has no quota, streams may end with an in-chat error (expected, not a code bug).


1. Anonymous 5-message trial (FREE-TIER — this is the headline feature)

This is the core new behavior. Everything here works without an account.

# Do this Expected
1.1 In incognito, notice the TopNav + Sidebar Both show a "Sign in" button (no avatar)
1.2 Pick a grade → subject → chapter, then send a message Streaming answer appears; chat thread builds
1.3 Send 4 more messages (5 total) Each works; counter quietly builds up (you see the conversation continue)
1.4 Send a 6th message Composer is replaced by a card: "You've used your 5 free messages — Sign in to continue"
1.5 If you've closed/reopened between messages: the URL stays on / the whole time Anonymous chat does NOT reflect a chat id into the browser URL
1.6 Click "Sign in to continue" on the card The sign-in modal opens
1.7 Close the modal (× / "Maybe later" / click the dimmer) Modal closes; you can keep navigating, still capped at 5
1.8 Refresh the page after using some messages Conversation resets to a fresh 5-message budget (by design)
1.9 Secure: open DevTools → Application → Cookies There is no padhle.anon cookie; your anonymous state is 100% in-memory (refresh wipes it)

Cross-browser isolation:

# Do this Expected
1.10 Use 2 different browsers (or normal + incognito), both anonymous Each has its own separate budget; their chats are not visible to each other

2. Sign-up / Sign-in / Auth

# Do this Expected
2.1 Click "Sign in" (TopNav or Sidebar) Modal opens cleanly
2.2 Sign up with a valid email + password (≥6 chars) Account created; you are now signed in; avatar appears in TopNav; sessions sidebar appears
2.3 Reload the page (F5) You stay signed in (session restored from the httpOnly cookie)
2.4 Try to sign up with a 5-character password (via the UI if it lets you, or note): Server must reject (password ≥ 6). The UI enforces it too — if the UI blocks it, that's fine
2.5 Sign out (Sidebar → sign out) You are logged out; back to anonymous app with a fresh 5-message budget; "Sign in" buttons return
2.6 Sign back in with the same email/password Your previous signed-in conversation is still there in the sidebar

3. Sessions (persisted conversations, signed-in only)

# Do this Expected
3.1 While signed in, start a new chat and send a few messages When you send, the URL becomes /chat/<id> (signed-in chats ARE deep-linkable)
3.2 Open another chat from the sidebar URL switches to that chat's /chat/<id>; back/forward browser buttons work
3.3 Copy the /chat/<id> URL, open it in another tab (signed in there) The conversation loads directly (deep link works)
3.4 New chat button Resets to /, clears composer, back to a fresh conversation
3.5 Delete a session from the sidebar Removed; no longer in the list
3.6 Clear messages in a session (if available) Conversation empties but the session stays
3.7 Secure — ownership: in browser A (user 1) note a session URL; in incognito (user 2) paste that exact URL Two possibilities: if you are NOT signed in there → app shows clean "could not load" / stays on /; if you ARE signed in as user 2 → NOT user 1's messages (must be 404 — you should NOT see user 1's chat)

4. Routing / URLs (added this session)

# Do this Expected
4.1 While anonymous, send a message URL stays / (anonymous trial id is never written to the URL — security decision)
4.2 While signed in, open a chat URL is /chat/<id> — shareable and refreshable
4.3 Type a random path, e.g. http://localhost:5173/whatever App still loads at the root shell (SPA fallback) — no 404 page yet (documented)
4.4 Browser back/forward buttons between chats Moves between conversations as expected

5. AI streaming + rendering

# Do this Expected
5.1 Send a question and watch the reply Answer streams word by word (token by token), typing indicator during
5.2 Ask for something with Markdown (e.g. "give me a bulleted list, bold text, a code block") Renders as formatted Markdown (not raw ** / backticks)
5.3 Ask for math (e.g. "what is x^2 + y^2") LaTeX renders via KaTeX
5.4 Secure — XSS: ask the AI to output raw HTML like <script>alert(1)</script> (or intentionally craft a message) It renders as text, NOT executable HTML — no alert pops
5.5 Long answer Auto-scrolls to the new content

6. Errors, validation, robustness (secure boundary checks)

These verify the backend still protects you even if the frontend is bypassed. Easiest way: open DevTools Console and run fetch(...) from the page (same-origin) — or just reason through the UI where possible.

# Try Expected
6.1 fetch('http://localhost:3001/api/chat',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:123})}) (no session cookie) 400 with a clean JSON error — NOT a 500 / stack trace
6.2 fetch('http://localhost:3001/api/chat',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:'hi',chapter:'<script>'})}) (no cookie) 400 (chapter with </> rejected)
6.3 fetch('http://localhost:3001/api/sessions') (no cookie) 401
6.4 fetch('http://localhost:3001/api/chat/sessions') (no cookie) 401
6.5 Shut down the backend, then send a message Frontend shows a "Connection error… make sure backend is running" message — app doesn't hang
6.6 Open DevTools → Network, and confirm the chat requests carry cookies with credentials: include Requests are same-origin via the Vite proxy; cookies sent automatically

The rate limits (5 auth/15min, 30 chat/min, 20 sessions/min per IP) won't usually trip you in manual testing — they're per-IP and reset. Don't try to exhaust them in the UI; they're verified server-side.


7. Security-review smoke test (quick pass)

# Do this Expected
7.1 Sign in; open DevTools → Application → Cookies for localhost padhle.token and padhle.user are marked HttpOnly; SameSite = Lax
7.2 Open any response in DevTools → Network → Headers Headers include X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: no-referrer, Cross-Origin-Opener-Policy: same-origin; no X-Powered-By
7.3 After signing out, note your old chat URL and reload it (signed out) You can't load a signed-in-only chat while anonymous (clean, no data leak)

8. Final sign-off checklist

  • Anonymous user can send 5 messages, then is blocked gracefully with a Sign in to continue card.
  • Anonymous URL stays on /.
  • Sign in/up works; session survives reload.
  • Signed-in chats are deep-linkable at /chat/<id>.
  • Two identities never see each other's data.
  • Streamed Markdown + math renders; raw HTML is not executed.
  • Malformed JSON (non-string text) → clean 400, no crash/stack trace.
  • Unauthenticated calls to /api/sessions and /api/chat/sessions → 401.
  • Backend + frontend both build; cd backend && node --test → 38 pass.

Notes / expectations

  • You will NOT be able to exceed 5 anonymous messages in normal UI use — the card blocks you. That's correct.
  • Markdown/LaTeX demo depends on the AI model actually producing them; a generic question works either way.
  • If a real AI key has no quota, streaming may show an in-chat error after a short delay — that's the vendor, not the app. The frontend still handles errors gracefully.
  • This plan tests the frontend behavior. The full backend regression suite is cd backend && node --test (38 tests) and runs independently.