# ClassicsLens E2E Test Specification

This document specifies all test cases for automated Playwright testing. Each test includes setup, steps, and assertions that Claude can convert to executable TypeScript test code.

**Target:** 80+ test cases covering all major user flows

**Format per test case:**
```
### [Section] — [Test Name]
**Prerequisites:** [Setup needed]
**Steps:**
1. [Action]
2. [Action]
3. [Assertion]
**Expected Result:** [What should happen]
**Assertion Code:** [Key assertions to check]
```

---

# SECTION 1: AUTHENTICATION & ACCOUNT MANAGEMENT

## 1.1 Google OAuth

### Test 1.1.1 — Google OAuth Sign-In (First Time)
**Prerequisites:** Fresh browser, not logged in, valid Google test account
**Steps:**
1. Navigate to classicslens.com (unauthenticated)
2. Verify "Sign in with Google" button visible
3. Click "Sign in with Google"
4. (Mock OAuth or use test account — verify redirect)
5. Verify redirected back to app
6. Verify localStorage contains auth token

**Expected Result:** User logged in, redirected to Today tab, auth token stored

**Assertion Code:**
```javascript
// URL contains classicslens.com/app (not oauth provider)
// localStorage.getItem('auth_token') exists and is non-empty
// Page displays "Today" tab with greeting message
```

---

### Test 1.1.2 — Google OAuth Sign-In (Returning User)
**Prerequisites:** Account with prior login + saved SRS data
**Steps:**
1. Log in via Google OAuth
2. Verify redirected to Today tab
3. Navigate to Review tab
4. Verify saved SRS cards are present (from prior session)

**Expected Result:** User logs in, existing data preserved

**Assertion Code:**
```javascript
// Review tab shows SRS card count > 0
// Card details match previously saved words
```

---

## 1.2 Email/Password Auth (if implemented)

### Test 1.2.1 — Email/Password Sign-Up
**Prerequisites:** Fresh browser, new email address
**Steps:**
1. Navigate to login page
2. Click "Sign up with email"
3. Enter new email: test+[timestamp]@example.com
4. Enter password: TestPass123!
5. Click "Sign up"
6. (Check email mock or test inbox for verification link)
7. Click verification link
8. Verify email marked as verified

**Expected Result:** Account created, email verified, user can log in

**Assertion Code:**
```javascript
// Success message: "Account created"
// Redirected to verification page or success page
// Subsequent login with same email/password succeeds
```

---

### Test 1.2.2 — Email/Password Sign-In
**Prerequisites:** Account with email/password credentials
**Steps:**
1. Navigate to login page
2. Click "Sign in with email"
3. Enter email: test@example.com
4. Enter password: TestPass123!
5. Click "Sign in"
6. Verify redirected to Today tab

**Expected Result:** User logged in with valid credentials

**Assertion Code:**
```javascript
// URL changes to /app
// localStorage.getItem('auth_token') exists
// User greeting displays (name or email)
```

---

### Test 1.2.3 — Password Reset Flow
**Prerequisites:** Account with email/password
**Steps:**
1. On login page, click "Forgot password?"
2. Enter email: test@example.com
3. Click "Send reset link"
4. Verify success message: "Check your email for reset link"
5. (Mock or test inbox: click reset link)
6. Enter new password: NewPass456!
7. Click "Reset password"
8. Verify success message
9. Log in with new password

**Expected Result:** Password successfully reset, old password no longer works

**Assertion Code:**
```javascript
// Reset page displays success message
// Login with old password fails
// Login with new password succeeds
```

---

## 1.3 Session Management

### Test 1.3.1 — Logout
**Prerequisites:** Logged-in user
**Steps:**
1. Click account menu (top right)
2. Click "Logout"
3. Verify redirected to login page
4. Check localStorage — no auth token
5. Try to navigate to /app directly
6. Verify redirected back to login

**Expected Result:** User logged out, session cleared, cannot access protected pages

**Assertion Code:**
```javascript
// URL is /login or /
// localStorage.getItem('auth_token') is null or empty
// Accessing /app redirects to /login
```

---

### Test 1.3.2 — Session Persistence (Refresh)
**Prerequisites:** Logged-in user on Today tab
**Steps:**
1. Log in
2. Navigate to Review tab
3. Refresh page (F5)
4. Verify still on Review tab
5. Verify data intact (SRS cards still present)

**Expected Result:** Session persists across refresh, no re-login needed

**Assertion Code:**
```javascript
// Page reloads and returns to Review tab
// SRS cards still displayed
// Auth token still in localStorage
```

---

# SECTION 2: ACCOUNT & PROFILE MANAGEMENT

## 2.1 Account Settings Page

### Test 2.1.1 — View Account Page
**Prerequisites:** Logged-in user
**Steps:**
1. Click account menu → "Account settings"
2. Verify page displays:
   - Display name field
   - Email field (read-only or editable)
   - Account created date
   - Subscription status (if monetized)

