zoteroPaneTest.js (22510B)
1 "use strict"; 2 3 describe("ZoteroPane", function() { 4 var win, doc, zp, userLibraryID; 5 6 // Load Zotero pane and select library 7 before(function* () { 8 win = yield loadZoteroPane(); 9 doc = win.document; 10 zp = win.ZoteroPane; 11 userLibraryID = Zotero.Libraries.userLibraryID; 12 }); 13 14 after(function () { 15 win.close(); 16 }); 17 18 describe("#newItem", function () { 19 it("should create an item and focus the title field", function* () { 20 yield zp.newItem(Zotero.ItemTypes.getID('book'), {}, null, true); 21 var itemBox = doc.getElementById('zotero-editpane-item-box'); 22 var textboxes = doc.getAnonymousNodes(itemBox)[0].getElementsByTagName('textbox'); 23 assert.lengthOf(textboxes, 1); 24 assert.equal(textboxes[0].getAttribute('fieldname'), 'title'); 25 textboxes[0].blur(); 26 yield Zotero.Promise.delay(1); 27 }) 28 29 it("should save an entered value when New Item is used", function* () { 30 var value = "Test"; 31 var item = yield zp.newItem(Zotero.ItemTypes.getID('book'), {}, null, true); 32 var itemBox = doc.getElementById('zotero-editpane-item-box'); 33 var textbox = doc.getAnonymousNodes(itemBox)[0].getElementsByTagName('textbox')[0]; 34 textbox.value = value; 35 yield itemBox.blurOpenField(); 36 item = yield Zotero.Items.getAsync(item.id); 37 assert.equal(item.getField('title'), value); 38 }) 39 }); 40 41 describe("#newNote()", function () { 42 it("should create a child note and select it", function* () { 43 var item = yield createDataObject('item'); 44 var noteID = yield zp.newNote(false, item.key, "Test"); 45 var selected = zp.itemsView.getSelectedItems(true); 46 assert.lengthOf(selected, 1); 47 assert.equal(selected, noteID); 48 }) 49 50 it("should create a standalone note within a collection and select it", function* () { 51 var collection = yield createDataObject('collection'); 52 var noteID = yield zp.newNote(false, false, "Test"); 53 assert.equal(zp.collectionsView.getSelectedCollection(), collection); 54 var selected = zp.itemsView.getSelectedItems(true); 55 assert.lengthOf(selected, 1); 56 assert.equal(selected, noteID); 57 }) 58 }) 59 60 describe("#newCollection()", function () { 61 it("should create a collection", function* () { 62 var promise = waitForDialog(); 63 var id = yield zp.newCollection(); 64 yield promise; 65 var collection = Zotero.Collections.get(id); 66 assert.isTrue(collection.name.startsWith(Zotero.getString('pane.collections.untitled'))); 67 }); 68 }); 69 70 describe("#newSearch()", function () { 71 it("should create a saved search", function* () { 72 var promise = waitForDialog( 73 // TODO: Test changing a condition 74 function (dialog) {}, 75 'accept', 76 'chrome://zotero/content/searchDialog.xul' 77 ); 78 var id = yield zp.newSearch(); 79 yield promise; 80 var search = Zotero.Searches.get(id); 81 assert.ok(search); 82 assert.isTrue(search.name.startsWith(Zotero.getString('pane.collections.untitled'))); 83 }); 84 85 it("should handle clicking Cancel in the search window", function* () { 86 var promise = waitForDialog( 87 function (dialog) {}, 88 'cancel', 89 'chrome://zotero/content/searchDialog.xul' 90 ); 91 var id = yield zp.newSearch(); 92 yield promise; 93 assert.isFalse(id); 94 }); 95 }); 96 97 describe("#itemSelected()", function () { 98 it.skip("should update the item count", function* () { 99 var collection = new Zotero.Collection; 100 collection.name = "Count Test"; 101 var id = yield collection.saveTx(); 102 yield waitForItemsLoad(win); 103 104 // Unselected, with no items in view 105 assert.equal( 106 doc.getElementById('zotero-item-pane-message-box').textContent, 107 Zotero.getString('pane.item.unselected.zero', 0) 108 ); 109 110 // Unselected, with one item in view 111 var item = new Zotero.Item('newspaperArticle'); 112 item.setCollections([id]); 113 var itemID1 = yield item.saveTx({ 114 skipSelect: true 115 }); 116 assert.equal( 117 doc.getElementById('zotero-item-pane-message-box').textContent, 118 Zotero.getString('pane.item.unselected.singular', 1) 119 ); 120 121 // Unselected, with multiple items in view 122 var item = new Zotero.Item('audioRecording'); 123 item.setCollections([id]); 124 var itemID2 = yield item.saveTx({ 125 skipSelect: true 126 }); 127 assert.equal( 128 doc.getElementById('zotero-item-pane-message-box').textContent, 129 Zotero.getString('pane.item.unselected.plural', 2) 130 ); 131 132 // Multiple items selected 133 var promise = zp.itemsView._getItemSelectedPromise(); 134 zp.itemsView.rememberSelection([itemID1, itemID2]); 135 yield promise; 136 assert.equal( 137 doc.getElementById('zotero-item-pane-message-box').textContent, 138 Zotero.getString('pane.item.selected.multiple', 2) 139 ); 140 }) 141 }) 142 143 describe("#viewAttachment", function () { 144 Components.utils.import("resource://zotero-unit/httpd.js"); 145 var apiKey = Zotero.Utilities.randomString(24); 146 var port = 16213; 147 var baseURL = `http://localhost:${port}/`; 148 var server; 149 var responses = {}; 150 var httpd; 151 152 var setup = Zotero.Promise.coroutine(function* (options = {}) { 153 server = sinon.fakeServer.create(); 154 server.autoRespond = true; 155 }); 156 157 function setResponse(response) { 158 setHTTPResponse(server, baseURL, response, responses); 159 } 160 161 async function downloadOnDemand() { 162 var item = new Zotero.Item("attachment"); 163 item.attachmentLinkMode = 'imported_file'; 164 item.attachmentPath = 'storage:test.txt'; 165 // TODO: Test binary data 166 var text = Zotero.Utilities.randomString(); 167 item.attachmentSyncState = "to_download"; 168 await item.saveTx(); 169 170 var mtime = "1441252524000"; 171 var md5 = Zotero.Utilities.Internal.md5(text) 172 173 var s3Path = `pretend-s3/${item.key}`; 174 httpd.registerPathHandler( 175 `/users/1/items/${item.key}/file`, 176 { 177 handle: function (request, response) { 178 response.setStatusLine(null, 302, "Found"); 179 response.setHeader("Zotero-File-Modification-Time", mtime, false); 180 response.setHeader("Zotero-File-MD5", md5, false); 181 response.setHeader("Zotero-File-Compressed", "No", false); 182 response.setHeader("Location", baseURL + s3Path, false); 183 } 184 } 185 ); 186 httpd.registerPathHandler( 187 "/" + s3Path, 188 { 189 handle: function (request, response) { 190 response.setStatusLine(null, 200, "OK"); 191 response.write(text); 192 } 193 } 194 ); 195 196 // Disable loadURI() so viewAttachment() doesn't trigger translator loading 197 var stub = sinon.stub(zp, "loadURI"); 198 199 await zp.viewAttachment(item.id); 200 201 assert.ok(stub.calledOnce); 202 assert.ok(stub.calledWith(OS.Path.toFileURI(item.getFilePath()))); 203 stub.restore(); 204 205 assert.equal(await item.attachmentHash, md5); 206 assert.equal(await item.attachmentModificationTime, mtime); 207 var path = await item.getFilePathAsync(); 208 assert.equal(await Zotero.File.getContentsAsync(path), text); 209 }; 210 211 before(function () { 212 Zotero.HTTP.mock = sinon.FakeXMLHttpRequest; 213 }) 214 beforeEach(function* () { 215 Zotero.Prefs.set("api.url", baseURL); 216 Zotero.Sync.Runner.apiKey = apiKey; 217 218 httpd = new HttpServer(); 219 httpd.start(port); 220 221 yield Zotero.Users.setCurrentUserID(1); 222 yield Zotero.Users.setCurrentUsername("testuser"); 223 }) 224 afterEach(function* () { 225 var defer = new Zotero.Promise.defer(); 226 httpd.stop(() => defer.resolve()); 227 yield defer.promise; 228 }) 229 after(function () { 230 Zotero.HTTP.mock = null; 231 }); 232 233 it("should download an attachment on-demand in as-needed mode", function* () { 234 yield setup(); 235 Zotero.Sync.Storage.Local.downloadAsNeeded(Zotero.Libraries.userLibraryID, true); 236 yield downloadOnDemand(); 237 }); 238 239 it("should download an attachment on-demand in at-sync-time mode", function* () { 240 yield setup(); 241 Zotero.Sync.Storage.Local.downloadOnSync(Zotero.Libraries.userLibraryID, true); 242 yield downloadOnDemand(); 243 }); 244 }) 245 246 247 describe("#renameSelectedAttachmentsFromParents()", function () { 248 it("should rename a linked file", async function () { 249 var oldFilename = 'old.png'; 250 var newFilename = 'Test.png'; 251 var file = getTestDataDirectory(); 252 file.append('test.png'); 253 var tmpDir = await getTempDirectory(); 254 var oldFile = OS.Path.join(tmpDir, oldFilename); 255 await OS.File.copy(file.path, oldFile); 256 257 var item = createUnsavedDataObject('item'); 258 item.setField('title', 'Test'); 259 await item.saveTx(); 260 261 var attachment = await Zotero.Attachments.linkFromFile({ 262 file: oldFile, 263 parentItemID: item.id 264 }); 265 await zp.selectItem(attachment.id); 266 267 await assert.eventually.isTrue(zp.renameSelectedAttachmentsFromParents()); 268 assert.equal(attachment.attachmentFilename, newFilename); 269 var path = await attachment.getFilePathAsync(); 270 assert.equal(OS.Path.basename(path), newFilename) 271 await OS.File.exists(path); 272 }); 273 274 it("should use unique name for linked file if target name is taken", async function () { 275 var oldFilename = 'old.png'; 276 var newFilename = 'Test.png'; 277 var uniqueFilename = 'Test 2.png'; 278 var file = getTestDataDirectory(); 279 file.append('test.png'); 280 var tmpDir = await getTempDirectory(); 281 var oldFile = OS.Path.join(tmpDir, oldFilename); 282 await OS.File.copy(file.path, oldFile); 283 // Create file with target filename 284 await Zotero.File.putContentsAsync(OS.Path.join(tmpDir, newFilename), ''); 285 286 var item = createUnsavedDataObject('item'); 287 item.setField('title', 'Test'); 288 await item.saveTx(); 289 290 var attachment = await Zotero.Attachments.linkFromFile({ 291 file: oldFile, 292 parentItemID: item.id 293 }); 294 await zp.selectItem(attachment.id); 295 296 await assert.eventually.isTrue(zp.renameSelectedAttachmentsFromParents()); 297 assert.equal(attachment.attachmentFilename, uniqueFilename); 298 var path = await attachment.getFilePathAsync(); 299 assert.equal(OS.Path.basename(path), uniqueFilename) 300 await OS.File.exists(path); 301 }); 302 303 it("should use unique name for linked file without extension if target name is taken", async function () { 304 var oldFilename = 'old'; 305 var newFilename = 'Test'; 306 var uniqueFilename = 'Test 2'; 307 var file = getTestDataDirectory(); 308 file.append('test.png'); 309 var tmpDir = await getTempDirectory(); 310 var oldFile = OS.Path.join(tmpDir, oldFilename); 311 await OS.File.copy(file.path, oldFile); 312 // Create file with target filename 313 await Zotero.File.putContentsAsync(OS.Path.join(tmpDir, newFilename), ''); 314 315 var item = createUnsavedDataObject('item'); 316 item.setField('title', 'Test'); 317 await item.saveTx(); 318 319 var attachment = await Zotero.Attachments.linkFromFile({ 320 file: oldFile, 321 parentItemID: item.id 322 }); 323 await zp.selectItem(attachment.id); 324 325 await assert.eventually.isTrue(zp.renameSelectedAttachmentsFromParents()); 326 assert.equal(attachment.attachmentFilename, uniqueFilename); 327 var path = await attachment.getFilePathAsync(); 328 assert.equal(OS.Path.basename(path), uniqueFilename) 329 await OS.File.exists(path); 330 }); 331 }); 332 333 334 describe("#duplicateSelectedItem()", function () { 335 it("should add reverse relations", async function () { 336 await selectLibrary(win); 337 var item1 = await createDataObject('item'); 338 var item2 = await createDataObject('item'); 339 item1.addRelatedItem(item2); 340 await item1.saveTx(); 341 item2.addRelatedItem(item1); 342 await item2.saveTx(); 343 var item3 = await zp.duplicateSelectedItem(); 344 assert.sameMembers(item3.relatedItems, [item1.key]); 345 assert.sameMembers(item2.relatedItems, [item1.key]); 346 assert.sameMembers(item1.relatedItems, [item2.key, item3.key]); 347 }); 348 }); 349 350 351 describe("#deleteSelectedItems()", function () { 352 it("should remove an item from My Publications", function* () { 353 var item = createUnsavedDataObject('item'); 354 item.inPublications = true; 355 yield item.saveTx(); 356 357 yield zp.collectionsView.selectByID("P" + userLibraryID); 358 yield waitForItemsLoad(win); 359 var iv = zp.itemsView; 360 361 var selected = iv.selectItem(item.id); 362 assert.ok(selected); 363 364 var tree = doc.getElementById('zotero-items-tree'); 365 tree.focus(); 366 367 yield Zotero.Promise.delay(1); 368 369 var promise = waitForDialog(); 370 var modifyPromise = waitForItemEvent('modify'); 371 372 var event = doc.createEvent("KeyboardEvent"); 373 event.initKeyEvent("keypress", true, true, window, false, false, false, false, 46, 0); 374 tree.dispatchEvent(event); 375 yield promise; 376 yield modifyPromise; 377 378 assert.isFalse(item.inPublications); 379 assert.isFalse(item.deleted); 380 }); 381 382 it("should move an item to trash from My Publications", function* () { 383 var item = createUnsavedDataObject('item'); 384 item.inPublications = true; 385 yield item.saveTx(); 386 387 yield zp.collectionsView.selectByID("P" + userLibraryID); 388 yield waitForItemsLoad(win); 389 var iv = zp.itemsView; 390 391 var selected = iv.selectItem(item.id); 392 assert.ok(selected); 393 394 var tree = doc.getElementById('zotero-items-tree'); 395 tree.focus(); 396 397 yield Zotero.Promise.delay(1); 398 399 var promise = waitForDialog(); 400 var modifyPromise = waitForItemEvent('modify'); 401 402 var event = doc.createEvent("KeyboardEvent"); 403 event.initKeyEvent( 404 "keypress", 405 true, 406 true, 407 window, 408 false, 409 false, 410 !Zotero.isMac, // shift 411 Zotero.isMac, // meta 412 46, 413 0 414 ); 415 tree.dispatchEvent(event); 416 yield promise; 417 yield modifyPromise; 418 419 assert.isTrue(item.inPublications); 420 assert.isTrue(item.deleted); 421 }); 422 }); 423 424 describe("#deleteSelectedCollection()", function () { 425 it("should delete collection but not descendant items by default", function* () { 426 var collection = yield createDataObject('collection'); 427 var item = yield createDataObject('item', { collections: [collection.id] }); 428 var promise = waitForDialog(); 429 yield zp.deleteSelectedCollection(); 430 assert.isFalse(Zotero.Collections.exists(collection.id)); 431 assert.isTrue(Zotero.Items.exists(item.id)); 432 assert.isFalse(item.deleted); 433 }); 434 435 it("should delete collection and descendant items when deleteItems=true", function* () { 436 var collection = yield createDataObject('collection'); 437 var item = yield createDataObject('item', { collections: [collection.id] }); 438 var promise = waitForDialog(); 439 yield zp.deleteSelectedCollection(true); 440 assert.isFalse(Zotero.Collections.exists(collection.id)); 441 assert.isTrue(Zotero.Items.exists(item.id)); 442 assert.isTrue(item.deleted); 443 }); 444 }); 445 446 447 describe("#setVirtual()", function () { 448 var cv; 449 450 before(function* () { 451 cv = zp.collectionsView; 452 }); 453 beforeEach(function () { 454 Zotero.Prefs.clear('duplicateLibraries'); 455 Zotero.Prefs.clear('unfiledLibraries'); 456 return selectLibrary(win); 457 }) 458 459 it("should show a hidden virtual collection in My Library", function* () { 460 // Create unfiled, duplicate items 461 var title = Zotero.Utilities.randomString(); 462 var item1 = yield createDataObject('item', { title }); 463 var item2 = yield createDataObject('item', { title }); 464 465 // Start hidden (tested in collectionTreeViewTest) 466 Zotero.Prefs.set('duplicateLibraries', `{"${userLibraryID}": false}`); 467 Zotero.Prefs.set('unfiledLibraries', `{"${userLibraryID}": false}`); 468 yield cv.refresh(); 469 470 // Show Duplicate Items 471 var id = "D" + userLibraryID; 472 assert.isFalse(cv.getRowIndexByID(id)); 473 yield zp.setVirtual(userLibraryID, 'duplicates', true); 474 // Duplicate Items should be selected 475 assert.equal(cv.selectedTreeRow.id, id); 476 // Should be missing from pref 477 assert.isUndefined(JSON.parse(Zotero.Prefs.get('duplicateLibraries'))[userLibraryID]) 478 479 // Clicking should select both items 480 var row = cv.getRowIndexByID(id); 481 assert.ok(row); 482 assert.equal(cv.selection.currentIndex, row); 483 yield waitForItemsLoad(win); 484 var iv = zp.itemsView; 485 row = iv.getRowIndexByID(item1.id); 486 assert.isNumber(row); 487 clickOnItemsRow(iv, row); 488 assert.equal(iv.selection.count, 2); 489 490 // Show Unfiled Items 491 id = "U" + userLibraryID; 492 assert.isFalse(cv.getRowIndexByID(id)); 493 yield zp.setVirtual(userLibraryID, 'unfiled', true); 494 // Unfiled Items should be selected 495 assert.equal(cv.selectedTreeRow.id, id); 496 // Should be missing from pref 497 assert.isUndefined(JSON.parse(Zotero.Prefs.get('unfiledLibraries'))[userLibraryID]) 498 }); 499 500 it("should expand library if collapsed when showing virtual collection", function* () { 501 // Start hidden (tested in collectionTreeViewTest) 502 Zotero.Prefs.set('duplicateLibraries', `{"${userLibraryID}": false}`); 503 yield cv.refresh(); 504 505 var libraryRow = cv.getRowIndexByID(Zotero.Libraries.userLibrary.treeViewID); 506 if (cv.isContainerOpen(libraryRow)) { 507 yield cv.toggleOpenState(libraryRow); 508 cv._saveOpenStates(); 509 } 510 511 // Show Duplicate Items 512 var id = "D" + userLibraryID; 513 yield zp.setVirtual(userLibraryID, 'duplicates', true); 514 515 // Library should have been expanded and Duplicate Items selected 516 assert.ok(cv.getRowIndexByID(id)); 517 assert.equal(cv.selectedTreeRow.id, id); 518 }); 519 520 it("should hide a virtual collection in My Library", function* () { 521 yield cv.refresh(); 522 523 // Hide Duplicate Items 524 var id = "D" + userLibraryID; 525 assert.ok(yield cv.selectByID(id)); 526 yield zp.setVirtual(userLibraryID, 'duplicates', false); 527 assert.isFalse(cv.getRowIndexByID(id)); 528 assert.isFalse(JSON.parse(Zotero.Prefs.get('duplicateLibraries'))[userLibraryID]) 529 530 // Hide Unfiled Items 531 id = "U" + userLibraryID; 532 assert.ok(yield cv.selectByID(id)); 533 yield zp.setVirtual(userLibraryID, 'unfiled', false); 534 assert.isFalse(cv.getRowIndexByID(id)); 535 assert.isFalse(JSON.parse(Zotero.Prefs.get('unfiledLibraries'))[userLibraryID]) 536 }); 537 538 it("should hide a virtual collection in a group", function* () { 539 yield cv.refresh(); 540 541 var group = yield createGroup(); 542 var groupRow = cv.getRowIndexByID(group.treeViewID); 543 var rowCount = cv.rowCount; 544 545 // Make sure group is open 546 if (!cv.isContainerOpen(groupRow)) { 547 yield cv.toggleOpenState(groupRow); 548 } 549 550 // Make sure Duplicate Items is showing 551 var id = "D" + group.libraryID; 552 assert.ok(cv.getRowIndexByID(id)); 553 554 // Hide Duplicate Items 555 assert.ok(yield cv.selectByID(id)); 556 yield zp.setVirtual(group.libraryID, 'duplicates', false); 557 // Row should have been removed 558 assert.isFalse(cv.getRowIndexByID(id)); 559 // Pref should have been updated 560 Zotero.debug(Zotero.Prefs.get('duplicateLibraries')); 561 assert.isFalse(JSON.parse(Zotero.Prefs.get('duplicateLibraries'))[group.libraryID]); 562 // Group row shouldn't have changed 563 assert.equal(cv.getRowIndexByID(group.treeViewID), groupRow); 564 // Group should remain open 565 assert.isTrue(cv.isContainerOpen(groupRow)); 566 // Row count should be 1 less 567 assert.equal(cv.rowCount, --rowCount); 568 569 // Hide Unfiled Items 570 id = "U" + group.libraryID; 571 assert.ok(yield cv.selectByID(id)); 572 // Hide Unfiled Items 573 yield zp.setVirtual(group.libraryID, 'unfiled', false); 574 // Row should have been removed 575 assert.isFalse(cv.getRowIndexByID(id)); 576 // Pref should have been udpated 577 assert.isFalse(JSON.parse(Zotero.Prefs.get('unfiledLibraries'))[group.libraryID]); 578 // Group row shouldn't have changed 579 assert.equal(cv.getRowIndexByID(group.treeViewID), groupRow); 580 // Group should remain open 581 assert.isTrue(cv.isContainerOpen(groupRow)); 582 // Row count should be 1 less 583 assert.equal(cv.rowCount, --rowCount); 584 }); 585 }); 586 587 describe("#editSelectedCollection()", function () { 588 it("should edit a saved search", function* () { 589 var search = yield createDataObject('search'); 590 var promise = waitForWindow('chrome://zotero/content/searchDialog.xul', function (win) { 591 let searchBox = win.document.getElementById('search-box'); 592 var c = searchBox.search.getCondition( 593 searchBox.search.addCondition("title", "contains", "foo") 594 ); 595 searchBox.addCondition(c); 596 win.document.documentElement.acceptDialog(); 597 }); 598 yield zp.editSelectedCollection(); 599 yield promise; 600 var conditions = search.getConditions(); 601 assert.lengthOf(Object.keys(conditions), 3); 602 }); 603 604 it("should edit a saved search in a group", function* () { 605 var group = yield getGroup(); 606 var search = yield createDataObject('search', { libraryID: group.libraryID }); 607 var promise = waitForWindow('chrome://zotero/content/searchDialog.xul', function (win) { 608 let searchBox = win.document.getElementById('search-box'); 609 var c = searchBox.search.getCondition( 610 searchBox.search.addCondition("title", "contains", "foo") 611 ); 612 searchBox.addCondition(c); 613 win.document.documentElement.acceptDialog(); 614 }); 615 yield zp.editSelectedCollection(); 616 yield promise; 617 var conditions = search.getConditions(); 618 assert.lengthOf(Object.keys(conditions), 3); 619 }); 620 }); 621 622 describe("#onCollectionSelected()", function() { 623 var cv; 624 625 beforeEach(function* () { 626 cv = zp.collectionsView; 627 yield cv.selectLibrary(Zotero.Libraries.userLibraryID); 628 Zotero.Prefs.clear('itemsView.columnVisibility'); 629 yield clearFeeds(); 630 }); 631 632 it("should store column visibility settings when switching from default to feeds", function* () { 633 doc.getElementById('zotero-items-column-dateAdded').setAttribute('hidden', false); 634 var feed = yield createFeed(); 635 yield cv.selectLibrary(feed.libraryID); 636 var settings = JSON.parse(Zotero.Prefs.get('itemsView.columnVisibility')); 637 assert.isOk(settings.default.dateAdded); 638 }); 639 640 it("should restore column visiblity when switching between default and feeds", function* () { 641 doc.getElementById('zotero-items-column-dateAdded').setAttribute('hidden', false); 642 var feed = yield createFeed(); 643 yield cv.selectLibrary(feed.libraryID); 644 assert.equal(doc.getElementById('zotero-items-column-dateAdded').getAttribute('hidden'), 'true'); 645 doc.getElementById('zotero-items-column-firstCreator').setAttribute('hidden', true); 646 yield cv.selectLibrary(Zotero.Libraries.userLibraryID); 647 assert.equal(doc.getElementById('zotero-items-column-dateAdded').getAttribute('hidden'), 'false'); 648 yield cv.selectLibrary(feed.libraryID); 649 assert.equal(doc.getElementById('zotero-items-column-firstCreator').getAttribute('hidden'), 'true'); 650 }); 651 652 it("should restore column visibility settings on restart", function* () { 653 doc.getElementById('zotero-items-column-dateAdded').setAttribute('hidden', false); 654 assert.equal(doc.getElementById('zotero-items-column-dateAdded').getAttribute('hidden'), 'false'); 655 656 win.close(); 657 win = yield loadZoteroPane(); 658 doc = win.document; 659 zp = win.ZoteroPane; 660 661 assert.equal(doc.getElementById('zotero-items-column-dateAdded').getAttribute('hidden'), 'false'); 662 }); 663 }); 664 })