6af92621b7dba437be69c05f3ff49079ba637383 braney Fri Sep 4 11:43:39 2026 -0700 docent: let convert: take a bare string, like every other verb convert: hs1 left the argument as a String, so o.to was undefined and o.search picked up String.prototype.search. The run then reported convert: "function search() { [native code] }" matched nothing which says nothing about what is wrong with the script. A bare string is now the target assembly, matching hub:, addCustomTrack:, loadSession: and the rest. quicklift: is still never implied, so convert: hs1 is a plain coordinate convert; the README row says so now. Found while writing the first of the regression tests for #38252, fourteen of which open with convert:. refs #37892 diff --git src/hg/utils/docent/docent.js src/hg/utils/docent/docent.js index c8604e635d1..faa72a30d3b 100755 --- src/hg/utils/docent/docent.js +++ src/hg/utils/docent/docent.js @@ -1395,31 +1395,36 @@ async function resolveTarget(to) { if (/^GC[AF]_/i.test(to)) return to; const matches = await page.$$eval('#hglft_toDbSelect option', (os, q) => { const norm = t => t.toLowerCase().replace(/[^a-z0-9]+/g, ' '); const toks = norm(q).trim().split(' ').filter(Boolean); return os.filter(o => toks.every(tk => norm(o.text).includes(tk))).map(o => ({ v: o.value, t: o.text })); }, String(to)); if (!matches.length) throw new Error('convert target not found in Assembly dropdown: ' + to); if (matches.length > 1) { console.warn(`WARNING: "${to}" matches ${matches.length} assemblies; using the first. Use an exact accession to disambiguate:`); matches.forEach(m => console.warn(` ${m.v} ${m.t}`)); } return matches[0].v; } async function convert(o) { - o = o || {}; + // A bare string is the target assembly, the way every other verb takes its one + // obvious argument. Without this `convert: hs1` left o as the String, so o.to was + // undefined and o.search picked up String.prototype.search -- the run then reported + // `convert: "function search() { [native code] }" matched nothing`, which tells the + // reader nothing about what is wrong with their script. + o = (typeof o === 'string') ? { to: o } : (o || {}); // `shot:` here can name up to three moments of the Convert page, none of which any // other verb can reach (after Submit the tour is already on the results page): // shot: convert_filled -- just before Submit (the common one) // shot: {opened: a, filled: b, result: c} // opened the page as it comes up, nothing chosen yet // filled target searched for, QuickLift/Hide-defaults set -- ready to Submit // result the conversion result page (the coordinate link `open: lift` clicks) const shots = (o.shot == null) ? {} : (typeof o.shot === 'string' ? { filled: o.shot } : o.shot); for (const k of Object.keys(shots)) if (!['opened', 'filled', 'result'].includes(k)) console.warn(`convert shot: unknown moment "${k}" (use opened, filled or result)`); try { await glideTo('#view'); await page.hover('#view'); await dwell(900); await clickGlide('a#convertMenuLink'); await page.waitForSelector('#hglft_toDbSelect', { timeout: 8000 });