**Expected Result:** Account page loads with all user info

**Assertion Code:**
```javascript
// Page title or header contains "Account" or "Settings"
// Display name field value matches logged-in user
// Email field shows correct email
// Account created date is displayed
```

---

### Test 2.1.2 — Update Display Name
**Prerequisites:** Logged-in user on account page
**Steps:**
1. Click edit button next to name (or clear field)
2. Enter new name: "Test User Updated"
3. Click "Save"
4. Verify success message: "Profile updated"
5. Refresh page
6. Verify name is still "Test User Updated"

**Expected Result:** Display name updated and persisted

**Assertion Code:**
```javascript
// Success message displays
// Name field value changes to new name
// After refresh, name field still shows new name
// (Optional) User greeting in header shows new name
```

---

### Test 2.1.3 — Change Password
**Prerequisites:** Logged-in user with password auth
**Steps:**
1. On account page, click "Change password"
2. Enter current password: OldPass123!
3. Enter new password: NewPass456!
4. Confirm new password: NewPass456!
5. Click "Save"
6. Verify success message
7. Log out
8. Try logging in with old password — should fail
9. Log in with new password — should succeed

**Expected Result:** Password changed, old password invalid

**Assertion Code:**
```javascript
// Success message displays
// Logout and login with old password fails (401 Unauthorized)
// Login with new password succeeds
```

---

### Test 2.1.4 — Delete Account
**Prerequisites:** Logged-in user
**Steps:**
1. On account page, scroll to "Danger Zone"
2. Click "Delete Account"
3. Modal appears with warning
4. (If confirmation text required) Type "DELETE"
5. Click "Confirm Delete Account"
6. Verify success message: "Account deleted"
7. Verify redirected to login page
8. Try to log in with deleted email — should fail

**Expected Result:** Account and all data deleted permanently

**Assertion Code:**
```javascript
// Success message displays
// Redirected to login page (URL is /login or /)
// Attempting login with deleted email returns 401 or "Account not found"
```

---

# SECTION 3: TODAY TAB — DAILY PASSAGE

## 3.1 Passage Display

### Test 3.1.1 — Load Today Tab on Login
**Prerequisites:** Fresh login
**Steps:**
1. Log in (any auth method)
2. Verify Today tab is active/highlighted
3. Verify passage loads with:
   - Title (author/work)
   - Passage text
   - Language indicator (Greek/Latin)
   - Difficulty buttons (Easy/Medium/Hard)

**Expected Result:** Today tab displays passage on login

**Assertion Code:**
```javascript
// Active tab is "Today"
// Passage text element contains > 50 characters
// Title element is visible and non-empty
// Language indicator shows "Greek" or "Latin"
// Difficulty buttons visible
```

---

### Test 3.1.2 — Switch Difficulty Level
**Prerequisites:** On Today tab with passage loaded
**Steps:**
1. Start on Easy difficulty
2. Identify words with glosses (count them)
3. Click "Medium" difficulty
4. Verify gloss count changes (fewer glosses visible)
5. Click "Hard"
6. Verify even fewer glosses
7. Click "Easy" again
8. Verify glosses return to original count

**Expected Result:** Glosses shown/hidden based on difficulty

**Assertion Code:**
```javascript
// On Easy: visible gloss elements count >= medium count
// On Medium: visible gloss elements count between easy and hard
// On Hard: visible gloss elements count <= medium count
// Switching back to Easy restores original gloss visibility
```

---

### Test 3.1.3 — Tap Word for Popup
**Prerequisites:** On Today tab with passage loaded
**Steps:**
1. Click/tap a word in the passage
2. Verify popup appears with:
   - Headword (lemma)
   - Short definition
   - Morphological analysis
   - Frequency (if available)
   - External links (Logeion/Perseus if available)
3. Click outside popup or close button
4. Verify popup closes

**Expected Result:** Word popup displays and closes cleanly

**Assertion Code:**
```javascript
// Popup element is visible after word click
// Popup contains text "Definition:" or similar label
// Popup contains morphological info
// Close button or outside click removes popup from DOM
```

---

### Test 3.1.4 — Add Word to SRS from Popup
**Prerequisites:** Word popup open on Today tab
**Steps:**
1. Tap a word, popup appears
2. Click "Add to review" button
3. Verify success message: "Added to review"
4. Navigate to Review tab
5. Verify word appears in saved vocabulary list

**Expected Result:** Word saved to SRS deck

**Assertion Code:**
```javascript
// Success toast/message displays after clicking "Add to review"
// Word appears in Review tab vocabulary list
// (Optional) SRS card count increments
```

---

## 3.2 Passage Navigation

