diff --git a/Makefile b/Makefile index a7cd8ea..cdc2216 100644 --- a/Makefile +++ b/Makefile @@ -72,8 +72,13 @@ test-list: ## Show test counts by marker test-stats: @echo "=== Test counts by marker ===" - @$(PYTEST) --collect-only -q -m unit 2>/dev/null | grep -c "test" || echo "0" + @$(PYTEST) --collect-only -q -m unit 2>/dev/null | tail -1 @echo "^ unit tests" - @$(PYTEST) --collect-only -q -m integration 2>/dev/null | grep -c "test" || echo "0" + @$(PYTEST) --collect-only -q -m integration 2>/dev/null | tail -1 @echo "^ integration tests" + @$(PYTEST) --collect-only -q -m e2e 2>/dev/null | tail -1 + @echo "^ e2e tests" + @$(PYTEST) --collect-only -q -m "not unit and not integration and not e2e" 2>/dev/null | tail -1 + @echo "^ ORPHAN tests (tanpa marker) — harus 0, unit + integration == total" @$(PYTEST) --collect-only -q 2>/dev/null | tail -1 + @echo "^ total collected" diff --git a/README.md b/README.md index c474739..a70b9d2 100644 --- a/README.md +++ b/README.md @@ -493,14 +493,20 @@ student_id;token;nama_siswa;hello_world;variabel || `./elemes.sh test` | Full test suite (alias ke `test-all`) | || `./elemes.sh test-unit` | Unit test saja (cepat, no DB) | || `./elemes.sh test-integration` | Integration test (butuh PostgreSQL `elemes_test`) | -|| `./elemes.sh test-all` | Full test suite (CI gate) | +|| `./elemes.sh test-all` | Full test suite | || `./elemes.sh test-smoke` | Smoke test post-deploy (unit + sub-home subset) | || `./elemes.sh docs-validate` | Validasi frontmatter & broken link di `docs/*.md` | +> **Catatan testing (CI):** CI otomatis (GitHub Actions) **belum diaktifkan** — +> solo dev, test dijalankan manual sebelum push via +> `make test-unit && make test-integration` (atau `./elemes.sh test-all`). +> Rencana diaktifkan lagi saat ada kontributor lain; file `ci.yml` versi lama +> tetap tersimpan di git history (`git show a5aedf6:.github/workflows/ci.yml`). + ## Dokumentasi & Referensi API - **Docs Viewer**: Buka `http://localhost:3000/docs` untuk panduan teknis lengkap (arsitektur, backend, frontend, kuis, velxio, embed, dll) yang merender file `docs/*.md` secara dinamis. -- **API Reference**: `http://localhost:3000/docs/api-reference` menampilkan daftar semua endpoint Flask dengan docstring, metode, path, dan requirement auth. +- **API Reference**: Buka `/docs` lalu klik **API Reference** di sidebar (entry pertama) untuk melihat daftar semua endpoint Flask dengan docstring, metode, path, dan requirement auth. - **Troubleshooting**: Buka `http://localhost:3000/help` untuk tutorial siswa; tautan ke Docs Viewer ada di sana. ## Database & Penyimpanan (PostgreSQL) diff --git a/frontend/src/lib/types/docs.ts b/frontend/src/lib/types/docs.ts index f87da8b..25a6e6f 100644 --- a/frontend/src/lib/types/docs.ts +++ b/frontend/src/lib/types/docs.ts @@ -17,3 +17,16 @@ export interface DocMeta { order: number; category: string; } + +/** Satu entry dari GET /api/docs/api-reference. */ +export interface ApiReferenceEntry { + method: string[]; + path: string; + name: string; + auth: boolean; + doc: string; +} + +export interface ApiReferenceResponse { + endpoints: ApiReferenceEntry[]; +} diff --git a/frontend/src/routes/docs/+page.svelte b/frontend/src/routes/docs/+page.svelte index 665a26e..38bbad8 100644 --- a/frontend/src/routes/docs/+page.svelte +++ b/frontend/src/routes/docs/+page.svelte @@ -2,6 +2,7 @@ import { env } from '$env/dynamic/public'; import { renderMath } from '$lib/actions/renderMath'; import { tick } from 'svelte'; + import type { ApiReferenceEntry } from '$types/docs'; export let data: { docs: import('$types/docs').DocsIndexEntry[] @@ -12,11 +13,16 @@ let docContent: { title: string; html: string } | null = null; let docError = false; + let apiRefMode = false; + let apiRefEntries: ApiReferenceEntry[] | null = null; + let apiRefError = false; + $: filteredDocs = data.docs.filter(d => d.title.toLowerCase().includes(searchQuery.toLowerCase()) ); async function selectDoc(doc: import('$types/docs').DocsIndexEntry) { + apiRefMode = false; selectedDoc = doc; searchQuery = ''; docError = false; @@ -30,10 +36,29 @@ docError = true; } } + + async function selectApiReference() { + apiRefMode = true; + selectedDoc = data.docs[0]; + searchQuery = ''; + docError = false; + docContent = null; + + if (apiRefEntries) return; // sudah pernah dimuat — reuse + apiRefError = false; + try { + const res = await fetch('/api/docs/api-reference'); + if (!res.ok) throw new Error('Failed to load API reference'); + const payload = await res.json(); + apiRefEntries = payload.endpoints; + } catch { + apiRefError = true; + } + } - {selectedDoc?.title || 'Dokumentasi'} - Elemes LMS + {apiRefMode ? 'API Reference' : selectedDoc?.title || 'Dokumentasi'} - Elemes LMS
@@ -47,9 +72,18 @@ />