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() }