### Test 3.2.1 — Navigate to Next/Previous Day
**Prerequisites:** On Today tab
**Steps:**
1. Note current passage title
2. Click next arrow (→)
3. Verify passage changes to next day
4. Note new passage title (different from before)
5. Click prev arrow (←)
6. Verify passage returns to original

**Expected Result:** Navigation between days works correctly

**Assertion Code:**
```javascript
// After clicking next: passage title changes
// After clicking prev: passage title matches original
// Passage text content changes when navigating
```

---

### Test 3.2.2 — Navigate via Date Picker (if implemented)
**Prerequisites:** On Today tab
**Steps:**
1. Click date picker or calendar icon
2. Select a specific date in the past (e.g., 5 days ago)
3. Verify passage changes to that date
4. Date picker closes

**Expected Result:** Passage for selected date loads

**Assertion Code:**
```javascript
// Date picker opens on click
// Selecting a date closes picker and loads new passage
// Passage date matches selected date (if date displayed)
```

---

## 3.3 Settings Integration

### Test 3.3.1 — Language Mix Setting
**Prerequisites:** User with settings
**Steps:**
1. Go to Settings
2. Set "Language mix" to "Greek only"
3. Navigate to Today tab
4. Verify current passage is in Greek (check text for Greek characters)
5. Go to Settings, change to "Latin only"
6. Navigate to next day
7. Verify new passage is in Latin

**Expected Result:** Language setting controls daily passage language

**Assertion Code:**
```javascript
// Language mix dropdown value changes
// After setting Greek only: passage contains Greek characters (α, β, γ, etc.)
// After setting Latin only: passage contains Latin text (no Greek chars)
```

---

### Test 3.3.2 — Support Level (Difficulty) Setting
**Prerequisites:** User with settings
**Steps:**
1. Go to Settings
2. Set "Support level" to "Hard"
3. Navigate to Today tab
4. Verify difficulty is defaulted to Hard (Hard button highlighted)
5. Go back to Settings, change to "Easy"
6. Refresh page or navigate away and back
7. Verify difficulty now defaults to Easy

**Expected Result:** Default difficulty setting is remembered

**Assertion Code:**
```javascript
// Support level dropdown value matches setting
// After setting Hard: Today tab defaults to Hard difficulty (button highlighted)
// After changing to Easy and refresh: defaults to Easy
```

---

# SECTION 4: REVIEW TAB — SPACED REPETITION

## 4.1 SRS Deck

### Test 4.1.1 — Load Review Tab (No Cards)
**Prerequisites:** Fresh account with no saved vocabulary
**Steps:**
1. Log in to fresh account
2. Click Review tab
3. Verify message: "No cards due today" or similar
4. Verify no card displayed

**Expected Result:** Empty state message shown

**Assertion Code:**
```javascript
// Review tab active
// Message text contains "No cards" OR "Great job" OR similar
// No card element visible
```

---

### Test 4.1.2 — Load Review Tab (Cards Due)
**Prerequisites:** Account with 5+ due SRS cards
**Steps:**
1. Log in
2. Click Review tab
3. Verify first card displays with:
   - Inflected form (front)
   - Card counter: "1 of 5" or similar
   - Card is interactive (appears clickable)
4. Click card
5. Verify back of card shows:
   - Lemma (bold)
   - Definition
   - Morphology
   - Passage context (optional)

**Expected Result:** SRS card displays and flips on click

**Assertion Code:**
```javascript
// Card element visible
// Card counter text includes number of cards
// Clicking card shows lemma/definition
// Card state changes from "front" to "back"
```

---

### Test 4.1.3 — Grade Card (Again/Good/Easy)
**Prerequisites:** Flipped SRS card on Review tab
**Steps:**
1. On Review tab with flipped card
2. Click "Again" button (red)
3. Verify:
   - Card marked as "Again"
   - Next card appears (counter increments to 2 of 5)
4. Click "Good" on next card
5. Click "Easy" on next card
6. Verify all three cards graded and next card appears

**Expected Result:** Cards graded and spaced-repetition intervals applied

**Assertion Code:**
```javascript
// After clicking grade button: next card appears
// Card counter increments (1 of 5 → 2 of 5)
// (Optional) Grade buttons are disabled briefly to prevent double-click
```

---

### Test 4.1.4 — Session Complete & Summary
**Prerequisites:** Reviewed all due cards for session
**Steps:**
1. On Review tab, grade all cards (mix of Again/Good/Easy)
2. After last card graded, summary appears:
   - "Session complete!"
   - Breakdown: "Again: X, Good: Y, Easy: Z"
   - Next review time: "Tomorrow at 2pm" or similar
3. Click "Done" or "Back"
4. Verify Review tab shows updated due count (should be 0 if all cards reviewed)

**Expected Result:** Session summary displayed, SRS state updated

**Assertion Code:**
```javascript
// Summary message displays with breakdown counts
// Counts match grades given (sum of Again + Good + Easy = cards reviewed)
// Due count resets to 0 (or only future cards show as due)
```

