Skip to content
quarry Artifact [bb8e59cbdc]
Login

Artifact [bb8e59cbdc]

Artifact bb8e59cbdcd8b7ccbdf115db0b122e9ef972755fef4248ef02b2ac1997fc1658:


package web

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

// A single-line row that holds an icon centres its items.
//
// An SVG has no baseline. In a flex or grid row aligned on the
// baseline, the browser synthesises one from the icon's bottom margin
// edge and stands the whole icon ON the text baseline, so it rides
// high. Measured in Chrome against the deployed stylesheet: the state
// tabs on the ticket, landing and sqlite trackers each sat exactly
// -2.00px (icon centre against the adjacent text's own glyph box), and
// 0.00 once the tab centres.
func TestTheStateTabsCentreTheirContents(t *testing.T) {
	re := regexp.MustCompile(`nav\.seg-box a\s*\{([^}]*)\}`)
	var seen bool
	for _, m := range re.FindAllStringSubmatch(sheet, -1) {
		if strings.Contains(m[1], "align-items:center") || strings.Contains(m[1], "align-items: center") {
			seen = true
		}
	}
	if !seen {
		t.Fatal("FAIL: nav.seg-box a does not centre its items; its icon will ride 2px high")
	}
	t.Log("ok: nav.seg-box a centres its items")
}

// The icon rule itself must NOT declare alignment.
//
// This is the guard on a fix I got wrong first. Putting
// align-self:center on .ic fixed the state tabs and broke the ticket
// list: li.t-row is a GRID whose rows are four lines tall, align-self
// applies to grid items too, and the status glyph was centred over the
// whole row — measured +27.59px below the title it belongs to, where
// the row's own baseline alignment had it at -0.01px.
//
// The icon cannot know whether its row is one line or four. Only the
// host knows, so alignment is the host's to declare. A global rule here
// is a rule that must be right for every row on the site at once, and
// no value is.
func TestTheIconRuleDoesNotDeclareAlignment(t *testing.T) {
	re := regexp.MustCompile(`(?s)(^|[};])\s*\.ic\s*\{([^}]*)\}`)
	for _, m := range re.FindAllStringSubmatch(sheet, -1) {
		body := m[2]
		if !strings.Contains(body, "fill") { // the scoped rules only resize
			continue
		}
		if strings.Contains(body, "align-self") {
			t.Fatalf("FAIL: the base .ic rule declares align-self, which centres the "+
				"ticket-list glyph over a four-line row: %s", strings.TrimSpace(body))
		}
		if !strings.Contains(body, "vertical-align") {
			t.Fatalf("FAIL: the base .ic rule lost vertical-align, which is what aligns "+
				"an icon in the block and table-cell hosts: %s", strings.TrimSpace(body))
		}
		t.Log("ok: .ic sets vertical-align for inline hosts and leaves flex and grid rows to say their own")
		return
	}
	t.Fatal("no base .ic rule in the served stylesheet")
}

// A row that WRAPS puts its icon on the first line, and says so itself.
//
// The about rows wrap. Baseline alignment leaves their icon 1.70px
// above the first line, for the same reason the state tabs were 2.00px
// high: an SVG has no baseline, so the synthesised one stands it on the
// text's. A box exactly one line tall settles it at +0.29px without a
// magic number — the width still sets the glyph size and the SVG's own
// preserveAspectRatio centres it in the taller box.
//
// Pinned WITH its @supports guard. Without the lh unit the height falls
// back to 1em, and align-self:start alone measured -3.30px: worse than
// the 1.70px it replaces. A browser that cannot do this must keep what
// it has rather than inherit a bigger error.
func TestAWrappingAboutRowPutsItsIconOnTheFirstLine(t *testing.T) {
	i := strings.Index(sheet, ".about-row>.ic")
	if i < 0 {
		i = strings.Index(sheet, ".about-row > .ic")
	}
	if i < 0 {
		t.Fatal("FAIL: nothing aligns the about-row icon to its first line")
	}
	head := sheet[max(0, i-220):i]
	if !strings.Contains(head, "@supports") || !strings.Contains(head, "1lh") {
		t.Fatalf("FAIL: the about-row alignment is not behind an @supports (height: 1lh) guard, "+
			"so a browser without the unit gets align-self:start alone, which is worse: %q", head)
	}
	t.Log("ok: the about-row icon takes a one-line-tall box, behind an lh guard")
}

// The same declaration must NOT be shared with the ticket rows, where
// it measured +2.39px against the row's own exact -0.01px. This is the
// third time one alignment has been right for one row and wrong for
// another; the guard states it so the next person does not generalise.
func TestTheTicketRowIsNotGivenTheAboutRowAlignment(t *testing.T) {
	// The dot matters: "about-row" ends in "t-row", and the first
	// version of this test flagged the about rule as a ticket rule.
	re := regexp.MustCompile(`([^{}]*\.t-row\b[^{}]*)\{([^}]*)\}`)
	for _, m := range re.FindAllStringSubmatch(sheet, -1) {
		if strings.Contains(m[2], "align-self") {
			t.Errorf("FAIL: %s declares align-self; the ticket row is already exact on its own baseline: %s",
				strings.TrimSpace(m[1]), strings.TrimSpace(m[2]))
		}
	}
	t.Log("ok: the ticket rows keep their own baseline alignment")
}