Skip to content

Commit 4cfd8a7

Browse files
ChBrainclaude
andauthored
governance: tag-agnostic selectors in main.test and architecture-playbook.test (#460)
* governance: tag-agnostic selectors in main.test (snap chassis, app cards) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0176ZYTwoV8V4So9SBTizc5X * governance: tag-agnostic .pb-spreads selectors in architecture-playbook.test Same rule as main.test: BaseLayout owns the page's main landmark, so chassis wrappers are queried by class, not tag. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0176ZYTwoV8V4So9SBTizc5X --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 87e24a3 commit 4cfd8a7

2 files changed

Lines changed: 25 additions & 14 deletions

File tree

tests/architecture-playbook.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,15 +299,17 @@ describe("architecture playbook - design contract", () => {
299299
});
300300

301301
describe("snap chassis (CVI parity)", () => {
302-
it("renders a main.pb-spreads wrapper around the spreads", () => {
302+
// Class-based, not tag-based: BaseLayout owns the page's <main> landmark,
303+
// so the spreads wrapper's tag is an implementation detail.
304+
it("renders a .pb-spreads wrapper around the spreads", () => {
303305
const dom = new JSDOM(playbookPage!.html);
304-
const wrap = dom.window.document.querySelector("main.pb-spreads");
306+
const wrap = dom.window.document.querySelector(".pb-spreads");
305307
expect(wrap).not.toBeNull();
306308
});
307309

308310
it("SiteFooter lives OUTSIDE the spreads container", () => {
309311
const dom = new JSDOM(playbookPage!.html);
310-
const wrap = dom.window.document.querySelector("main.pb-spreads");
312+
const wrap = dom.window.document.querySelector(".pb-spreads");
311313
const footer = dom.window.document.querySelector(".footfed");
312314
expect(footer).not.toBeNull();
313315
expect(wrap?.contains(footer)).toBe(false);

tests/main.test.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ describe("main (company front door) — design contract", () => {
221221

222222
it("sections appear in canonical funnel order (services → author|founder → method → apps)", () => {
223223
const dom = new JSDOM(main!.html);
224-
const ids = [...dom.window.document.querySelectorAll("main.snap-scroll section.section")].map(
224+
const ids = [...dom.window.document.querySelectorAll(".snap-scroll section.section")].map(
225225
(s) => s.id,
226226
);
227227
// Build the expected id list by picking, for each canonical section, the
@@ -240,30 +240,34 @@ describe("main (company front door) — design contract", () => {
240240
});
241241

242242
describe("snap chassis (CVI parity)", () => {
243-
it("main.snap-scroll wraps the chapters", () => {
243+
it(".snap-scroll wraps the chapters", () => {
244+
// Class-based, not tag-based: the landmark element carrying
245+
// .snap-scroll is a chassis concern (BaseLayout owns the actual
246+
// <main> landmark), so this asserts the class regardless of
247+
// whether the wrapper renders as <main> or a plain <div>.
244248
const dom = new JSDOM(main!.html);
245-
const scroll = dom.window.document.querySelector("main.snap-scroll");
246-
expect(scroll, "missing main.snap-scroll container").not.toBeNull();
249+
const scroll = dom.window.document.querySelector(".snap-scroll");
250+
expect(scroll, "missing .snap-scroll container").not.toBeNull();
247251
});
248252

249253
it("renders one snap panel per section plus the masthead", () => {
250254
const dom = new JSDOM(main!.html);
251-
const panels = dom.window.document.querySelectorAll("main.snap-scroll .snap-panel");
252-
const sections = dom.window.document.querySelectorAll("main.snap-scroll section.section");
255+
const panels = dom.window.document.querySelectorAll(".snap-scroll .snap-panel");
256+
const sections = dom.window.document.querySelectorAll(".snap-scroll section.section");
253257
// masthead + every section is its own panel (4 today, 5 once plays lands).
254258
expect(panels.length).toBe(1 + sections.length);
255259
expect(sections.length).toBeGreaterThanOrEqual(4);
256260
});
257261

258262
it("masthead is the first snap panel", () => {
259263
const dom = new JSDOM(main!.html);
260-
const first = dom.window.document.querySelector("main.snap-scroll .snap-panel");
264+
const first = dom.window.document.querySelector(".snap-scroll .snap-panel");
261265
expect(first?.classList.contains("masthead")).toBe(true);
262266
});
263267

264268
it("SiteFooter lives OUTSIDE the snap container", () => {
265269
const dom = new JSDOM(main!.html);
266-
const snap = dom.window.document.querySelector("main.snap-scroll");
270+
const snap = dom.window.document.querySelector(".snap-scroll");
267271
const footer = dom.window.document.querySelector(".footfed");
268272
expect(footer).not.toBeNull();
269273
expect(snap?.contains(footer)).toBe(false);
@@ -435,10 +439,15 @@ describe("main (company front door) — design contract", () => {
435439
// the invariants that hold across that growth rather than a fixed roster —
436440
// the source/test split keeps a new app card and this test in separate
437441
// PRs, so a lockstep count would force one to land red.
442+
//
443+
// Cards are queried by class (.app), not tag: the live cards render as
444+
// <a class="app">, but the planned placeholder is a non-interactive
445+
// <div class="app app--planned"> (it has no destination yet), so an
446+
// `a.app` selector would silently drop it from the NodeList.
438447
it("leads with Cultures (live) and closes with the planned placeholder", () => {
439448
const dom = new JSDOM(main!.html);
440449
const section = dom.window.document.querySelector("section#apps");
441-
const cards = [...section!.querySelectorAll("a.app")];
450+
const cards = [...section!.querySelectorAll(".app")];
442451
expect(cards.length).toBeGreaterThanOrEqual(2);
443452

444453
// First card: Cultures, live.
@@ -460,15 +469,15 @@ describe("main (company front door) — design contract", () => {
460469
it("Cultures (live) carries the brick .app-state--live", () => {
461470
const dom = new JSDOM(main!.html);
462471
const section = dom.window.document.querySelector("section#apps");
463-
const cards = [...section!.querySelectorAll("a.app")];
472+
const cards = [...section!.querySelectorAll(".app")];
464473
const live = cards[0].querySelector(".app-state--live");
465474
expect(live, "live app should carry .app-state--live for brick").not.toBeNull();
466475
});
467476

468477
it("'More applications' placeholder carries .app--planned (dashed border)", () => {
469478
const dom = new JSDOM(main!.html);
470479
const section = dom.window.document.querySelector("section#apps");
471-
const cards = [...section!.querySelectorAll("a.app")];
480+
const cards = [...section!.querySelectorAll(".app")];
472481
// The placeholder is always the last card (live apps precede it).
473482
expect(cards[cards.length - 1].classList.contains("app--planned")).toBe(true);
474483
});

0 commit comments

Comments
 (0)