---

### Test 4.1.5 — Session Persistence (Refresh During Review)
**Prerequisites:** In middle of SRS session, with cards graded
**Steps:**
1. On Review tab, grade a card
2. Note the card counter (e.g., "2 of 5")
3. Refresh page (F5)
4. Verify Review tab reloads
5. Verify session resumes (either shows next card or offers to resume)

**Expected Result:** SRS session state persisted across refresh

**Assertion Code:**
```javascript
// After refresh: Review tab still visible
// Card counter still shows same or higher number (not reset to 1)
// (Optional) "Resume session" button if session interrupted
```

---

## 4.2 Vocabulary Management

### Test 4.2.1 — View Saved Vocabulary List
**Prerequisites:** Account with 10+ saved words
**Steps:**
1. Click Review tab
2. If vocabulary list is separate view, click "Vocabulary" or similar
3. Verify list displays all saved words:
   - Lemma
   - Definition
   - Date added
   - Frequency (if available)

**Expected Result:** Vocabulary list shows all saved words with details

**Assertion Code:**
```javascript
// Vocabulary list element visible
// List contains >= 10 items (each with lemma, definition)
// Each item displays date added (or timestamp)
```

---

### Test 4.2.2 — Remove Word from SRS
**Prerequisites:** Vocabulary list visible with saved words
**Steps:**
1. On vocabulary list, click delete/remove button for a word
2. Verify confirmation modal: "Remove from review?"
3. Click "Confirm"
4. Verify word removed from list
5. Start new SRS session
6. Verify deleted word does not appear in new session

**Expected Result:** Word removed from SRS deck

**Assertion Code:**
```javascript
// Delete button click shows confirmation modal
// After confirming: word removed from vocabulary list
// Next SRS session does not include deleted word
```

---

### Test 4.2.3 — Export Vocabulary as CSV (if implemented)
**Prerequisites:** Vocabulary list with saved words
**Steps:**
1. On vocabulary list, click "Export" or "Download CSV"
2. Verify file downloads: classicslens-vocabulary.csv (or similar)
3. Open CSV in text editor or spreadsheet
4. Verify columns: headword, definition, frequency, date_added
5. Verify all saved words included in CSV

**Expected Result:** CSV export includes all vocabulary

**Assertion Code:**
```javascript
// Download triggered (monitor Network tab for file request)
// File has .csv extension
// File content includes headword column header
// CSV contains all vocabulary words (count matches list)
```

---

# SECTION 5: PARSE TAB — MORPHOLOGICAL LOOKUP

## 5.1 Word Parsing

### Test 5.1.1 — Parse Greek Word (With Accents)
**Prerequisites:** On Parse tab
**Steps:**
1. Enter: "ἀνθρώπου" (Greek genitive singular with accent)
2. Press Enter or click Parse
3. Verify results show:
   - Lemma: "ἄνθρωπος"
   - Definition: contains "man" or "human"
   - Morphology: contains "Gen" and "sg" or "singular"
   - Paradigm table (collapsible)

**Expected Result:** Accurate parse with full morphological analysis

**Assertion Code:**
```javascript
// Results section visible after parsing
// Results contain lemma
// Results contain definition
// Results contain morphological info (case, number, etc.)
// Paradigm table present
```

---

### Test 5.1.2 — Parse Greek Word (Accentless)
**Prerequisites:** On Parse tab
**Steps:**
1. Enter: "anthropou" (accentless)
2. Press Enter
3. Verify results match Test 5.1.1 (same lemma, definition, morphology)

**Expected Result:** Accentless input generates accent variants automatically

**Assertion Code:**
```javascript
// Parsing succeeds despite missing accents
// Results match accented parsing (same lemma)
```

---

### Test 5.1.3 — Parse Latin Word
**Prerequisites:** On Parse tab
**Steps:**
1. Enter: "hominis" (Latin genitive singular)
2. Press Enter
3. Verify results show:
   - Lemma: "homo"
   - Definition: contains "man"
   - Morphology: Gen, sg, M (masculine)
   - Paradigm table

**Expected Result:** Latin parsing works correctly

**Assertion Code:**
```javascript
// Results contain Latin lemma
// Morphology includes gender (M/F/N)
// Definition matches Latin word sense
```

---

### Test 5.1.4 — Paradigm Collapse/Expand (if implemented)
**Prerequisites:** Parse results with paradigm table visible
**Steps:**
1. Click "Conjugation" or "Declension" header or expand/collapse arrow
2. Verify table collapses (hidden from view)
3. Click again
4. Verify table expands and shows all forms

**Expected Result:** Paradigm table toggleable

**Assertion Code:**
```javascript
// Paradigm section visible initially
// Clicking collapse button hides table
// Clicking expand button shows table again
```

---

