Skip to main content

APP_CONTEXT.md — forsyt.io Application Knowledge

Living document. Update this file whenever Claude discovers new information about the app — real selectors, confirmed flows, new pages, UI changes. This is the domain knowledge base that lets Claude write tests with minimal prompting.


What the App Is

forsyt.io is a mobile-first sports web application — likely a sports betting or live sports tracking platform. It is designed primarily for mobile browsers (402×874 viewport, matching the Figma canvas). A desktop layout also exists.

  • Live URL: https://forsyt.io
  • Primary device: Mobile (402×874, touch, is_mobile=true)
  • Browser default: Chromium (configurable via .env)
  • Auth: Session-based. Saved auth state: .auth/state.json

Known Pages

PageURLAuthStatusPage Object
Splash / Root/NoConfirmed loads (test passes)None yet
Sports Feed/sportsNoUnknown — not yet testedNone yet
Live / In-Play/liveNoUnknown — not yet testedNone yet
Login/loginNoSkeleton page object existspages/login_page.py (placeholder selectors)
Dashboard/dashboardYesSkeleton page object existspages/dashboard_page.py (placeholder selectors)
My Bets/my-betsYesNot yet testedNone yet
Account / Profile/accountYesNot yet testedNone yet
Event Detail/event/<id>NoNot yet testedNone yet
404 / Error/nonexistentNoNot yet testedNone yet

Note on placeholder selectors: login_page.py and dashboard_page.py use [data-testid='...'] selectors that do not yet correspond to real elements in the live app. Tests using these page objects will fail until real selectors are discovered and updated.


UI Structure — From Figma Analysis

Splash Screen (Figma node 837:22442)

  • Viewport: 402×874 (iPhone-sized)
  • Background: Dark/solid colour
  • Centre: forsyt.io logo (logo_white2) — white logo centred vertically and horizontally
  • Top: iPhone-style Status Bar (iPhone / Status Bar) — time, signal, battery indicators
  • Bottom: Navigation bar frame is present in the DOM but hidden on the splash screen
  • Behaviour: Transitions to the main app automatically or via user action

Key Figma nodes observed:

837:22442  → Splash Screen frame (root)
837:22443 → iPhone / Status Bar
837:22465 → Logo group (logo_white2 1)
837:22467 → Frame 43474 — bottom nav (hidden="true" on splash)

Bottom Navigation Bar (Mobile)

Observed from Figma node 837:22467 (hidden on splash, visible on other pages):

  • 5 navigation slots (icon + optional label each)
  • Tab 1: Sports — has icon + text label "Sports"
  • Tabs 2–5: Icons only (no labels confirmed yet)
  • Notification badge: Visible on at least one tab — shows number "2" (Figma node 837:22497)
  • Structure: Horizontal bar pinned to bottom of screen
  • Touch targets: Must be ≥ 44×44px each
Frame 43474 (bottom nav root)
├── Frame 43473 → Sports tab (icon + "Sports" label)
│ ├── Frame (icon slot)
│ └── Text "Sports"
├── Frame (tab 2 icon)
├── Frame (tab 3 icon)
├── Frame (tab 4 icon)
├── Frame (tab 5 icon)
└── Frame 43474 → badge container → Text "2"

Status Bar (Mobile)

  • Present at top of every screen
  • Contains: left side (time display), right side (signal, wifi, battery icons)
  • Height: ~44px
  • Content below must not overlap with the status bar

Known User Flows

Flow 1: App Entry (Splash → Home)

User opens forsyt.io
→ Splash screen appears (logo visible, status bar visible, bottom nav hidden)
→ Auto-transition OR user taps to continue
→ Lands on Sports Feed / Home
→ Bottom nav becomes visible

Flow 2: Tab Navigation (Mobile)

User is on Sports Feed
→ Taps "Live" tab in bottom nav
→ Live / In-Play page loads
→ Active tab indicator moves to "Live"

