Test¶
AdaptiveLearner'ın test disiplini, her değişiklikte make test
tarafından uygulanır. Strateji bir piramittir: tabanda birim
testleri, ortada entegrasyon, üstte E2E duman testleri.
Test sayıları¶
| Katman | Sayı | Araç |
|---|---|---|
| Arka uç birim + entegrasyon | 786 | pytest ^9 |
| Eklenti testleri (10 eklenti) | 615 | pytest ^9 |
| Frontend birim + entegrasyon | 1233 | Vitest 4 |
| E2E duman | 16 dosya | Playwright |
Toplam (make test) |
2634 |
Eklenti dağılımı: assessment 110 + ai-anthropic 34 + ai-openai 31 + ai-gemini 33 + session 215 + tracking 64 + tools 58 + gamification 23 + anki 20 + notebooklm 27.
Arka uç pytest¶
make test-backend # 786 test, ~35s
cd backend && poetry run pytest -k "test_session" -v
cd backend && poetry run pytest --pdb
Testler backend/tests/ dizininde bulunur. conftest.py
içindeki fikstürler test başına taze bir bellek içi SQLite veritabanı,
TestClient ve sahte bir eklenti yöneticisi sağlar. Test izolasyonu
katıdır - herhangi bir app.* içe aktarımından önce
ADAPTIVE_LEARNER_TEST=1 ayarlanır.
Eklenti testleri¶
Her eklentinin kendi tests/ dizini vardır:
make test-plugins # tümü
make test-plugin-session # yalnızca biri
cd plugins/adaptive-learner-plugin-session && poetry run pytest
Eklenti testleri FastAPI uygulamasını yüklemez - eklentinin
modüllerini izole olarak test eder. Hook tetiklemeyi test ederken
pluggy.PluginManager'ı sahte yapın.
Frontend Vitest¶
make test-frontend # 387 test, ~2s
cd frontend && bunx vitest # izleme modu
cd frontend && bunx vitest run src/storage/ # tek dizin
Testler kaynakla birlikte yaşar: Component.tsx yanında
Component.test.tsx. Ortam happy-dom'dur; React 19 + RTL.
Sahte desenler¶
AI sağlayıcıları: global.fetch'i sahte yapın ve URL,
başlıklar, gövde üzerinde iddia edin:
beforeEach(() => {
global.fetch = vi.fn(async (input, init) => {
calls.push({url, method, body});
return new Response(JSON.stringify({content: [{type: "text", text: "hi"}]}), {status: 200});
});
});
fake-indexeddb: her Dexie test dosyasının başında:
import "fake-indexeddb/auto";
beforeEach(async () => {
await _resetDbForTests();
const {IDBFactory} = await import("fake-indexeddb");
(globalThis as unknown as {indexedDB: IDBFactory}).indexedDB = new IDBFactory();
});
Her test taze bir bellek içi IndexedDB alır - sızıntı yok.
api/client.ts sahte yapıları (eski sayfalar):
vi.mock("../api/client", async () => {
const actual = await vi.importActual<typeof import("../api/client")>("../api/client");
return {...actual, api: {...actual.api, users: {...actual.api.users, get: apiGetMock}}};
});
Sayfa getStorage()'ı içe aktarır, bu ApiStorage'a, o da api.*'a
devretir. Sahte yapı api.* katmanında keser ve depolama yığını
üzerinden hâlâ tetiklenir.
Playwright E2E¶
cd e2e && npx playwright test
cd e2e && npx playwright test --ui # etkileşimli
cd e2e && npx playwright test smoke/mobile-viewports.spec.ts
Duman testleri kritik kullanıcı yollarını kapsar:
- Açılış dil seçici + başlangıç formu
- Değerlendirme 12 soru + radar oluşturma
- Oturum başlatma + bitirme + puanlama
- Ayarlar dil + API anahtarı
- Müfredat oluşturma
- Mobil görünüm alanları (iPhone SE, iPhone 14, Pixel 7, iPad)
Testler yalnızca data-testid seçicileri kullanır - kırılgan CSS
seçicileri yok. Duman testleri make test yolunda değildir;
çalışan bir uygulama gerektirir (önce make dev-bg çalıştırın).
Kapsam¶
Kapsam, main'e her push'ta CI'da çalışır; artefaktları indirin:
.claude/rules/quality-checks.md başına hedefler:
- Servisler + iş mantığı: min %95
- API uç noktaları: min %90
- Mantıklı frontend bileşenleri: min %85
- Hook'lar + yardımcılar: min %95
Genel: proje genelinde %85-95.
Ön teslim¶
Kancalar: ruff check (otomatik düzeltme), ruff format, sondaki boşluk, dosya sonu düzeltici, check-yaml, check-merge-conflict. Yalnızca arka uç - frontend lint, ön teslimde değil CI zamanında çalışır.
CI¶
CI iki katmana ayrılır: doğruluk kapıları her PR'de çalışır (merge için geçmeleri zorunludur); pahalı ya da yalnızca uyarı veren takımlar gece vardiyasında ve release zamanında çalışır.
.github/workflows/ci.yml, develop / main dallarına push'ta ve
her PR'de çalışır (Python 3.12):
- Arka uç testleri (pytest)
- Eklenti testleri (
make test-plugins, arka uç venv'i üzerinden 13'ünün tümü) - Frontend:
tsc --noEmit, ESLint (--max-warnings 0), döngüsel bağımlılık denetimi, Stylelint, Vitest,vite build,npm audit - Tüm dosyalarda pre-commit kancaları
- Arka uç ruff + mypy + pip-audit
- Dokümantasyon sapma doğrulayıcısı (
verify_docs.py+ mkdocs-nav eşitlemesi)
Test Impact Analysis (#615): bir PR'de yalnızca etkilenen
testler çalışır - vitest run --changed origin/<base> ve
pytest --testmon. develop / main push'ları, gece koşuları ve
release koşuları her zaman TAM takımı çalıştırır. Tam takıma geri
dönüş otomatiktir (çözülemeyen base ref'i ya da testmon önbellek
kaçırması).
Diğer PR kapıları kendi workflow'larında yaşar:
complexity-check.yml- karmaşıklık ratchet kapısı (make check-complexity-gate, Python için radon + TS için ESLint complexity). Bir baseline ratchet'idir: yalnızca.complexity-baselinekarşısında YENİ ya da gerileyen ihlallerde başarısız olur; böylece var olan borcun topluca temizlenmesini zorlamadan yeni karmaşıklığı engeller. Yalnızca uyarı veren tam karmaşıklık raporu gece çalışır.cohesion-check.yml- dosya boyutu koruması (.filesize-whitelistkarşısında kapı) artı iki sınıf adı kapısı: ölü CSS sınıf adları (check-dead-classnames.py,.dead-classnames-baselinekarşısında) ve stillenmemiş className kapısı (--unstyled,.unstyled-classnames-baselinekarşısında bir ratchet) - tüm token'ları ölü olan birclassNamePR'ı engeller. Eşlik eden klasör boyutu koruması yereldemake check-folder-sizeile çalışır.visual-baseline-gate.yml- görsel açıdan kritik yolları (ders bileşenleri, alıştırma renderer'ları, tema/CSS dosyaları) değiştiren bir PR, etkilenen baseline ekran görüntülerini aynı PR'de getirmek zorundadır; kanıtlanabilir şekilde etkisiz değişiklikler için kaçış etiketivisual-baselines-unaffected.testid-reference-gate.yml- bir PR, bir E2E spec'inin statik olarak referans verdiği birdata-testid'yi (kullanıcıya çok görünür bir yüzeyde) spec'e dokunmadan kaldırır ya da yeniden adlandırırsa kapı başarısız olur (make check-testid-refs); kaçış etiketitestid-refs-unaffected.docker-build-smoke.yml- üretim compose imajlarının yalnızca build içeren duman testi (launcher / install.sh yolu), PR'lerde yol filtreli, ayrıcarelease/**üzerinde, haftalık ve manuel tetiklemeyle; yereldemake docker-build-smoke.
Gece vardiyası / release (PR'lerde değil):
dexie-smoke.yml- Dexie modu E2E kapısı (günlük +release/**üzerinde + manuel tetikleme; yereldemake test-dexie-smoke)coverage.yml- kapsam raporu (günlük + manuel tetikleme)security-scan.yml- pip-audit / npm audit / bandit (haftalık +release/**üzerinde + manuel tetikleme; yalnızca uyarı)content-stats.yml- taze bir içerik checkout'una karşı içerik istatistikleri sapması (günlük + manuel tetikleme)mutation-frontend.yml- Stryker mutasyon testleri (gecelik,ENABLE_NIGHTLY_MUTATIONrepo değişkeninin arkasında + manuel tetikleme; her çalıştırma, iş zaman sınırına sığmak için dosyaların bir dilimini mutasyona uğratır); arka uç mutasyon testleri mutmut kullanırwebkit-gate.yml- gerçek WebKit motoruyla çalışan yerleşim kapısı (Chromium kapılarının yapısal olarak göremediği iOS/Safari hata sınıfları), günlük olarakENABLE_NIGHTLY_WEBKITrepo değişkeninin arkasında,release/**üzerinde ve manuel tetiklemede her zamanvisual-regression.yml- görsel baseline matrisi (günlük + manuel tetikleme;update_baselines=true, baseline'ları CI'da yeniden render eder ve artefakt olarak yükler)visual-baseline-sync.yml- servis workflow'u: baseline'ları CI'da render eder ve PR dalına bir commit olarak push'lar (refresh-visual-baselinesetiketi ya da PR numarasıyla manuel tetikleme) - merge öncesi görsel inceleme zorunlu kalır
.github/workflows/release-gate.yml, etiket push'larında çalışır:
sürüm pinlerinin sürüm taşıyan tüm dosyalarda eşitlendiğini (sapma
yok), eklenti kilit dosyalarının eşleştiğini ve yeniden üretilen
artefaktların güncel olduğunu doğrular.