### Test 5.1.5 — Compound Verb Detection (if implemented)
**Prerequisites:** On Parse tab
**Steps:**
1. Enter: "ἀπολύω" (compound: ἀπο- + λύω)
2. Press Enter
3. Verify results show:
   - Breakdown: "ἀπο- (away/from) + λύω (loosen)"
   - Link to root: "See root: λύω"
4. Click root link
5. Verify page shows parse of λύω

**Expected Result:** Compound verbs detected and decomposed

**Assertion Code:**
```javascript
// Results show prefix + root breakdown
// Root link present and clickable
// Clicking root link navigates to root word parse
```

---

### Test 5.1.6 — Word Not Found (Fallback Links)
**Prerequisites:** On Parse tab
**Steps:**
1. Enter: "zzzzz" (invalid word)
2. Press Enter
3. Verify message: "Word not found in local database"
4. Verify external links visible:
   - "Look up on Logeion"
   - "Look up on Perseus"
5. Click Logeion link (verify URL format, e.g., contains logeion.uchicago.edu)

**Expected Result:** Missing words show external links

**Assertion Code:**
```javascript
// "Word not found" message displays
// External link buttons visible
// Logeion link URL contains "logeion.uchicago.edu" or similar
// Perseus link URL contains "perseus.tufts.edu" or similar
```

---

## 5.2 Search History

### Test 5.2.1 — Search History Display
**Prerequisites:** Parsed 3+ words
**Steps:**
1. On Parse tab, parse: "ἀνθρώπου", "λύω", "hominis"
2. Verify search history appears (sidebar, dropdown, or list)
3. Verify all three words shown in history

**Expected Result:** Search history tracks recent parses

**Assertion Code:**
```javascript
// Search history section visible
// History contains >= 3 items
// Each history item shows word that was parsed
```

---

### Test 5.2.2 — Click History to Re-Parse
**Prerequisites:** Search history visible
**Steps:**
1. Click a word in search history (e.g., "λύω")
2. Verify results for that word appear (same as when parsing directly)

**Expected Result:** Clicking history re-runs parse

**Assertion Code:**
```javascript
// Clicking history item triggers parse
// Results appear for selected word
```

---

### Test 5.2.3 — Clear Search History
**Prerequisites:** Search history visible with >= 1 item
**Steps:**
1. Click "Clear history" button or option
2. Confirm if prompted
3. Verify history is cleared (no items shown)

**Expected Result:** Search history cleared

**Assertion Code:**
```javascript
// Clear history button visible
// After clicking: history section empty or shows "No history"
```

---

# SECTION 6: SETTINGS PAGE

## 6.1 Settings Page Load & Display

### Test 6.1.1 — Load Settings Page
**Prerequisites:** Logged-in user
**Steps:**
1. Click Settings tab or gear icon
2. Verify page displays all settings:
   - Language mix (dropdown/radio)
   - Support level (dropdown/radio)
   - POS color-coding (toggle)
   - Dark/light mode (toggle)
   - (If monetized) Subscription status

**Expected Result:** Settings page loads with all options

**Assertion Code:**
```javascript
// Settings page visible
// Language mix dropdown present
// Support level dropdown present
// Color-coding toggle present
// Dark mode toggle present
```

---

### Test 6.1.2 — Toggle Dark Mode
**Prerequisites:** On Settings page
**Steps:**
1. Click dark mode toggle (off → on)
2. Verify entire UI switches to dark theme
   - Background is dark
   - Text is light
   - All tabs and elements use dark theme
3. Log out and log in again
4. Verify dark mode is still active

**Expected Result:** Dark mode toggle persists across sessions

**Assertion Code:**
```javascript
// After toggle: background color changes to dark (RGB ~0-50)
// After toggle: text color changes to light (RGB ~200-255)
// After logout/login: dark mode still active
// localStorage or DB stores dark mode preference
```

---

### Test 6.1.3 — Language Mix Setting
**Prerequisites:** On Settings page
**Steps:**
1. Set language mix to "Greek only"
2. Navigate to Today tab
3. Verify passage is Greek (contains Greek characters)
4. Go back to Settings, change to "Latin only"
5. Navigate to next day's passage
6. Verify passage is Latin

**Expected Result:** Language mix setting controls daily passage language

**Assertion Code:**
```javascript
// Language mix dropdown value changes
// After Greek only: passage text contains Greek Unicode (α, β, γ)
// After Latin only: passage text is ASCII Latin (no Greek chars)
```

---

# SECTION 7: NAVIGATION & LAYOUT

## 7.1 Tab Navigation

### Test 7.1.1 — Switch Between All Tabs
**Prerequisites:** Logged-in user
**Steps:**
1. Click Today tab — verify passage loads
2. Click Review tab — verify SRS deck loads (or empty message)
3. Click Parse tab — verify input field visible
4. Click Settings tab — verify settings form visible
5. Click Today again — verify passage still displays

