From 49130c71d839f24f5b84fcefd6347bdacd6cc5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adomas=20Ven=C4=8Dkauskas?= Date: Fri, 31 Oct 2025 12:27:52 +0200 Subject: [PATCH] Fix connector save timing out with Advanced Search Report: https://forums.zotero.org/discussion/127760/connector-conflict-with-advanced-search Also restore Advanced Search tests that depend on the item tree. They were disabled due to React timing issues. Hopefully with these changes the initialization of the tree is more robust. --- chrome/content/zotero/advancedSearch.js | 4 ++- chrome/content/zotero/libraryTree.js | 2 +- test/tests/advancedSearchTest.js | 14 ++++----- test/tests/itemTreeTest.js | 38 +++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/chrome/content/zotero/advancedSearch.js b/chrome/content/zotero/advancedSearch.js index 2ad68bbefb..6aff0c6686 100644 --- a/chrome/content/zotero/advancedSearch.js +++ b/chrome/content/zotero/advancedSearch.js @@ -35,6 +35,7 @@ var ZoteroAdvancedSearch = new function () { this.onItemActivate = onItemActivate; this.itemsView = false; + this._loadedDeferred = Zotero.Promise.defer(); var _searchBox; var _libraryID; @@ -69,7 +70,7 @@ var ZoteroAdvancedSearch = new function () { columns, }); - this.itemsView.changeCollectionTreeRow({ + await this.itemsView.changeCollectionTreeRow({ ref: _searchBox.search, visibilityGroup: 'default', isSearchMode: () => true, @@ -89,6 +90,7 @@ var ZoteroAdvancedSearch = new function () { // Focus the first field in the window Services.focus.moveFocus(window, null, Services.focus.MOVEFOCUS_FORWARD, 0); + this._loadedDeferred.resolve(); } this.onUnload = function () { diff --git a/chrome/content/zotero/libraryTree.js b/chrome/content/zotero/libraryTree.js index 1325ad3005..219274d026 100644 --- a/chrome/content/zotero/libraryTree.js +++ b/chrome/content/zotero/libraryTree.js @@ -200,8 +200,8 @@ var LibraryTree = class LibraryTree extends React.Component { try { await Zotero.Promise.resolve(this.props.onSelectionChange(this.selection)); } catch (e) {} - this.runListeners('select'); } + this.runListeners('select'); } _onSelectionChangeDebounced = Zotero.Utilities.debounce(this._onSelectionChange, 100) diff --git a/test/tests/advancedSearchTest.js b/test/tests/advancedSearchTest.js index 71d6cb513d..455409d4a1 100644 --- a/test/tests/advancedSearchTest.js +++ b/test/tests/advancedSearchTest.js @@ -16,18 +16,13 @@ describe("Advanced Search", function () { win.close(); }); - // TEMP: React timing issue - figure this out - it.skip("should perform a search", function* () { + it("should perform a search", function* () { var item = yield createDataObject('item', { setTitle: true }); - var promise = waitForWindow('chrome://zotero/content/advancedSearch.xhtml', async (win) => { - // Wait for the itemsView to be initialized in the onload listener of the window - while (!win.ZoteroAdvancedSearch.itemsView) { - await Zotero.Promise.delay(5); - } - }); + var promise = waitForWindow('chrome://zotero/content/advancedSearch.xhtml'); zp.openAdvancedSearchWindow(); var searchWin = yield promise; + yield searchWin.ZoteroAdvancedSearch._loadedDeferred.promise; // Add condition var searchBox = searchWin.document.getElementById('zotero-search-box'); @@ -37,9 +32,10 @@ describe("Advanced Search", function () { // Run search and wait for results var o = searchWin.ZoteroAdvancedSearch; - yield o.search(); var iv = o.itemsView; yield iv.waitForLoad(); + yield o.search(); + yield iv.waitForLoad(); // Check results assert.equal(iv.rowCount, 1); diff --git a/test/tests/itemTreeTest.js b/test/tests/itemTreeTest.js index f1af8979ca..428f920453 100644 --- a/test/tests/itemTreeTest.js +++ b/test/tests/itemTreeTest.js @@ -1864,4 +1864,42 @@ describe("Zotero.ItemTree", function () { assert.include(text, toplevelItemTwo.getDisplayTitle()); }); }); + + describe('Advanced Search', function () { + describe('#notify', function () { + it('should resolve the returned promise when an item is selected', async function() { + var item = await createDataObject('item', { setTitle: true }); + var promise = waitForWindow('chrome://zotero/content/advancedSearch.xhtml'); + zp.openAdvancedSearchWindow(); + var searchWin = await promise; + await searchWin.ZoteroAdvancedSearch._loadedDeferred.promise; + // Add condition + var searchBox = searchWin.document.getElementById('zotero-search-box'); + + var s = new Zotero.Search(); + s.addCondition('title', 'is', item.getField('title')) + searchBox.search = s; + + // Run search and wait for results + var o = searchWin.ZoteroAdvancedSearch; + var iv = o.itemsView; + await iv.waitForLoad(); + await o.search(); + await iv.waitForLoad(); + + // Check results + assert.equal(iv.rowCount, 1); + + // Make sure an item is selected (otherwise notify resolves fine) + await iv.selectItem(item.id); + assert.equal(iv.selection.count, 1); + + let notifySpy = sinon.spy(iv, 'notify'); + await createDataObject('item'); + assert.isTrue(notifySpy.calledOnce); + await notifySpy.returnValues[0]; + notifySpy.restore(); + }); + }); + }); })