Hold'em: every seat on the ring is the same seat, and the ring is measured before it is believed #122
@@ -509,37 +509,53 @@
|
||||
not during it.
|
||||
</p>
|
||||
|
||||
<nav id="rulingsIndex" class="rulingsIndex" aria-label="Jump to a ruling"></nav>
|
||||
@* Twelve rulings, shut.
|
||||
|
||||
<section class="ruling" data-short="Misdeal">
|
||||
<h3>Redeal it — misdeal</h3>
|
||||
They used to be twelve headings with all their prose under them — 2,480px of
|
||||
it on a 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, which is the same
|
||||
list twice: 172px of navigation before the first word, and the dealer who
|
||||
used it landed in the middle of a scroll with eleven rulings they didn't ask
|
||||
for still wrapped around them.
|
||||
|
||||
The headings are the index now. NN/g's rule for this shape — a 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.
|
||||
|
||||
Not exclusive (no `name` attribute): closing one because another opened moves
|
||||
everything under the dealer's finger, which is the disorientation the
|
||||
accordion is here to avoid. *@
|
||||
<details class="ruling">
|
||||
<summary><h3>Redeal it — misdeal</h3></summary>
|
||||
<ul>
|
||||
<li>The first card goes to the wrong seat.</li>
|
||||
<li>A seat entitled to a hand gets dealt out, or a seat that isn't entitled gets dealt in.</li>
|
||||
<li>Two or more boxed cards turn up on the initial deal.</li>
|
||||
<li>Either of the first two cards is exposed by dealer error.</li>
|
||||
</ul>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="Board card early">
|
||||
<h3>A board card turned too early</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>A board card turned too early</h3></summary>
|
||||
<p>
|
||||
If the fourth board card gets turned before the betting round is finished,
|
||||
that card is out of play for the round. Finish the betting, then burn and
|
||||
turn what would have been the fifth card in the fourth card's place.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="Out of turn">
|
||||
<h3>Acting out of turn</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>Acting out of turn</h3></summary>
|
||||
<p>
|
||||
A one-off is usually just backed up if no one has acted behind them.
|
||||
Doing it repeatedly is what earns a penalty.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="Clock">
|
||||
<h3>Calling the clock on a player</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>Calling the clock on a player</h3></summary>
|
||||
<p>
|
||||
Any player may ask for a clock once a decision is taking unreasonably
|
||||
long; it is the dealer, not the table, who grants it. The player then
|
||||
@@ -553,10 +569,10 @@
|
||||
count once you tap <em>Call the clock</em>, and offers the ruling as one
|
||||
button when it ends.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="Straddle">
|
||||
<h3>A straddle is a blind raise</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>A straddle is a blind raise</h3></summary>
|
||||
<p>
|
||||
The player left of the big blind may put out twice it before the cards,
|
||||
without looking. It is a blind bet, not a raise made in turn, so it does
|
||||
@@ -570,10 +586,10 @@
|
||||
posts it, puts the right player on the clock and prices the raise;
|
||||
the seat wears an <em>STR</em> badge for the hand.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="Short all-in">
|
||||
<h3>A short all-in doesn't reopen the betting</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>A short all-in doesn't reopen the betting</h3></summary>
|
||||
<p>
|
||||
Somebody shoving in less than a full raise — say $3 more when the last
|
||||
raise was $8 — does not give the players behind them another go. Anyone
|
||||
@@ -585,20 +601,20 @@
|
||||
the minimum raise stays measured off the last <em>full</em> raise, not
|
||||
off the short one. The action bar follows this for you.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="Uncalled bet">
|
||||
<h3>Chips nobody called come back</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>Chips nobody called come back</h3></summary>
|
||||
<p>
|
||||
Bet more than anyone was able to call and the excess is returned to you
|
||||
before the showdown — it was never contested, so it isn't part of the
|
||||
pot. The pot breakdown shows it as "uncalled" rather than pretending it's
|
||||
a side pot you could win.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="Oversized chip">
|
||||
<h3>One big chip, nothing said</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>One big chip, nothing said</h3></summary>
|
||||
<p>
|
||||
The most common argument at a home table. A player facing a bet who
|
||||
pushes out a single oversized chip without saying anything has
|
||||
@@ -611,10 +627,10 @@
|
||||
clear verbal declaration in turn is binding either way — if words and
|
||||
chips disagree, whichever came first is the action.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="Minimum raise">
|
||||
<h3>A raise has to be a full raise</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>A raise has to be a full raise</h3></summary>
|
||||
<p>
|
||||
At least as much again as the last raise, or the big blind if there
|
||||
hasn't been one. Anything between a call and that minimum isn't a raise
|
||||
@@ -622,10 +638,10 @@
|
||||
in. The raise pad says so if you type one, and won't stop you: your
|
||||
ruling beats the arithmetic.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="Who shows first">
|
||||
<h3>Who turns their hand over first</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>Who turns their hand over first</h3></summary>
|
||||
<p>
|
||||
If there was a bet on the river, the last player to bet or raise shows
|
||||
first. If the river was checked all the way round, it's the first live
|
||||
@@ -638,20 +654,20 @@
|
||||
was. The action bar names the seat and the reason at every showdown, so
|
||||
the call is already made before anyone asks.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="Odd chip">
|
||||
<h3>The odd chip in a split pot</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>The odd chip in a split pot</h3></summary>
|
||||
<p>
|
||||
When a chopped pot won't divide evenly, the odd chip goes to the first
|
||||
player left of the button, not to whoever the dealer happened to tick
|
||||
first. Pot payouts here order the winners that way, so the leftover lands
|
||||
on the right seat every time.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="ruling" data-short="String bet">
|
||||
<h3>Betting in one motion — the string bet</h3>
|
||||
<details class="ruling">
|
||||
<summary><h3>Betting in one motion — the string bet</h3></summary>
|
||||
<p>
|
||||
A bet is whatever goes in on the first trip to the stack, unless the
|
||||
amount was said out loud first. Reaching back for more chips without
|
||||
@@ -664,7 +680,7 @@
|
||||
fine — the point is that a player can't watch the table react and then
|
||||
decide how much to bet. Say it, or push it all at once.
|
||||
</p>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<p class="rulingsSource">
|
||||
Follows the Tournament Directors Association rules, which most rooms and
|
||||
|
||||
@@ -2131,63 +2131,63 @@ button,
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* One chip per ruling, wrapped across the top of the sheet. Names rather than icons:
|
||||
a dealer scanning this is looking for the words somebody at the table just said. */
|
||||
.rulingsIndex {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--sp-1);
|
||||
margin: 0 0 var(--sp-4);
|
||||
}
|
||||
|
||||
.rulingsIndexBtn {
|
||||
box-sizing: border-box;
|
||||
min-height: 32px;
|
||||
padding: var(--sp-1) var(--sp-2);
|
||||
border-radius: var(--r-pill);
|
||||
border: 1px solid var(--line);
|
||||
background: var(--surface-2);
|
||||
color: var(--gold);
|
||||
font-family: inherit;
|
||||
font-size: var(--fs-sm);
|
||||
line-height: 1.25;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.rulingsIndexBtn:hover {
|
||||
background: var(--surface-3);
|
||||
border-color: var(--line-strong);
|
||||
}
|
||||
}
|
||||
|
||||
/* A thumb needs the same 44px here as everywhere else. */
|
||||
@media (pointer: coarse) {
|
||||
.rulingsIndexBtn {
|
||||
min-height: 44px;
|
||||
font-size: var(--fs-sm);
|
||||
}
|
||||
}
|
||||
|
||||
/* The heading the index jumps to takes focus, and a focus ring on a heading that the
|
||||
dealer just asked for reads as noise rather than as help. */
|
||||
.ruling h3:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* A shut ruling is a row you can read; an open one is a passage you can read. The gold
|
||||
left bar used to run down all twelve at once, which on a list of headings is twelve
|
||||
vertical rules and no hierarchy. It belongs to the one that is open. */
|
||||
.ruling {
|
||||
margin-bottom: var(--sp-4);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.ruling[open] {
|
||||
margin-bottom: var(--sp-2);
|
||||
padding-left: var(--sp-3);
|
||||
border-left: 2px solid rgba(216, 180, 106, 0.4);
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
.ruling h3 {
|
||||
margin: 0 0 var(--sp-1);
|
||||
color: var(--gold);
|
||||
/* Padding rather than a flex box with min-height, because a <summary> only draws its
|
||||
disclosure triangle while it is `display: list-item` — and content-box means a
|
||||
min-height would be *added* to the padding. Both traps are the sidebar's, one
|
||||
stylesheet section over, and they are the same traps here. */
|
||||
.ruling > summary {
|
||||
box-sizing: border-box;
|
||||
min-height: 44px;
|
||||
padding: var(--sp-2) 0;
|
||||
color: var(--text);
|
||||
font-size: var(--fs-base);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.03em;
|
||||
line-height: 1.35;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* The gold arrives when a ruling is opened, and not before. These were all gold while
|
||||
they were headings with prose between them; twelve of them in a column is the accent
|
||||
doing the job of body text, which leaves it nothing to say when one of them is the
|
||||
one the dealer is reading. The sidebar's eight panel names are `--text` for the same
|
||||
reason — this is the same component doing the same job. */
|
||||
.ruling[open] > summary {
|
||||
margin-bottom: var(--sp-1);
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
/* A <summary> is announced as a button, not as a heading, so the twelve names — which
|
||||
are now the whole of this sheet's navigation — would be invisible to anybody moving
|
||||
through it by heading. Same fix as the sidebar's panel names: keep the heading and
|
||||
make it look like nothing happened. Inline, because a block child of a summary
|
||||
pushes the disclosure triangle onto its own line. */
|
||||
.ruling > summary > h3 {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
letter-spacing: inherit;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.ruling > summary:hover {
|
||||
color: var(--gold-bright);
|
||||
}
|
||||
}
|
||||
|
||||
.ruling p,
|
||||
@@ -2201,6 +2201,14 @@ button,
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Five of the twelve are two paragraphs, and they ran into each other: the sections
|
||||
were spaced apart from one another but nothing separated the halves of one ruling,
|
||||
so "the most that chip allows." and "Facing no bet," read as one paragraph. It did
|
||||
not show while there was a gold heading every few lines to break the column up. */
|
||||
.ruling p + p {
|
||||
margin-top: var(--sp-2);
|
||||
}
|
||||
|
||||
.ruling ul {
|
||||
margin: 0;
|
||||
padding-left: var(--sp-4);
|
||||
|
||||
@@ -879,50 +879,19 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
});
|
||||
}
|
||||
|
||||
// An index across the top of the rulings sheet, one chip per ruling.
|
||||
// The sheet opens on twelve shut rulings, and it opens that way every time.
|
||||
//
|
||||
// This is opened mid-argument with players waiting, and it was nine rulings of
|
||||
// prose with no way in: reaching the last one meant scrolling 1.6 screens on a
|
||||
// desktop, 2.1 on a phone and 3.5 on a phone held sideways. A dealer looking for
|
||||
// the odd-chip rule had to read past seven others to find it.
|
||||
//
|
||||
// Built from the sections rather than written out beside them, so a ruling added
|
||||
// later turns up in the index without anyone having to remember to add it twice.
|
||||
const buildRulingsIndex = () => {
|
||||
const index = document.getElementById("rulingsIndex");
|
||||
if (!index || index.childElementCount > 0) return;
|
||||
[...rulingsOverlay.querySelectorAll(".ruling")].forEach((section, i) => {
|
||||
const heading = section.querySelector("h3");
|
||||
if (!heading) return;
|
||||
if (!section.id) section.id = `ruling${i + 1}`;
|
||||
|
||||
const jump = document.createElement("button");
|
||||
jump.type = "button";
|
||||
jump.className = "rulingsIndexBtn";
|
||||
// A short label where the ruling gives one. The headings are sentences —
|
||||
// "A short all-in doesn't reopen the betting" — and nine of those stacked
|
||||
// one per row made the index 342px tall on a phone, which is most of the
|
||||
// sheet before the first ruling. "Short all-in" says the same thing to
|
||||
// somebody who is looking for it, and three fit on a line.
|
||||
jump.textContent = section.dataset.short || heading.textContent;
|
||||
// The full heading is still what it announces, so the short label never
|
||||
// costs a screen reader the sentence.
|
||||
if (section.dataset.short) jump.setAttribute("aria-label", heading.textContent);
|
||||
jump.addEventListener("click", () => {
|
||||
Render.bringIntoView(section, { block: "start" });
|
||||
// The heading is what the dealer is now reading, so that is where the
|
||||
// keyboard and a screen reader should be too.
|
||||
heading.setAttribute("tabindex", "-1");
|
||||
heading.focus({ preventScroll: true });
|
||||
});
|
||||
index.appendChild(jump);
|
||||
});
|
||||
// There was an index of chips here that this built from the headings; the headings
|
||||
// are the index now, so there is nothing to build. What is left is the other half
|
||||
// of the job: a dealer who read the odd-chip rule an hour ago should not find it
|
||||
// still hanging open under the one they came back for. <details> keeps its state,
|
||||
// so closing the sheet is what forgets it.
|
||||
const openRulings = () => {
|
||||
rulingsOverlay.querySelectorAll(".ruling[open]").forEach(r => { r.open = false; });
|
||||
rulingsOverlay.hidden = false;
|
||||
};
|
||||
|
||||
document.getElementById("openRulingsBtn").addEventListener("click", () => {
|
||||
buildRulingsIndex();
|
||||
rulingsOverlay.hidden = false;
|
||||
});
|
||||
document.getElementById("openRulingsBtn").addEventListener("click", openRulings);
|
||||
document.getElementById("closeRulingsBtn").addEventListener("click", closeRulings);
|
||||
rulingsOverlay.addEventListener("click", e => {
|
||||
if (e.target === rulingsOverlay) closeRulings();
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
// 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('<div id="rulingsOverlay"');
|
||||
assert.ok(at >= 0, "there is no rulings overlay");
|
||||
return PAGE.slice(at, PAGE.indexOf('<div id="seatMenuOverlay"', at));
|
||||
};
|
||||
|
||||
const ruleFor = selector => {
|
||||
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('<details class="ruling"');
|
||||
return parts.slice(1).map(p => p.slice(0, p.indexOf("</details>")));
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
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(!/<details class="ruling"[^>]*\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(!/<details class="ruling"[^>]*\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, /<summary><h3>.+<\/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 <summary> 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 <summary> 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\)/);
|
||||
});
|
||||
|
||||
// <details> 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\)/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user