User taps "My Bets" tab
→ If authenticated → My Bets page loads
→ If not authenticated → Redirected to Login

Flow 3: Login

User arrives at /login (directly or via redirect)
→ Email field visible
→ Password field visible
→ Submit button visible
→ User enters credentials → taps submit
→ Valid credentials → redirects to main app (dashboard or sports feed)
→ Invalid credentials → error banner appears, stays on login page
→ Empty form submit → field-level validation shown

Flow 4: Protected Page Access (Unauthenticated)

User navigates to /my-bets or /account without being logged in
→ App redirects to /login

Flow 5: Event Navigation

User is on Sports Feed
→ Sees list of event cards (teams, odds, time/status)
→ Taps an event card
→ Event detail page loads (match info, full odds)
→ Taps browser back
→ Returns to Sports Feed at the same scroll position

UI Patterns Confirmed / Observed

PatternWhereNotes
Logo centred on dark backgroundSplashWhite logo, logo_white2
iPhone status barAll pages (mobile)Time + icons, ~44px height
Bottom nav — 5 tabsAll pages except Splash (mobile)Tab 1 = Sports confirmed
Notification badgeBottom navShows "2" in Figma
Event cards with oddsSports FeedTeams + 2+ odds values + time
Loading spinnerAny data pageAppears during fetch, disappears when ready
Error bannerLogin, form pagesAppears inline on bad credentials
Field validationLogin formAppears on empty submit

Confirmed Selectors

Selectors are confirmed only once tested against the live site. Do not use unconfirmed selectors in tests. Mark them with # UNCONFIRMED until verified.

ElementSelectorStatusPage object location
(none confirmed yet)

When a selector is discovered from the live site (via browser DevTools, Playwright inspector, or a passing test), add it to the table above AND update the corresponding page object.


Placeholder Selectors (Not Yet Verified)

These exist in the codebase but are not confirmed to work on the live site:

SelectorUsed inLikely real?
[data-testid='username-input']pages/login_page.pyUnknown
[data-testid='password-input']pages/login_page.pyUnknown
[data-testid='login-submit']pages/login_page.pyUnknown
[data-testid='login-error']pages/login_page.pyUnknown
h1[data-testid='login-heading']pages/login_page.pyUnknown
h1[data-testid='dashboard-heading']pages/dashboard_page.pyUnknown
[data-testid='welcome-message']pages/dashboard_page.pyUnknown
[data-testid='stats-card']pages/dashboard_page.pyUnknown
nav[role='navigation']components/navbar.pyUnknown

How to Discover Real Selectors

When the user asks to implement a test for a page with no confirmed selectors:

  1. Flag it clearly — state that selectors are unknown and tests will be skeletons
  2. Use the most stable selector strategy — prefer data-testid, then ARIA role, then text
  3. Mark unconfirmed selectors with # UNCONFIRMED — update after live site inspection
  4. Update this file once selectors are confirmed from a passing test or DevTools inspection

To inspect selectors on the live site:

# Launch Playwright inspector on forsyt.io
HEADLESS=false python -c "
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
b = p.chromium.launch(headless=False)
ctx = b.new_context(viewport={'width':402,'height':874}, is_mobile=True)
page = ctx.new_page()
page.goto('https://forsyt.io')
page.pause() # opens Playwright Inspector
"

What Claude Should Infer from This Document

  • If asked to "add a test for the bottom nav" → bottom nav has 5 tabs, tab 1 is Sports, one tab has badge "2", hidden on splash screen
  • If asked to "add a test for the splash screen" → check logo visibility, check status bar, check bottom nav is hidden, check no console errors
  • If asked about selectors → assume data-testid attributes exist (common pattern), but mark as unconfirmed until a test passes
  • If asked to "add a smoke test for any page" → page load + key element visible + no console errors is the minimum smoke set
  • If told "the selector is X" → update the page object _PRIVATE_CONSTANT and this file's Confirmed Selectors table