**Expected Result:** All tabs accessible, content switches correctly

**Assertion Code:**
```javascript
// Today tab: passage element visible
// Review tab: SRS card or "no cards" message visible
// Parse tab: input field visible
// Settings tab: settings controls visible
```

---

### Test 7.1.2 — Active Tab Highlighting
**Prerequisites:** Logged-in user on Today tab
**Steps:**
1. Verify Today tab is highlighted/bold in nav
2. Click Review
3. Verify Review is now highlighted, Today is not
4. Repeat for all tabs

**Expected Result:** Current tab visually distinct

**Assertion Code:**
```javascript
// Today tab has active class (or bold, color, etc.)
// After clicking Review: Review has active class, Today does not
// Each tab has active class when selected
```

---

## 7.2 Header & Menu

### Test 7.2.1 — Account Menu Dropdown
**Prerequisites:** Logged-in user
**Steps:**
1. Click account avatar/menu icon (top right)
2. Verify dropdown shows:
   - User name or email
   - "Account settings"
   - "Settings"
   - "Logout"
3. Click "Account settings"
4. Verify redirected to account page

**Expected Result:** Account menu dropdown works

**Assertion Code:**
```javascript
// Account menu dropdown visible after click
// Dropdown contains "Account settings" option
// Clicking "Account settings" navigates to account page
```

---

### Test 7.2.2 — Logo Navigation
**Prerequisites:** Logged-in user on Review or Parse tab
**Steps:**
1. Click app logo (top left)
2. Verify redirected to Today tab

**Expected Result:** Logo navigates to Today tab

**Assertion Code:**
```javascript
// Clicking logo changes active tab to Today
// Passage content loads
```

---

# SECTION 8: RESPONSIVE DESIGN

## 8.1 Mobile Responsiveness

### Test 8.1.1 — Mobile Viewport (375px)
**Prerequisites:** On desktop, devtools open
**Steps:**
1. Open devtools (F12)
2. Toggle device toolbar (mobile view)
3. Set viewport to 375px width (iPhone SE)
4. Navigate through all tabs
5. Verify:
   - No horizontal scrolling
   - Buttons/inputs large enough (tap target >= 44px)
   - Text readable (font size >= 14px)

**Expected Result:** Mobile layout responsive, no horizontal scroll

**Assertion Code:**
```javascript
// Viewport width is 375px
// No horizontal scrollbar visible
// Button elements have min-height/width >= 44px
// Text elements have font-size >= 14px
```

---

### Test 8.1.2 — Tablet Viewport (768px)
**Prerequisites:** On desktop, devtools open
**Steps:**
1. Open devtools, toggle device toolbar
2. Set viewport to 768px (iPad)
3. Navigate through tabs
4. Verify:
   - No horizontal scrolling
   - Content uses space efficiently
   - All controls accessible

**Expected Result:** Tablet layout optimized

**Assertion Code:**
```javascript
// Viewport width is 768px
// No horizontal scrollbar
// Content width <= 100% of viewport
```

---

### Test 8.1.3 — Desktop Viewport (1440px+)
**Prerequisites:** On desktop at 1440px+ width
**Steps:**
1. Open app on wide screen or resize browser to 1440px+
2. Navigate through tabs
3. Verify:
   - Content not stretched to edges (reasonable max-width)
   - Text line length < 100 characters (readable)
   - Layout is centered/balanced

**Expected Result:** Desktop layout uses space well

**Assertion Code:**
```javascript
// Viewport width >= 1440px
// Page content has max-width (not stretched)
// Main content area width readable (<=80-100 chars)
```

---

## 8.2 Touch Interactions

### Test 8.2.1 — Tap Word for Popup (Mobile)
**Prerequisites:** Mobile viewport (375px), on Today tab
**Steps:**
1. Tap a word in the passage
2. Verify popup appears (centered, not cut off)
3. Popup is closeable by:
   - Tapping outside
   - Clicking X button (if visible)

**Expected Result:** Popup works on mobile without precise clicks

**Assertion Code:**
```javascript
// Popup visible after tap
// Popup is centered or positioned within viewport
// Popup closes on outside click or X button
```

---

### Test 8.2.2 — Tap to Flip SRS Card (Mobile)
**Prerequisites:** Mobile viewport, Review tab with due cards
**Steps:**
1. Tap the SRS card (center area)
2. Verify card flips to show answer
3. Tap again to flip back

**Expected Result:** Card flip works with single tap

**Assertion Code:**
```javascript
// Card flips on tap (shows back/answer)
// Card flips back on second tap
```

---

# SECTION 9: ERROR HANDLING & EDGE CASES

## 9.1 Network Errors

