v0.315.0: close the log tab's <script> — the live poller was dead, and a test now says so
gates / gates (push) Failing after 49s

FOUND IN A BROWSER. The log tab's body was lifted out of the old logs.html by line range and the
range stopped one line short, so the closing </script> never came with it. Everything downstream
agreed the page was fine:

  - html/template parsed it,
  - the page rendered and looked right,
  - TestAppPage_EachTabRendersItsOwnContent found `setInterval(window.fetchLogs` exactly where it
    expected it, because the TEXT was there.

Chrome refused the whole block with "SyntaxError: Unexpected token '<'" at the `</div>` that
followed, so the live log never refreshed. A marker proves a string is present; it does not prove
the browser will execute it.

TestAppPage_ScriptTagsAreBalanced now counts <script> against </script> on all seven app-page URLs
and checks the last block is closed. Red-proved by removing the tag again: it fails naming the logs
tab, 3 opened and 2 closed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117kRTSgs3rJWUFGxyoWN6Y
This commit is contained in:
2026-10-15 19:27:21 +02:00
parent fe0228c877
commit db52f5a4cf
3 changed files with 38 additions and 0 deletions
+36
View File
@@ -583,3 +583,39 @@ func TestAppPage_EachTabRendersItsOwnContent(t *testing.T) {
}
}
}
// TestAppPage_ScriptTagsAreBalanced — every tab's rendered HTML closes every <script> it opens.
//
// THIS TEST EXISTS BECAUSE THE SUITE MISSED A DEAD PAGE. The log tab's body was lifted out of the
// old logs.html by line range and the range stopped one line short, dropping `</script>`. Go's
// html/template parsed it, the page rendered, and TestAppPage_EachTabRendersItsOwnContent found
// `setInterval(window.fetchLogs` exactly where it expected it — because the TEXT was there. The
// browser then refused the block with „SyntaxError: Unexpected token '<'" and the live log poller
// never ran. A marker proves a string is present; it does not prove the browser will execute it.
//
// RED-PROOF (REPORT.md): delete the `</script>` from app_logs.html again → this fails naming the
// logs tab. Reverted.
func TestAppPage_ScriptTagsAreBalanced(t *testing.T) {
s := appPageHarness(t)
for _, p := range []string{
"/apps/adventurelog", "/apps/adventurelog/settings", "/apps/adventurelog/data",
"/apps/adventurelog/guide", "/apps/adventurelog/logs",
"/apps/grocy", "/apps/grocy/install",
} {
body := appGet(t, s, p).Body.String()
open := strings.Count(body, "<script")
closed := strings.Count(body, "</script>")
if open != closed {
t.Errorf("%s: %d <script> opened, %d closed — an unclosed block swallows the markup after it "+
"and the browser refuses the whole thing", p, open, closed)
}
// An unclosed block shows up as page markup INSIDE the script: the first thing after the
// last statement would be a tag rather than </script>.
if i := strings.LastIndex(body, "<script"); i >= 0 {
rest := body[i:]
if j := strings.Index(rest, "</script>"); j < 0 {
t.Errorf("%s: the last <script> is never closed", p)
}
}
}
}
@@ -70,6 +70,7 @@
container.scrollTop = container.scrollHeight;
startPolling();
})();
</script>
</div>
{{template "layout_end" .}}
@@ -289,6 +289,7 @@ line two</pre>
container.scrollTop = container.scrollHeight;
startPolling();
})();
</script>
</div>