package web import ( "bytes" "encoding/json" "io" "log" "net/http/httptest" "path/filepath" "strconv" "strings" "testing" "time" "gitea.dooplex.hu/admin/felhom-hub/internal/store" ) func newRenderServer(t *testing.T) (*Server, *store.Store) { t.Helper() st, err := store.New(filepath.Join(t.TempDir(), "render.db"), log.New(io.Discard, "", 0)) if err != nil { t.Fatalf("store.New: %v", err) } t.Cleanup(func() { st.Close() }) return New(st, "", "", "test", time.Hour, log.New(io.Discard, "", 0)), st } // Part A + H UI — the expanded issue row renders the FULL message in a copyable
,
// the context block with provenance, the explicit affected-customers list, the dismissal
// controls, and the customer-filter header.
func TestAppDetail_ExpandableIssueRender(t *testing.T) {
s, _ := newRenderServer(t)
fullMsg := "ERROR: nfs mount /mnt/media lost — stale file handle on /mnt/media/books (retry 5/5, giving up)"
dismissed := time.Now()
data := map[string]interface{}{
"AppName": "cwa",
"Issues": []store.AppIssue{
{
ID: 7, AppName: "cwa", Fingerprint: "error: nfs mount lost", Severity: "error",
Message: fullMsg, FirstSeen: time.Now().Add(-48 * time.Hour), LastSeen: time.Now(),
OccurrenceCount: 42,
AffectedCustomers: []string{"cust-a", "cust-b"},
Context: []string{"line before", fullMsg, "line after"},
ContextCustomer: "cust-a",
},
{
ID: 8, AppName: "cwa", Fingerprint: "warn: slow", Severity: "warn",
Message: "WARN: slow disk", FirstSeen: time.Now(), LastSeen: time.Now(),
OccurrenceCount: 1, AffectedCustomers: []string{"cust-a"},
DismissedAt: &dismissed,
},
},
"ChartData": ChartData{},
"Period": "24h",
"CustomerFilter": "cust-a",
"ShowDismissed": true,
"CSRFToken": "tok",
"Flash": "",
}
var buf bytes.Buffer
if err := s.templates.ExecuteTemplate(&buf, "app_detail.html", data); err != nil {
t.Fatalf("render app_detail.html: %v", err)
}
body := buf.String()
for _, want := range []string{
fullMsg, // full message, not tooltip-only
`id="issue-msg-7"`, // copyable target
`id="issue-ctx-7"`, // context block target
"Copy", // copy buttons
"Context around first occurrence", // context label
`/customers/cust-a`, // provenance link
"line before", // context content
"filtered: cust-a", // Part H header
"Occurrences (all customers)", // fleet-total label
"Dismiss Selected", // Part G buttons
"Dismiss All Issues", //
"/apps/cwa/dismiss-issues", // dismissal route
">dismissed<", // dismissed badge on row 8
`,