# QA Test Report — Production **Date:** 2026-06-24 06:31:44 **URL:** https://falahos.my/mobile ## Summary | ✅ Pass | ❌ Fail | ⚠️ Warn | Total | Grade | |:------:|:------:|:------:|:----:|:-----:| | 94 | 4 | 9 | 107 | **C** | ## Details | Result | Message | |:------|:--------| | ✅ | Landing page (/) → 200 in 209ms | | ✅ | Learn catalog page (/learn) → 200 in 109ms | | ✅ | Certificate verification (/verify/ABC123) → 200 in 114ms | | ✅ | Health API (/api/health) → 200 in 67ms | | ✅ | Learn courses API (/api/learn/courses) → 200 in 106ms | | ✅ | Course detail (no auth) (/api/learn/courses/atomic-habits) → 401 in 114ms | | ✅ | /this-does-not-exist → 404 | | ✅ | /api/nonexistent → 404 | | ⚠️ | /learn/nonexistent-route → 200 (expected 404) | | ✅ | Health API — status=ok, db=True, uptime=1991s | | ✅ | Courses API — 1 course(s) returned | | ✅ | Course #0: 'Atomic Habits' by James Clear — 5 modules, 25min, beginner | | ✅ | Course detail without auth → 401 (correct) | | ✅ | Course detail — 'Atomic Habits', 5 modules | | ✅ | Course detail — 5 module(s) with content+quiz | | ✅ | Module #1: 'The 1% Rule' — 5min, 3 quiz Qs | | ✅ | Module #2: 'Identity-Based Habits' — 5min, 2 quiz Qs | | ✅ | Module #3: 'The 4 Laws of Behavior Change' — 5min, 2 quiz Qs | | ✅ | Module #4: 'Habit Stacking' — 5min, 1 quiz Qs | | ✅ | Module #5: 'Design Your Environment' — 5min, 2 quiz Qs | | ✅ | Verify page — 200 OK | | ✅ | Verify — JSON response: None | | ✅ | Landing (/) — clean (13749B) | | ✅ | Landing (/) — contains "Falah" | | ❌ | Landing (/) — MISSING "Assalamualaikum" | | ✅ | Learn Catalog (/learn) — clean (14195B) | | ✅ | Learn Catalog (/learn) — contains "Learn" | | ❌ | Learn Catalog (/learn) — MISSING "Course" | | ❌ | Verify Certificate (/verify/ABC123) — ERROR in HTML: ['not found'] | | ✅ | Verify Certificate (/verify/ABC123) — contains "Verify" | | ✅ | Verify Certificate (/verify/ABC123) — contains "Certificate" | | ✅ | Pattern "Invalid response" — absent | | ✅ | Pattern "Internal Server Error" — absent | | ✅ | Pattern "Application error" — absent | | ✅ | Pattern "Cannot read properties of" — absent | | ✅ | Pattern "undefined is not" — absent | | ✅ | Pattern "TypeError" — absent | | ✅ | Pattern "Failed to fetch" — absent | | ✅ | Pattern "500 Internal" — absent | | ✅ | Pattern "JSON Parse error" — absent | | ✅ | Pattern "Unexpected token" — absent | | ✅ | Pattern "Cannot find module" — absent | | ✅ | Pattern "Minified React error" — absent | | ❌ | Pattern "not found" on: /verify/ABC123 | | ✅ | Unauthenticated / — accessible | | ⚠️ | Unauthenticated /learn → 503 | | ✅ | Login — obtained token (eyJhbGciOiJIUzI1...6SI4) | | ✅ | Courses listed — Atomic Habits (slug: atomic-habits) | | ✅ | Course detail loaded — 5 module(s) | | ✅ | Module: 'The 1% Rule' — 5min, quiz: 3 Qs | | ✅ | Module: 'Identity-Based Habits' — 5min, quiz: 2 Qs | | ✅ | Module: 'The 4 Laws of Behavior Change' — 5min, quiz: 2 Qs | | ✅ | Module: 'Habit Stacking' — 5min, quiz: 1 Qs | | ✅ | Module: 'Design Your Environment' — 5min, quiz: 2 Qs | | ✅ | Certificate verification page loads | | ✅ | api/learn/courses/atomic-habits with bad token → 401 (graceful) | | ⚠️ | SQLi on api/learn/courses/' OR 1=1-- → 0 | | ⚠️ | SQLi on learn/' OR 1=1-- → 0 | | ⚠️ | SQLi on api/learn/courses/'; DROP TABLE courses;-- → 0 | | ⚠️ | SQLi on learn/'; DROP TABLE courses;-- → 0 | | ⚠️ | SQLi on api/learn/courses/" OR "1"="1 → 0 | | ⚠️ | SQLi on learn/" OR "1"="1 → 0 | | ✅ | Path traversal '../../../etc/passwd' → 404 | | ✅ | Path traversal '..%2F..%2F..%2Fetc%2Fpasswd' → 401 | | ✅ | Verify code '' → 404 | | ✅ | Verify code 'INVALID!@#$' → 200 | | ✅ | Verify code 'aaaaaaaaaaaaaaaaaaaa' → 200 | | ✅ | Burst — 10/10 OK (avg 120ms, total 0.2s) | | ✅ | / — viewport meta present | | ✅ | /learn — viewport meta present | | ✅ | /verify/ABC123 — viewport meta present | | ✅ | / — safe-area inset detected | | ✅ | /learn — safe-area inset detected | | ✅ | /verify/ABC123 — safe-area inset detected | | ✅ | / — dark theme detected | | ✅ | /learn — dark theme detected | | ✅ | /verify/ABC123 — dark theme detected | | ✅ | / — responsive container detected | | ✅ | /learn — responsive container detected | | ✅ | /verify/ABC123 — responsive container detected | | ✅ | Landing page (/) — cold=101ms warm=93ms, 13KB | | ✅ | Learn catalog (/learn) — cold=50ms warm=45ms, 14KB | | ✅ | Health API (/api/health) — cold=52ms warm=52ms, 0KB | | ✅ | Courses API (/api/learn/courses) — cold=54ms warm=77ms, 0KB | | ✅ | / — no JWT token leak | | ✅ | / — no API key leak | | ✅ | / — no GitHub PAT leak | | ✅ | / — no Private key leak | | ✅ | /learn — no JWT token leak | | ✅ | /learn — no API key leak | | ✅ | /learn — no GitHub PAT leak | | ✅ | /learn — no Private key leak | | ✅ | /verify/ABC123 — no JWT token leak | | ✅ | /verify/ABC123 — no API key leak | | ✅ | /verify/ABC123 — no GitHub PAT leak | | ✅ | /verify/ABC123 — no Private key leak | | ✅ | Content-Type: text/html; charset=utf-8 | | ✅ | X-Content-Type-Options: nosniff | | ✅ | Learn page — HTTP 200 (Playwright) | | ✅ | Learn page — no JS console errors | | ⚠️ | Learn page — may be empty/loading (text not found) | | ✅ | Learn page — title: Falah — Islamic Lifestyle | | ✅ | Learn page — loaded with auth (Playwright) | | ✅ | Learn page — course content visible after auth | | ✅ | Auth token persists in localStorage | | ✅ | Verify page — HTTP 200 (Playwright) | | ✅ | Verify page — 159 chars rendered | ## Re-run ```bash /usr/bin/python3.12 /root/falah-mobile/tests/qa-learn-prod.py ```