### Test 9.1.1 — Network Error on Page Load (Offline)
**Prerequisites:** App loaded, devtools open
**Steps:**
1. Open devtools Network tab
2. Set throttling to "Offline"
3. Navigate to a different tab or refresh
4. Verify error message: "Unable to load. Check your connection."
5. Click "Retry" button
6. Turn throttling back to normal
7. Click "Retry"
8. Verify page loads successfully

**Expected Result:** Graceful error handling for network failures

**Assertion Code:**
```javascript
// Error message displays when offline
// Retry button visible
// After enabling network and clicking Retry: content loads
```

---

### Test 9.1.2 — Slow Network (Simulate 3G)
**Prerequisites:** Devtools open
**Steps:**
1. Set network throttling to "Slow 3G"
2. Navigate to Today tab
3. Verify loading spinner appears
4. Wait up to 10 seconds
5. Verify content loads or timeout error shows
6. Turn off throttling

**Expected Result:** Loading state shown for slow networks

**Assertion Code:**
```javascript
// Loading spinner visible initially
// After timeout or load: spinner removed and content shown or error displayed
```

---

## 9.2 Input Validation

### Test 9.2.1 — Empty Parse Search
**Prerequisites:** On Parse tab, search field empty
**Steps:**
1. Leave search field empty
2. Press Enter or click Parse button
3. Verify either:
   - Button is disabled
   - Error message: "Please enter a word"

**Expected Result:** Empty search prevented

**Assertion Code:**
```javascript
// Parse button is disabled (greyed out) OR
// Error message displays: "Please enter a word"
```

---

### Test 9.2.2 — SQL Injection / XSS Protection
**Prerequisites:** On Parse tab
**Steps:**
1. Enter: `' OR 1=1 --` (SQL injection test)
2. Press Enter
3. Verify no error, just "Word not found" message
4. Enter: `<script>alert('xss')</script>`
5. Press Enter
6. Verify no error, no script execution

**Expected Result:** Malicious input handled safely

**Assertion Code:**
```javascript
// Malicious input does not cause errors
// Results show "Word not found" or similar
// No JavaScript errors in console
// No script execution (no alert() popup)
```

---

## 9.3 Edge Cases

### Test 9.3.1 — Rapid Tab Switching
**Prerequisites:** Logged-in user
**Steps:**
1. Rapidly click between tabs (Today → Review → Parse → Settings)
2. Continue for 10+ switches
3. Verify app remains stable (no errors, crashes)

**Expected Result:** Rapid navigation handled gracefully

**Assertion Code:**
```javascript
// No JavaScript errors in console after rapid switching
// App remains responsive (no blank screens or hangs)
```

---

### Test 9.3.2 — Large Passage Text
**Prerequisites:** On Today tab
**Steps:**
1. Verify passage displays (even if very long)
2. Scroll through entire passage
3. Verify all words are clickable and tappable

**Expected Result:** Large content handled without performance issues

**Assertion Code:**
```javascript
// Passage text fully visible and scrollable
// Word popup works for words anywhere in passage
// No performance lag while scrolling
```

---

# SECTION 10: MONETIZATION (If Implemented)

## 10.1 Pricing & Subscriptions

### Test 10.1.1 — Pricing Page Display
**Prerequisites:** Not logged in or on marketing site
**Steps:**
1. Navigate to /pricing (or Pricing link on landing page)
2. Verify pricing table shows three tiers:
   - Free Tier: features list, "Sign up" CTA
   - Pro Tier: features list, "$4.99/month" price, "Subscribe" CTA
   - Academic Tier: features list, "$14.99/month" price, "Contact sales" CTA

**Expected Result:** Pricing page displays all tiers

**Assertion Code:**
```javascript
// Pricing table visible
// Free, Pro, Academic tiers shown
// Prices displayed ($4.99, $14.99)
// CTAs visible for each tier
```

---

### Test 10.1.2 — Free Tier Quote Enforcement (10 parses/day)
**Prerequisites:** Logged in as free user
**Steps:**
1. Click Parse tab
2. Parse 10 different words throughout the day
3. After 10th parse, attempt to parse another
4. Verify error: "Daily parse limit reached (10/10)"
5. Verify "Upgrade" button displayed

**Expected Result:** Free users limited to 10 parses/day

**Assertion Code:**
```javascript
// After 10 parses: error message displays
// Error message includes current limit and max limit
// "Upgrade" button visible
```

---

### Test 10.1.3 — SRS Disabled for Free Tier
**Prerequisites:** Logged in as free user
**Steps:**
1. Try to save a word to SRS (add word from Today tab)
2. Verify error or upgrade prompt: "SRS review requires Pro tier"
3. Review tab shows message: "Upgrade to Pro to unlock SRS"

**Expected Result:** Free users cannot use SRS

**Assertion Code:**
```javascript
// Add to SRS blocked with upgrade message
// Review tab shows upgrade prompt (not SRS cards)
```

---

