package web
import (
"regexp"
"strings"
"testing"
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
)
// R-563 — the Távoli mentés page starts its progress poll from a MACHINE-READABLE status, not from
// the word it happens to display.
//
// Until v0.251.0 the page did `v.textContent.indexOf('Fut') >= 0`. Two consequences, both measured:
// the English page (slice 1 shipped it) could never see a running backup, because the English word is
// „Running…"; and the Hungarian word could not be translated at all while that line existed — it was
// the ONE word slice 1 had to leave behind.
//
// RED-PROOF (REPORT): put the textContent test back in backups_remote.html and the English half fails.
func TestR563_PollStartsFromAttribute(t *testing.T) {
statusEl := regexp.MustCompile(`
]*)>([^<]*)
`)
for _, lang := range []string{"hu", "en"} {
data := appRowSplitData()
data["Offbox"] = &settings.OffboxTarget{
Enabled: true, Host: "nas.local", LastStatus: "running", EscrowState: "escrowed",
}
html := renderBackupPageLang(t, lang, "backups_remote", data)
m := statusEl.FindStringSubmatch(html)
if m == nil {
t.Fatalf("[%s] the status element is gone — this test no longer reads what it thinks it reads", lang)
}
if !strings.Contains(m[1], `data-status="running"`) {
t.Errorf("[%s] the status element carries no machine-readable status: %q", lang, m[1])
}
if !strings.Contains(html, "v.dataset.status === 'running'") {
t.Errorf("[%s] the poll does not read the attribute", lang)
}
if strings.Contains(html, "textContent.indexOf('Fut')") {
t.Errorf("[%s] the poll reads the displayed Hungarian word again (R-563)", lang)
}
// The displayed word itself: Hungarian as always, English on the English page. Before this
// change the English page showed the Hungarian word here, because it could not be translated.
word := strings.TrimSpace(m[2])
want := map[string]string{"hu": "Fut…", "en": "Running…"}[lang]
if word != want {
t.Errorf("[%s] status label = %q, want %q", lang, word, want)
}
}
}
// A state that is NOT running must not claim to be: the attribute follows LastStatus exactly, so the
// poll cannot be started by a word that merely contains another.
func TestR563_AttributeFollowsTheStatus(t *testing.T) {
statusEl := regexp.MustCompile(`id="offbox-status-value" data-status="([a-z]*)"`)
for _, st := range []string{"ok", "error", "incomplete", "running"} {
data := appRowSplitData()
data["Offbox"] = &settings.OffboxTarget{Enabled: true, Host: "nas.local", LastStatus: st, EscrowState: "escrowed"}
html := renderBackupPage(t, "backups_remote", data)
m := statusEl.FindStringSubmatch(html)
if m == nil {
t.Fatalf("[%s] no data-status attribute on the status element", st)
}
if m[1] != st {
t.Errorf("[%s] data-status = %q — the poll would read the wrong state", st, m[1])
}
}
}
// renderBackupPageLang renders a backup page from a chosen language's template set (R-563 needs the
// English page: it is the one that could never see a running backup).
func renderBackupPageLang(t *testing.T, lang, page string, data map[string]interface{}) string {
t.Helper()
s := testServer(t)
s.loadTemplates()
var buf strings.Builder
if err := s.templatesFor(lang).ExecuteTemplate(&buf, page, data); err != nil {
t.Fatalf("render %s [%s]: %v", page, lang, err)
}
return buf.String()
}