diff --git a/test/tests/zoteroPaneTest.js b/test/tests/zoteroPaneTest.js index 372484032b..63353cdca5 100644 --- a/test/tests/zoteroPaneTest.js +++ b/test/tests/zoteroPaneTest.js @@ -1686,6 +1686,38 @@ describe("ZoteroPane", function () { }); it("should shift-tab across the zotero pane", async function () { + // TEMP: List open windows to diagnose the intermittent timeout + let describeWindows = function () { + let lines = []; + for (let openWin of Services.wm.getEnumerator(null)) { + lines.push("type=" + (openWin.document.documentElement.getAttribute("windowtype") || "") + + ", URL=" + openWin.location.href + + ", title=" + JSON.stringify(openWin.document.title) + + ", active=" + (openWin === Services.focus.activeWindow)); + } + return lines.length ? "\n " + lines.join("\n ") : " (none)"; + }; + let windowsAtStart = describeWindows(); + // Surface the open-window list in the failure message. On a plain + // hang Mocha just reports a context-free 15s timeout and none of our + // code runs, so wrap each await to reject with the window list instead. + // Done this way rather than logging at the start via Zotero.Debug.init(), + // which enables app-wide debug output that adds latency into the focus + // race and could keep the intermittent failure from reproducing. + let withTimeout = function (promise, label) { + let timer; + let timeout = new Promise(function (resolve, reject) { + timer = setTimeout(function () { + reject(new Error("Timed out waiting for " + label + + "\nActive element: " + + (doc.activeElement.id || [...doc.activeElement.classList].join(".")) + + "\nOpen windows at start:" + windowsAtStart + + "\nOpen windows now:" + describeWindows())); + }, 5000); + }); + return Promise.race([promise, timeout]).finally(() => clearTimeout(timer)); + }; + // Start from the Advanced Search button (the last focusable element in the // search field) so the first shift-tab exercises advanced button -> search field let advancedButton = doc.getElementById('zotero-tb-search-advanced-button'); @@ -1713,10 +1745,10 @@ describe("ZoteroPane", function () { } doc.activeElement.dispatchEvent(shiftTab); if (focusPromise) { - await focusPromise; + await withTimeout(focusPromise, "focusin on " + id); } if (hidePromise) { - await hidePromise; + await withTimeout(hidePromise, "collections-search to hide before " + id); } // Some elements don't have id, so use classes to verify they're focused if (doc.activeElement.id) {