### Test 10.1.4 — Stripe Checkout Flow
**Prerequisites:** Logged in as free user
**Steps:**
1. Click "Upgrade to Pro" button
2. Verify redirected to Stripe checkout page
3. Verify checkout shows:
   - Plan name: "ClassicsLens Pro - $4.99/month"
   - Email field (pre-filled)
   - Card input fields
4. (Do NOT complete payment in test)

**Expected Result:** Stripe checkout loads correctly

**Assertion Code:**
```javascript
// Redirected to Stripe domain (stripe.com)
// Checkout form visible with plan details
// Email pre-filled with user email
// Card input fields present
```

---

### Test 10.1.5 — Manage Subscription (Billing Portal)
**Prerequisites:** Logged in as paid user
**Steps:**
1. Go to Account settings → Billing
2. Click "Manage subscription"
3. Verify redirected to Stripe Customer Portal
4. In portal, verify:
   - Current plan: "ClassicsLens Pro"
   - Next invoice date and amount
   - Payment method on file
   - "Cancel subscription" option available

**Expected Result:** Billing portal accessible

**Assertion Code:**
```javascript
// Redirected to Stripe Customer Portal
// Portal shows current plan
// Next invoice visible
// Cancel option available
```

---

# SECTION 11: REGRESSION TESTS

## 11.1 Parser Accuracy Regressions

### Test 11.1.1 — Issue #11 Regression: mare (Correct Case Assignment)
**Prerequisites:** On Parse tab
**Steps:**
1. Enter: "mare" (neuter noun, nominative/accusative singular)
2. Press Enter
3. Verify results:
   - Nominative/Accusative singular listed ✓
   - Ablative NOT listed (should be "mari" for ablative) ✓

**Expected Result:** mare correctly parsed as nom/acc, not ablative

**Assertion Code:**
```javascript
// Results contain "Nominative" or "Nom"
// Results contain "Accusative" or "Acc"
// Results do NOT contain "Ablative" or "Abl" (for "mare" specifically)
// Paradigm shows ablative form as "mari" (not "mare")
```

---

### Test 11.1.2 — Issue #12 Regression: Particles Have Definitions
**Prerequisites:** On Parse tab
**Steps:**
1. Enter: "δη" (particle)
2. Press Enter
3. Verify results show:
   - Definition: NOT "missing definitions"
   - Definition contains meaningful text (e.g., "then", "indeed", "now")
4. Enter: "ανα"
5. Verify definition present (e.g., "up", "throughout")

**Expected Result:** Particles show short definitions (not missing)

**Assertion Code:**
```javascript
// Results for "δη" contain definition (not "missing definitions")
// Definition text is non-empty and meaningful
// Results for "ανα" also show definition
```

---

### Test 11.1.3 — Issue #10 Regression: Word Found with Correct Definitions
**Prerequisites:** On Parse tab
**Steps:**
1. Enter: "λιμῷ" (dative of hunger)
2. Verify word found (not missing)
3. Enter: "χειρών" (genitive plural of hand)
4. Verify word found
5. Enter: "μελλω" (to be about to)
6. Verify word found with definition

**Expected Result:** Previously missing words now found

**Assertion Code:**
```javascript
// "λιμῷ" parsing returns results (not "not found")
// "χειρών" parsing returns results
// "μελλω" parsing returns results with definition
```

---

---

# TEST EXECUTION SUMMARY

## Test Count by Section
- Section 1 (Auth): 6 tests
- Section 2 (Account): 4 tests
- Section 3 (Today Tab): 6 tests
- Section 4 (Review Tab): 9 tests
- Section 5 (Parse Tab): 9 tests
- Section 6 (Settings): 3 tests
- Section 7 (Navigation): 4 tests
- Section 8 (Responsive): 5 tests
- Section 9 (Errors): 6 tests
- Section 10 (Monetization): 5 tests
- Section 11 (Regression): 3 tests

**Total: 60+ test cases** (can be split into smaller suites or parallelized)

---

## Test Execution Strategy for Claude

1. **Happy Path Suite** (40 tests) — Core functionality, all users
2. **Edge Cases Suite** (10 tests) — Network, input validation, rapid interactions
3. **Monetization Suite** (5 tests) — Free tier limits, Stripe, billing (if implemented)
4. **Regression Suite** (5 tests) — Known bug fixes, parser accuracy

Claude can write test code for each suite separately and run them at different stages:
- Happy path: pre-release
- Edge cases: integration testing
- Monetization: before launch
- Regression: continuous

---

## Notes for Claude Implementation

- Use Playwright `test()` blocks with clear naming: `test('[Section] [Test Name]', ...)`
- Setup/teardown: login before each test, clear localStorage between tests
- Wait for elements with timeouts: `page.waitForSelector(', {timeout: 5000})`
- Check visibility and content, not just presence
- Mock API calls where needed (e.g., external links)
- Use data-testid attributes in React for stable selectors
- Screenshot on failure for debugging

