Skip to content
quarry Artifact [c641ae2953]
Login

Artifact [c641ae2953]

Artifact c641ae295386adf0635c93ffb76701de55f3074722c6ae693bf746655587200e:


package web

import (
	"strings"
	"testing"
)

// The stylesheet is served, not inlined. It used to be 112,118 bytes of
// <style> in every response — 40% of a 309,584-byte timeline page,
// byte-identical each time and uncacheable because it had no URL.
func TestSheetIsLinkedNotInlined(t *testing.T) {
	if strings.Contains(baseHTML, "<style>") {
		t.Error("the page still inlines a stylesheet")
	}
	if !strings.Contains(baseHTML, `rel="stylesheet"`) {
		t.Error("the page does not link a stylesheet")
	}
	if len(sheet) < 50_000 {
		t.Errorf("the sheet is %d bytes; the rules did not come with it", len(sheet))
	}
}

// Both themes have to survive being moved out of the page — the whole
// two-theme story lives in this one file, and chroma's half of it is
// generated at startup rather than written down.
func TestSheetCarriesBothThemes(t *testing.T) {
	for _, want := range []string{
		"prefers-color-scheme: dark",
		`:root[data-theme="dark"]`,
		"--fg:", "--bg:", "--accent:",
		".chroma",
	} {
		if !strings.Contains(sheet, want) {
			t.Errorf("the sheet is missing %q", want)
		}
	}
}

// The URL carries a content hash so it can be served immutable: a rule
// change mints a new URL rather than asking anyone to revalidate.
func TestSheetURLIsContentAddressed(t *testing.T) {
	if !strings.HasPrefix(sheetURL, "/assets/quarry.") || !strings.HasSuffix(sheetURL, ".css") {
		t.Fatalf("sheetURL = %q", sheetURL)
	}
	if h := sheetHash(); !strings.Contains(sheetURL, h) {
		t.Errorf("sheetURL %q does not carry the hash %q", sheetURL, h)
	}
	// Same content, same hash — the URL must be stable across a
	// restart or every deploy busts every reader's cache for nothing.
	if sheetHash() != sheetHash() {
		t.Error("the hash is not stable for identical content")
	}
}

// No page may carry its own <style> element.
//
// The strict CSP is style-src 'self' with no nonce for style elements —
// style-src-attr covers the style="" attribute and nothing else — so a
// <style> block in a template is kept in the DOM, given no sheet, and
// applied to nothing. It fails silently: no console error a reader
// would notice, no failing test, just a page rendering unstyled.
//
// It happened. Chat and the inbox each carried one, and shipped
// unstyled from the day the CSP landed until somebody looked: the chat
// log rendered as a numbered list because .chatlog's list-style never
// arrived. Every test asserted the rules were in the HTML, which they
// were, and none asserted they were anywhere a browser would read them.
func TestNoTemplateCarriesItsOwnStyleElement(t *testing.T) {
	if n := strings.Count(baseHTML, "<style"); n > 0 {
		t.Errorf("base carries %d <style> elements; the CSP drops them", n)
	}
	for _, src := range []struct{ name, body string }{
		{"chatLogSource", chatLogSource},
		{"boardSource", boardSource},
		{"exploreSource", exploreSource},
		{"fleetAdminSource", fleetAdminSource},
		{"runStepsSource", runStepsSource},
		{"ticketSource", ticketSource},
	} {
		if strings.Contains(src.body, "<style") {
			t.Errorf("%s carries a <style> element; put the rules in sheetLiteral, "+
				"which is served, hashed and actually applied", src.name)
		}
	}
}

// The rules chat and the inbox need are IN the served sheet. Pinned by
// name because moving them there is what made them work at all.
func TestSheetCarriesChatAndInboxRules(t *testing.T) {
	for _, want := range []string{
		".chatlog{", ".chatmsg", ".chat-toolbar{", ".chat-quote{",
		".composer{", ".chat-date{", ".chat-divider",
		".inbox-bar{", ".attn-row", ".attn-done{",
	} {
		if !strings.Contains(sheet, want) {
			t.Errorf("the served stylesheet is missing %q", want)
		}
	}
	// And the log is not a numbered list.
	if !strings.Contains(sheet, "list-style:none") {
		t.Error("the chat log has no list-style reset; it will render as 1. 2. 3.")
	}
}