// The sheet a dealer opens mid-argument. // // It held twelve rulings with all their prose showing — 2,480px of it on a 390px // phone, of which 1,754 was below the fold — and a row of twelve chips across the top // to jump between them. The chips were an index of the twelve headings printed directly // above the same twelve headings: the same list twice, 172px of navigation before the // first word, and the dealer who used one landed in the middle of a scroll with eleven // rulings they hadn't asked for still wrapped around them. // // The headings are the index now. NN/g's rule for this shape — a longer list of // independent topics somebody opens one of — is an accordion, shut by default, and // half of these headings answer the question without being opened at all: "A short // all-in doesn't reopen the betting" is the ruling, not the topic. Measured after: // 29px below the fold on an iPhone with all twelve rows on screen at once, 51px on a // desktop. Opening the longest of them leaves 244px. // // These are layout and markup decisions, so they are checked as text — except the one // about what the sheet does when it is opened again, which is behaviour and lives in // main.js. const test = require("node:test"); const { describe } = require("node:test"); const assert = require("node:assert"); const fs = require("fs"); const path = require("path"); const ROOT = path.join(__dirname, "..", "..", "JoshHeaps.Net"); const PAGE = fs.readFileSync(path.join(ROOT, "Pages", "Casino", "TexasHoldem.cshtml"), "utf8"); const CSS = fs.readFileSync(path.join(ROOT, "wwwroot", "css", "casino", "holdem.css"), "utf8"); const MAIN = fs.readFileSync(path.join(ROOT, "wwwroot", "js", "casino", "holdem", "main.js"), "utf8"); const sheet = () => { const at = PAGE.indexOf('
= 0, "there is no rulings overlay"); return PAGE.slice(at, PAGE.indexOf('
{ const at = CSS.indexOf(`\n${selector} {`); assert.ok(at >= 0, `there is no \`${selector}\` rule`); return CSS.slice(at, CSS.indexOf("}", at)); }; // Each ruling as its own slice of markup. const rulings = () => { const parts = sheet().split('
p.slice(0, p.indexOf("
"))); }; // --------------------------------------------------------------------------- describe("twelve rulings, shut", () => { test("every one of them is a disclosure, and there are still twelve", () => { assert.equal(rulings().length, 12); }); // NN/g is explicit that opening the first one by default costs the reader the // glance at the whole list, which on this sheet is the entire point. test("none of them is open in the markup", () => { assert.ok(!/
]*\bopen\b/.test(sheet()), "a ruling starts open, so the sheet no longer opens on its own contents"); }); // Native exclusive accordions close the open one when another is opened, which // shifts everything below it under the finger that is reaching. That is the // disorientation the accordion is here to remove, not add. test("opening one does not close another", () => { assert.ok(!/
]*\bname=/.test(sheet()), "the rulings are an exclusive accordion, so content moves when one opens"); }); test("the name of a ruling is the control that opens it", () => { rulings().forEach((r, i) => { assert.match(r, /

.+<\/h3><\/summary>/, `ruling ${i + 1} does not carry its heading in its summary`); }); }); }); describe("the index that was above them is gone, not merely hidden", () => { test("nothing builds a chip row any more", () => { assert.ok(!/rulingsIndex/.test(PAGE), "the index nav is still in the markup"); assert.ok(!/buildRulingsIndex|rulingsIndexBtn/.test(MAIN), "main.js still builds the index"); assert.ok(!/rulingsIndexBtn/.test(CSS), "the index chips still have styles"); }); // The short labels existed only to fit three chips on a line. With the full // headings doing the work there is nothing left to read them. test("and the short labels it read are gone with it", () => { assert.ok(!/data-short=/.test(PAGE)); }); }); describe("what a summary has to be to work", () => { // A is announced as a button and not as a heading, so without this the // twelve names — the whole of this sheet's navigation — are invisible to anybody // moving through it by heading. Same fix as the sidebar's panel names. test("the heading survives being a control", () => { assert.match(ruleFor(".ruling > summary > h3"), /display:\s*inline/); assert.match(ruleFor(".ruling > summary > h3"), /font:\s*inherit/); }); // A is content-box, so a min-height is *added* to its padding — the trap // the sidebar's headers were in, one stylesheet section over. test("a thumb gets its 44px, counted the way the box actually counts", () => { const rule = ruleFor(".ruling > summary"); assert.match(rule, /box-sizing:\s*border-box/); assert.match(rule, /min-height:\s*44px/); }); test("the accent belongs to the ruling being read, not to all twelve", () => { assert.match(ruleFor(".ruling > summary"), /color:\s*var\(--text\)/); assert.match(ruleFor(".ruling[open] > summary"), /color:\s*var\(--gold\)/); }); test("and so does the gold bar down the side", () => { assert.match(ruleFor(".ruling[open]"), /border-left:\s*2px solid/); assert.ok(!/border-left/.test(ruleFor(".ruling")), "every ruling wears the open one's marker"); }); }); describe("reading one of them", () => { // Five of the twelve are two paragraphs and they ran into each other: the sections // were spaced from one another, but nothing separated the halves of one ruling. test("two paragraphs of a ruling are two paragraphs", () => { assert.match(ruleFor(".ruling p + p"), /margin-top:\s*var\(--sp-\d\)/); }); //
keeps its state, so without this a dealer who read the odd-chip rule an // hour ago finds it still hanging open under the one they came back for. test("the sheet opens shut, however it was left", () => { const at = MAIN.indexOf("const openRulings"); assert.ok(at >= 0, "nothing owns what the sheet looks like when it opens"); const body = MAIN.slice(at, MAIN.indexOf("};", at)); assert.match(body, /\.ruling\[open\]/); assert.match(body, /open = false/); }); test("and that is what the button calls", () => { assert.match(MAIN, /getElementById\("openRulingsBtn"\)\.addEventListener\("click", openRulings\)/); }); });