# 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
```