describe("CollectionTreeRow", function () { var win, zp, cv, userLibraryID; before(async function () { win = await loadZoteroPane(); zp = win.ZoteroPane; cv = zp.collectionsView; userLibraryID = Zotero.Libraries.userLibraryID; }); beforeEach(function () { return selectLibrary(win); }); after(function () { win.close(); }); describe("Search cache", function () { var collectionTreeRow; // Stub getSearchObject on a collectionTreeRow so that the search's .search() throws, // simulating a broken saved search (e.g., "too many SQL variables"). function stubBrokenSearch(ctr) { return sinon.stub(ctr, 'getSearchObject').resolves({ search: () => { throw new Error('simulated search failure'); } }); } beforeEach(function () { collectionTreeRow = zp.getCollectionTreeRows()[0]; collectionTreeRow.clearCache(); }); afterEach(function () { collectionTreeRow.setSearch(''); collectionTreeRow.setTags([]); }); it("should memoize getSearchResults() within a refresh cycle", async function () { var results1 = await collectionTreeRow.getSearchResults(); var results2 = await collectionTreeRow.getSearchResults(); assert.strictEqual(results1, results2, 'should return same cached array'); }); it("should memoize getSearchObject() within a refresh cycle", async function () { var search1 = await collectionTreeRow.getSearchObject(); var search2 = await collectionTreeRow.getSearchObject(); assert.strictEqual(search1, search2, 'should return same cached search'); }); it("should invalidate cache on clearCache()", async function () { var results1 = await collectionTreeRow.getSearchResults(); collectionTreeRow.clearCache(); var results2 = await collectionTreeRow.getSearchResults(); assert.notStrictEqual(results1, results2, 'should return new array after clearCache()'); }); it("should invalidate cache when setSearch() changes filters", async function () { await collectionTreeRow.getSearchResults(); assert.isNotNull(collectionTreeRow._cachedResults); collectionTreeRow.setSearch('test-query'); assert.isNull(collectionTreeRow._cachedResults); assert.isNull(collectionTreeRow._cachedSearch); }); it("should not invalidate cache when setSearch() is called with same value", async function () { collectionTreeRow.setSearch('same'); await collectionTreeRow.getSearchResults(); var cached = collectionTreeRow._cachedResults; assert.isNotNull(cached); collectionTreeRow.setSearch('same'); assert.strictEqual(collectionTreeRow._cachedResults, cached, 'cache should survive idempotent setSearch()'); }); it("should throw SearchError on search failure", async function () { var stub = stubBrokenSearch(collectionTreeRow); try { var err; try { await collectionTreeRow.getSearchResults(); } catch (e) { err = e; } assert.ok(err, 'getSearchResults() should throw'); assert.instanceOf(err, Zotero.CollectionTreeRow.SearchError); } finally { stub.restore(); } }); it("should propagate SearchError through getItems()", async function () { var stub = stubBrokenSearch(collectionTreeRow); try { var err; try { await collectionTreeRow.getItems(); } catch (e) { err = e; } assert.ok(err, 'getItems() should throw'); assert.instanceOf(err, Zotero.CollectionTreeRow.SearchError); } finally { stub.restore(); } }); it("should propagate SearchError through getTags()", async function () { var stub = stubBrokenSearch(collectionTreeRow); try { var err; try { await collectionTreeRow.getTags(); } catch (e) { err = e; } assert.ok(err, 'getTags() should throw'); assert.instanceOf(err, Zotero.CollectionTreeRow.SearchError); } finally { stub.restore(); } }); }); describe("Unfiled Items", function () { // https://github.com/zotero/zotero/issues/2771 it("shouldn't show filed attachments with annotations", async function () { var item1 = await createDataObject('item'); var collection = await createDataObject('collection'); var item2 = await createDataObject('item', { collections: [collection.id] }); var attachment = await importPDFAttachment(item2); var annotation = await createAnnotation('highlight', attachment); cv.selectByID("U" + userLibraryID); await waitForItemsLoad(win); var itemsView = zp.itemsView; assert.isNumber(itemsView.getRowIndexByID(item1.id)); assert.isFalse(itemsView.getRowIndexByID(item2.id)); }); }); });