Skip to content
quarry Artifact [06515f4034]
Login

Artifact [06515f4034]

Artifact 06515f40344ff1ea67fdf602fdbbfdcb1e380251402ed02fc2ebb054fca5d38e:


package web

import (
	"regexp"
	"strings"
	"testing"
)

// The mirror table's action cell holds two forms. A form is block-level,
// so without display:contents they stack and every row becomes two and a
// half lines tall — which is what the fleet page looked like.
func TestMirrorActionsShareOneRow(t *testing.T) {
	if !strings.Contains(baseHTML, "td.acts { display: flex") {
		t.Error("the action cell is not a flex row")
	}
	if !strings.Contains(baseHTML, "td.acts form { display: contents; }") {
		t.Error("the forms inside it still generate their own boxes, so the buttons will stack")
	}
	if !strings.Contains(fleetAdminSource, `<td class="acts">`) {
		t.Error("the mirror row's action cell is not marked up as one")
	}
}

// The footer is fixed, so every page must reserve its height plus a
// visible gap. Clearing it by a hair still reads as content running into
// it, and the reserve and the bar must come from one value or they drift.
func TestBodyClearsTheFixedFooter(t *testing.T) {
	if !strings.Contains(baseHTML, "position: fixed; bottom: 0") {
		t.Skip("footer is no longer fixed")
	}
	if !strings.Contains(baseHTML, "padding-bottom: calc(var(--footer-h) + 2rem)") {
		t.Error("body does not reserve the footer's height plus a visible gap")
	}
	if !strings.Contains(baseHTML, "min-height: var(--footer-h)") {
		t.Error("the footer does not use the height the page reserved for it")
	}
}

// The Popover API is click-driven; using it as a tooltip gave a click
// target that ALSO carried a native title, so two tooltips competed and
// the cursor turned into a question mark. There is no standard hover
// tooltip primitive (popover="hint" is Chrome-only), so column headers
// carry a real visible label instead — readable by touch and by a
// screen reader, neither of which can hover.
func TestColumnHeadersDoNotUsePopoverAsATooltip(t *testing.T) {
	if strings.Contains(baseHTML, "popovertarget=\"tip-") {
		t.Error("a column header still opens a popover as a tooltip")
	}
	if strings.Contains(baseHTML, "cursor: help") {
		t.Error("the question-mark cursor is back")
	}
	if !strings.Contains(baseHTML, ".collabel") {
		t.Error("column headers have no visible label to fall back from")
	}
	// The icon alone must still have an accessible name at every width.
	if !strings.Contains(baseHTML, `.colhead { display: inline-flex`) {
		t.Error("the header label and icon are not one unit")
	}
}

// The legend and the header labels are inverses: exactly one of them
// explains the icons at any width. If both breakpoints ever drift to
// the same side, a phone reader gets four unexplained glyphs and a
// title attribute they cannot hover.
func TestIconColumnsAreExplainedAtEveryWidth(t *testing.T) {
	const labelAt = "@media (min-width: 56rem) { .collabel { display: inline; } }"
	const legendOff = "@media (min-width: 56rem) { .collegend { display: none; } }"
	if !strings.Contains(baseHTML, labelAt) {
		t.Error("header labels do not appear at the wide breakpoint")
	}
	if !strings.Contains(baseHTML, legendOff) {
		t.Error("the legend does not retire at the same breakpoint the labels appear")
	}
	// The legend must drop the same column the table drops, or it names
	// a column that is not on screen.
	if !strings.Contains(baseHTML, "@media (max-width: 30rem) { .collegend .mirror-only { display: none; } }") {
		t.Error("the legend keeps an entry for the column hidden at 30rem")
	}
	if !strings.Contains(fleetSource, `class="mirror-only"`) {
		t.Error("the legend's mirror entry is not marked so it can drop with its column")
	}
	// A key read AFTER the data is not a key. On a phone the legend
	// landed under twenty-three repositories, so a reader met the icons
	// at the top and the explanation only after scrolling past
	// everything they described.
	legend := strings.Index(fleetSource, `class="collegend"`)
	table := strings.Index(fleetSource, `<table class="fleet">`)
	if legend < 0 || table < 0 {
		t.Fatal("legend or table missing from the fleet template")
	}
	if legend > table {
		t.Error("the legend comes after the table it explains")
	}
}

// The footer is one line, so something must give on a narrow screen —
// but the render time is the reason that bar earns its space. It is
// therefore the part that never shrinks, and the forge name and version
// collapse ahead of it. Truncating the whole left half dropped the
// timing FIRST, which is exactly backwards.
func TestFooterKeepsTheRenderTime(t *testing.T) {
	if !strings.Contains(baseHTML, ".f-time { flex: none; }") {
		t.Error("the render time can shrink; it must not")
	}
	if strings.Contains(baseHTML, ".foot-l { min-width: 0; overflow: hidden; text-overflow: ellipsis;") {
		t.Error("the whole left half truncates again, which cuts the timing off the end")
	}
	// The two lower-priority parts must retire before it, in order.
	brand := strings.Index(baseHTML, "@media (max-width: 34rem) { .f-brand { display: none; } }")
	ver := strings.Index(baseHTML, "@media (max-width: 26rem) { .f-ver { display: none; } }")
	if brand < 0 || ver < 0 {
		t.Fatal("the collapse order is not declared")
	}
	// A wider breakpoint means it goes first: brand must retire before version.
	if !strings.Contains(baseHTML, "34rem") || !strings.Contains(baseHTML, "26rem") {
		t.Error("the two collapse breakpoints are not distinct")
	}
}

// Datastar morphs #fleet and #tl from the server on every change. A
// widget holding its own state inside one of those regions is destroyed
// mid-interaction by a repaint — an open menu vanishes, a half-typed
// filter resets. This is the failure Morpheus was built to work around
// in JS-state component kits; quarry avoids it structurally by keeping
// every popover in page chrome, OUTSIDE the morphed region.
//
// That is currently true by luck of layout rather than by rule, which
// is why it is asserted: the natural next feature is a per-row menu,
// and it would break in a way nobody reproduces by hand.
var tmplComment = regexp.MustCompile(`(?s)\{\{-? */\*.*?\*/ *-?\}\}`)

func TestMorphedRegionsHoldNoStatefulWidgets(t *testing.T) {
	region := func(src, define string) string {
		i := strings.Index(src, `{{define "`+define+`"}}`)
		if i < 0 {
			t.Fatalf("no %s template", define)
		}
		rest := src[i:]
		if j := strings.Index(rest[10:], "{{define "); j >= 0 {
			rest = rest[:j+10]
		}
		return rest
	}
	for _, tc := range []struct{ name, src, define string }{
		{"fleet", fleetSource, "fleet-body"},
		{"timeline", timelineSource, "tl-body"},
	} {
		// Template comments are stripped: the prose beside these rules
		// discusses popovers, and a substring search finds the word in
		// the explanation rather than in any markup.
		body := tmplComment.ReplaceAllString(region(tc.src, tc.define), "")
		for _, bad := range []string{"popover", "data-tip"} {
			if strings.Contains(body, bad) {
				t.Errorf("%s is morphed over SSE but contains %q; a repaint would destroy it mid-interaction",
					tc.define, bad)
			}
		}
	}
}