ce8cbfc3d2ef6853f94bf80b0f8b5f389c60025b
braney
  Sat Sep 5 09:21:32 2026 -0700
docent: two more expect: checks, a positional click:, and three fixes found writing tests

Everything here was needed by a regression script that could not otherwise be
written, or by one that failed for a reason that was not a bug.

expect: {url:, noUrl:} is a substring check on the current address. Some things
are visible nowhere else: which CGI a click reached, and what a form put in a
query string. #36387's fix strips zero-width characters out of a search term
before the position box submits it, and the character is invisible in the
rendered page, so whether %E2%80%8B survives into the URL is the only evidence
either way.

expect: {has:, noHas:} takes a CSS selector, for a bug whose whole signature is
WHERE something sits. #37785 attached a squishyPack track's center label to the
wrong row: same rows drawn, same image height, same pixels, and only the row the
label's image map hangs off changed, so rows:, height: and text: are all blind
to it. Documented as a last resort, since an assertion on hgTracks' own ids
breaks easily for reasons that are not bugs.

click: now takes the positional forms mouseover: already had (at:/frac:/x:) and
follows the item box nearest that point. Some tracks have no item that can be
named at all: every GIAB Problematic Regions subtrack is type bigBed 3, so
hgTracks writes an EMPTY i= into the hgc href and gives every box the title
"Start of Exon (1/1)".  Neither item: nor title: can pick one, and a raw mouse
click on the data area is swallowed by the drag-select handler.

The "item not found" message now picks the row's map boxes by MAP NAME instead of
by a y-band, reports how many boxes are in the row, and falls back to a box's
title when it has no name. On a quickLift target the band test dropped every item
box, so the message said the GIAB row held three things when it held twenty-six,
and the three it named were a density control and two exon arrows.

goShow now scrolls to the top and takes the Login/Share links out of the way
before clicking Search. Those links sit in an absolutely-positioned container at
the top right of the header bar and on a wide page land on top of #goButton;
Playwright then retries for the full 30s and fails with "<a id=loginLink ...>
subtree intercepts pointer events", which reads like a broken Search button
rather than a covered one. Pressing Enter in the position box is not a
substitute: by the time a 30s click timeout has been caught, the navigation wait
armed before it has already expired.

tests/pagechecks and tests/pagechecks.xfail cover all of it, per the rule in
tests/README.txt that a verb we touch and find untested belongs on its list. The
xfail aims all four new checks the wrong way at once, because a check that cannot
fail is not a check.

refs #38252

diff --git src/hg/utils/docent/tests/README.txt src/hg/utils/docent/tests/README.txt
index bf7ca335cad..e8e240a92f8 100644
--- src/hg/utils/docent/tests/README.txt
+++ src/hg/utils/docent/tests/README.txt
@@ -50,30 +50,39 @@
                 `parent wgEncodeRegDnaseSignal off`, and pins the superTrack side effect
                 below.
   views.xfail   the same thing aimed at the COMPOSITE instead, which loses the row.
                 Expected to fail.
   supertrack    varsInPubs hideKids + one member: `exact: true`, because a test that only
                 checked the member was present would pass with all six drawn.
   urllen        {cCREs: hideKids} must not become the 1701-variable, 42,020-character GET
                 that Apache answered with 414. Checks `noText: "Too Long"`, since a 414
                 renders as a perfectly good page; the derive baseline pins it at 3.
   customtrack   addCustomTrack: with inline BED, tabs and newlines surviving the trip.
   scale         a 3x run draws the same rows as a 1x one.
   ordered       `ordered: true` on rows:, and the fact that a row which was not drawn is
                 reported by rows: alone rather than failing the order check as well.
   ordered.xfail the same two rows named the wrong way round. Expected to fail -- a flag
                 that cannot fail is not a check, it is a second copy of the set test.
+  pagechecks    the `expect:` checks that read the PAGE rather than the track image --
+                `url:`/`noUrl:` on the address, `has:`/`noHas:` on a CSS selector -- plus
+                the positional form of `click:` (`{track:, frac:}`), which follows the
+                item box nearest a point. All four exist for bugs that rows:, height: and
+                text: cannot see: a search term's zero-width space stripped out of a URL
+                (#36387), a center label attached to the wrong row (#37785), and an item
+                that cannot be named at all because its track is `type bigBed 3` (#36335).
+  pagechecks    the same four aimed the wrong way at once. Expected to fail. The message
+    .xfail      names every check that failed, so one run says which of the four broke.
   expectfail    an assertion that is plainly false. Expected to fail -- if it ever passes,
     .xfail      `expect:` has stopped throwing and every other test here means nothing.
   make parity   FAST vs slow, and a rerun, on composite. FAST drops the dwells and the
                 recording and must not change what the page ends up showing; the rerun
                 catches state left behind in the cart.
 
 Two things these tests found
 ----------------------------
 
 Worth knowing before writing more:
 
   * Turning on anything under a superTrack sends `<superTrack>=show`, and every OTHER
     member then comes up at its own trackDb visibility -- so `hide: all` is undone for
     them. views asserts wgEncodeRegMarkH3k27ac comes back, rather than working around it.
     Whether Docent should be cleverer here is an open question, not a settled one.