package web import ( "net/http/httptest" "strings" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/backup" "gitea.dooplex.hu/admin/felhom-controller/internal/settings" ) // v0.124.0 IA split (§10 nav/state): each backups sub-page renders ONLY its mapped sections — // a marker string per section, asserted present on its page and absent on every other page. func splitTestData() map[string]interface{} { return map[string]interface{}{ "Page": "backups", "Title": "Biztonsági mentés", "Backup": &backup.FullBackupStatus{ AppDataInfo: []backup.AppBackupInfo{{StackName: "calibre-web", DisplayName: "Calibre-Web"}}, }, "AppBackupRows": []AppBackupRow{ {StackName: "calibre-web", DisplayName: "Calibre-Web", OffboxEnabled: true, Tier3State: "active"}, }, "DBSectionState": "dumps", "Offbox": &settings.OffboxTarget{ Enabled: true, Host: "nas.local", LastStatus: "ok", EscrowState: "escrowed", }, "OffboxConfigured": true, "OffboxApps": []OffboxAppRow{{Name: "calibre-web", DisplayName: "Calibre-Web", Enabled: true}}, "OffboxToggledCount": 1, "OffboxQuotaPct": 0, "GuestBackup": map[string]interface{}{"Available": false, "Note": "n/a"}, } } func TestBackupsSplit_SectionsOnExactlyOnePage(t *testing.T) { pages := map[string]string{ "backups": renderBackupPage(t, "backups", splitTestData()), "backups_remote": renderBackupPage(t, "backups_remote", splitTestData()), "backups_apps": renderBackupPage(t, "backups_apps", splitTestData()), "backups_restore": renderBackupPage(t, "backups_restore", splitTestData()), } // marker → the ONE page it belongs to markers := map[string]string{ "Tárhely áttekintés": "backups", // Section 0 "Rendszermentés (teljes mentés)": "backups", // whole-guest ">Adatmentés<": "backups", // stat cards (neutral branch) `id="offbox-section"`: "backups_remote", // the offbox anchor target "Távoli mentési cél beállítása": "backups_remote", // manual-target form "Mely alkalmazások mentődnek": "backups_remote", // toggle list "

Ütemezés

": "backups_apps", // schedule "

Adatbázisok

": "backups_apps", // databases "Alkalmazások mentési állapota": "backups_apps", // per-app rows `id="restore-app"`: "backups_restore", // restore panel "Ellenőrző visszaállítás a távoli tárolóból": "backups_restore", // moved restore-to-verify `action="/backup/offbox/restore"`: "backups_restore", // the MOVED form itself } for marker, home := range markers { for page, html := range pages { has := strings.Contains(html, marker) if page == home && !has { t.Errorf("%s: missing its own section marker %q", page, marker) } if page != home && has { t.Errorf("%s: renders %q which belongs to %s only", page, marker, home) } } } } // The tier-3 row actions must deep-link cross-page to the offbox section (the pre-split // #offbox-section anchors would be orphaned on the apps page). func TestBackupsSplit_CrossPageAnchors(t *testing.T) { data := splitTestData() data["AppBackupRows"] = []AppBackupRow{ {StackName: "radarr", DisplayName: "Radarr", Tier3State: "off"}, } html := renderBackupPage(t, "backups_apps", data) if !strings.Contains(html, `href="/backups/remote#offbox-section"`) { t.Error("tier-3 'Bekapcsolás' must link cross-page to /backups/remote#offbox-section") } if strings.Contains(html, `href="#offbox-section"`) { t.Error("orphaned same-page #offbox-section anchor survives on the apps page") } } // Felhom-offsite status card (v0.124.0, decision 2): three honest states, display-only — // the card itself must never carry a form or button (no state change from the card, ever). func TestBackupsRemote_OffsiteStatusCardStates(t *testing.T) { cardOf := func(html string) string { i := strings.Index(html, `id="felhom-offsite-card"`) if i < 0 { return "" } j := strings.Index(html[i:], "") return html[i : i+j] } // State 1: no target configured → the opt-in pitch (and no "Aktív" headline). data := splitTestData() data["OffboxConfigured"] = false data["Offbox"] = nil data["OffboxToggledCount"] = 0 html := renderBackupPage(t, "backups_remote", data) if !strings.Contains(html, "Felhom offsite tárhely — igényelhető szolgáltatás. Titkosított, házon kívüli másolat a mentéseidről. Érdeklődj az üzemeltetőnél.") { t.Error("state 1: the opt-in pitch is missing") } if strings.Contains(html, "Aktív — nincs kijelölt alkalmazás") { t.Error("state 1 must not render the state-2 headline") } if card := cardOf(html); strings.Contains(card, "