describe("Zotero_Tabs", function() { var win, doc, zp; before(async function () { win = await loadZoteroPane(); doc = win.document; zp = win.ZoteroPane; }); after(function () { win.close(); }); describe("Title rendering", function () { it("should render citeproc.js markup in a tab title", async function () { let item = await createDataObject('item', { title: 'Not italic, italic' }); let attachment = await importPDFAttachment(item); let reader = await Zotero.Reader.open(attachment.id); let tab; while (!tab?.textContent.includes('Not italic, italic')) { await Zotero.Promise.delay(10); tab = doc.querySelector(`#tab-bar-container .tab[data-id="${reader.tabID}"]`); } assert.include(tab.querySelector('i').textContent, 'italic'); }); it("should not render unknown markup in a tab title", async function () { let item = await createDataObject('item', { title: 'Something bad ' }); let attachment = await importPDFAttachment(item); let reader = await Zotero.Reader.open(attachment.id); let tab; while (!tab?.textContent.includes('Something bad ')) { await Zotero.Promise.delay(10); tab = doc.querySelector(`#tab-bar-container .tab[data-id="${reader.tabID}"]`); } assert.notOk(tab.querySelector('img')); }); }); describe("#unload()", function () { it("should not make an unloaded tab reopenable", async function () { let item = await createDataObject('item'); let attachment = await importPDFAttachment(item); let reader = await Zotero.Reader.open(attachment.id); let tabs = win.Zotero_Tabs; tabs.select('zotero-pane'); let historyLength = tabs._history.length; tabs.unload(reader.tabID); let { tab } = tabs._getTab(reader.tabID); assert.equal(tab.type, 'reader-unloaded'); assert.lengthOf(tabs._history, historyLength); tabs.close(reader.tabID); }); }); describe("Window teardown", function () { it("should not leave observers registered after a window is closed", async function () { this.timeout(60000); let collection = await createDataObject('collection'); let item = await createDataObject('item', { collections: [collection.id] }); let notifierBefore = new Set(Zotero.Notifier.getLeakedObserverIDs()); let prefsBefore = Zotero.Prefs.getLeakedObserverNames(); // Render the library item pane in a second window let win2 = await loadZoteroPane(); await selectCollection(win2, collection); await win2.ZoteroPane.selectItem(item.id); // The window's observers are still registered while it tears down, and shouldn't be // reported as leaked before it's actually gone let leakedWhileUnloading = null; win2.addEventListener('pagehide', () => { leakedWhileUnloading = Zotero.Notifier.getLeakedObserverIDs() .filter(id => !notifierBefore.has(id)); }); // An object that nothing unregisters, so that it starts reporting as leaked as soon // as the window has finished tearing down let root = win2.document.documentElement; win2.close(); await waitForCallback( () => Zotero.Utilities.Internal.isObjectLeakingWindow(root), 50, 20 ); assert.deepEqual( leakedWhileUnloading, [], 'no observers are reported as leaked while unloading' ); let notifierAfter = Zotero.Notifier.getLeakedObserverIDs() .filter(id => !notifierBefore.has(id)); assert.isEmpty(notifierAfter, 'no notifier observers belong to a closed window'); let prefsAfter = Zotero.Prefs.getLeakedObserverNames(); for (let name of prefsBefore) { let index = prefsAfter.indexOf(name); if (index != -1) { prefsAfter.splice(index, 1); } } assert.isEmpty(prefsAfter, 'no pref observers belong to a closed window'); }); }); });