6f3f3596f3dc61a8a738717b9701e69a86b5bb0b
braney
Mon Sep 21 17:24:33 2026 -0700
docent: wait: {gone:} for a selector to leave, and rm38257 stops racing itself
rm38257 went red in the 2026-09-21 nightly with the #38257 fix still live on
genome-test. The script was waiting on the wrong half of the click.
hgHubConnect.js switches the tab synchronously inside the click dispatch, while
topLinks.js closes the Account popup from a setTimeout(..., 0). So the tab is
the half that settles FIRST, and waiting for it returned a tick early: the
expect after it read a page that still had the popup on it. Measured with a
MutationObserver over the click, the tab goes active at t=43ms and the popup
goes on the next task.
wait: now also takes {gone: <selector>}, which waits for a selector to leave the
DOM, so a script can wait on the vanishing half of an answer. rm38257 uses it.
Six runs each way on genome-test, same build, only the script differing: 6 of 6
green with the new wait:, 3 of 6 red with the old one, failing at the same step
with the same message the nightly printed. The whole directory is green, 98 of
98.
refs #37892, refs #38252
diff --git src/hg/utils/docent/tests/regress/rm38257.docent.yaml src/hg/utils/docent/tests/regress/rm38257.docent.yaml
index 2d838d21231..0578d254056 100644
--- src/hg/utils/docent/tests/regress/rm38257.docent.yaml
+++ src/hg/utils/docent/tests/regress/rm38257.docent.yaml
@@ -1,73 +1,82 @@
# #38257 -- clicking "My Track Hubs" in the Account popup left the popup on screen, and did
# not change the tab either. Only on hgHubConnect, and only there because that is the one
# link in the popup whose target can be the page you are already on.
#
# Nothing in the popup ever closed it. It went away because every link in it loads another
# page, and loading a page takes the whole DOM with it. On hgHubConnect, hgHubConnect.js
# watches for its own links and calls preventDefault() so it can switch tab instead of
# reloading, so no navigation happened and the popup stayed. The popup's overlay also called
# ev.stopPropagation() on every click, so hgHubConnect.js never saw the click and the tab did
# not switch either -- two separate faults with one symptom.
#
# 7d0ceafa7c0, hg/js/topLinks.js. The overlay lets a click on a link through
# (`if (!ev.target.closest("a")) ev.stopPropagation()`), and every link in the popup closes it
# itself on the next tick -- deferred, because detaching the link while its click is still
# being dispatched would rob hgHubConnect.js of the tab switch.
#
# Both halves are asserted, because either one alone would have looked fixed to a reporter
# who only checked the thing they filed: the popup is GONE, and the Connected Hubs tab is the
# active one. The popup is built by JavaScript with inline styles and no id or class of its
# own, so the check for it is the one string it puts on the page that hgHubConnect does not:
# "My Track Hubs" appears nowhere in that page's own markup.
#
# THIS IS THE FIRST SCRIPT IN regress/ THAT LOGS IN. The Account popup only exists for a
# signed-in reader, so there is no way to reach it otherwise. `login:` takes no credentials
# and reads ~/.docentLogin, one section per hgcentral database; genome-test reads
# hgcentraltest, and `make preflight` reports the account it resolved. Anyone without that
# file fails this one script at the login step, which is why it is worth saying here rather
# than leaving the next reader to work it out from a red run.
# NOT YET WATCHED TO FAIL, and the reason is the login rather than the check. Run against
# ticket sandbox 38252 (master with this batch's fixes reverted), the script dies at its
# first step: `login` fails with "Execution context was destroyed, most likely because of a
# navigation", reproducibly, twice. That is the hgLogin redirect race the docent README
# calls a standing open item -- hgLogin answers a good password with returnToURL(150), a
# page that navigates itself -- and it does not happen against genome-test. So this is the
# one script in the batch whose A/B is blocked by the harness, not by the tree. The same
# thing happens against the v503 park (38316), so it is the park and not the build.
proof:
- "assertion-only 2026-09-17 -- written from #38257 and 7d0ceafa7c0 after the fix reached genome-test"
+ - "assertion-only 2026-09-21 -- the wait: was on the wrong half and the script raced itself; put the old wait: back and it goes red on genome-test, with the fix in place"
target: genome-test
db: hg38
# Wide enough to be outside nice_menu.css's @media (max-width: 1100px) rule, which folds the
# top-right links into the hamburger and makes #loginLink invisible. Docent's default
# viewport is 1000px, which is inside it.
size: [1400, 900]
reset: true
fast: true
steps:
- login: true
- goto: "/cgi-bin/hgHubConnect?db=hg38"
- expect:
text: "Connected Hubs"
has: '#loginLink[data-username]'
noText: "My Track Hubs"
# Open the Account popup. #loginLink has href='#' and a handler; the popup is built here.
- click: '#loginLink'
- expect:
text: "Signed in as"
has: 'a:has-text("My Track Hubs")'
# The link that used to do neither of the two things it should.
- click: 'a:has-text("My Track Hubs")'
- # The popup closes on the next tick, after the click has been fully dispatched, so wait
- # for the half that settles last rather than sleeping.
- - wait: 'li.ui-tabs-active a[href="#unlistedHubs"]'
+ # Wait for the POPUP to go, not for the tab to arrive. The two halves do not settle in
+ # the order this script first assumed: hgHubConnect.js switches the tab synchronously
+ # inside the click dispatch, while topLinks.js closes the popup from a
+ # setTimeout(..., 0), so the tab is the half that settles FIRST. Waiting for it returned
+ # a tick early, the expect below read a page that still had the popup on it, and the
+ # script failed about half the time on a build with the fix in it -- 2026-09-19 and 09-20
+ # green, 09-21 red, then two of three reds on a re-run the same morning. Measured with a
+ # MutationObserver over the click: tab active at t=43ms, popup gone on the next task.
+ # "My Track Hubs" is the popup's own string, as the header says, so its removal is the
+ # popup's removal.
+ - wait: {gone: 'text=My Track Hubs'}
- expect:
# The tab really did switch: hgHubConnect.js saw the click.
has: 'li.ui-tabs-active a[href="#unlistedHubs"]'
# ...and the popup is off the page. Both strings it printed are gone.
noText: ["Signed in as", "My Track Hubs"]
# Still on hgHubConnect: the click was answered in place, not by a reload.
url: hgHubConnect