go-tell/internal/web/theme_origin_test.go
Daniel Noulet f40485842d
Some checks failed
Build, test, and publish / Build and test (push) Has been cancelled
Build, test, and publish / Build and push Docker image (push) Has been cancelled
CI / test (push) Has been cancelled
fixing style
2026-10-07 15:10:10 +02:00

75 lines
2.6 KiB
Go

package web
import (
"strings"
"testing"
)
const shell = `<!doctype html>
<html lang="en">
<head>
<title>Urpi's backlog</title>
</head>
<body><div id="root"></div><script type="module" src="/src/main.tsx"></script></body>
</html>`
// TestThemeLinesAreAddedWhenConfigured is the whole feature: the contract reaches
// the page.
func TestThemeLinesAreAddedWhenConfigured(t *testing.T) {
got := string(applyThemeOrigin([]byte(shell), "https://bananas-dev.urpi.be"))
if !strings.Contains(got, `href="https://bananas-dev.urpi.be/rt/v1/contract.css"`) {
t.Errorf("the contract stylesheet was not added:\n%s", got)
}
if !strings.Contains(got, `src="https://bananas-dev.urpi.be/rt/v1/components.js"`) {
t.Errorf("the control module was not added:\n%s", got)
}
// Injected before </head>, so the stylesheet is parsed before the body renders. A
// contract that arrives late shows a flash of the fallback palette.
headClose := strings.Index(got, "</head>")
link := strings.Index(got, "contract.css")
if link < 0 || link > headClose {
t.Errorf("the contract link is not inside the head (link=%d, head=%d)", link, headClose)
}
// The application script must survive untouched.
if !strings.Contains(got, `src="/src/main.tsx"`) {
t.Error("the application script was altered")
}
}
func TestThemeOriginTrailingSlashIsTrimmed(t *testing.T) {
for _, base := range []string{
"https://bananas-dev.urpi.be/",
"https://bananas-dev.urpi.be///",
} {
got := string(applyThemeOrigin([]byte(shell), base))
if strings.Contains(got, "be//") {
t.Errorf("base %q produced a doubled slash:\n%s", base, got)
}
}
}
// TestNothingIsAddedWhenNoOriginIsConfigured is the branch that matters most: an
// unset or blank origin must leave the page byte-identical, because the stylesheet's
// var() fallbacks are what carry the application in that case.
func TestNothingIsAddedWhenNoOriginIsConfigured(t *testing.T) {
for _, base := range []string{"", " ", "\t", "/"} {
got := applyThemeOrigin([]byte(shell), base)
if string(got) != shell {
t.Errorf("base %q modified the shell:\n%s", base, got)
}
if strings.Contains(string(got), "rt/v1") {
t.Errorf("base %q left a contract reference behind:\n%s", base, got)
}
}
}
// TestShellWithoutHeadIsUnchanged covers a malformed shell. Returning the input
// unchanged is better than corrupting it, and better than a 500 on a page that would
// otherwise have rendered.
func TestShellWithoutHeadIsUnchanged(t *testing.T) {
odd := []byte("<html><body>no head</body></html>")
if got := applyThemeOrigin(odd, "https://bananas-dev.urpi.be"); string(got) != string(odd) {
t.Errorf("a shell with no head was modified:\n%s", got)
}
}