"use strict"; describe("Zotero.AttachmentReadObserver", function () { describe("file events", function () { beforeEach(function () { Zotero.Libraries.userLibrary.lastReadItemInSession = null; }); it("should update an attachment's attachmentLastRead every time it is opened", async function () { let attachment = await importPDFAttachment(null); // We open the attachment at midnight on January 1 let stub = sinon.stub(Zotero.AttachmentReadObserver, '_getCurrentDate') .callsFake(() => new Date(2023, 1, 1, 0, 0, 0)); await Zotero.Notifier.trigger('open', 'file', [attachment.id]); let initialLastRead = attachment.attachmentLastRead; assert.isNumber(initialLastRead); // We open it again, only five seconds later stub.callsFake(() => new Date(2023, 1, 1, 0, 0, 5)); await Zotero.Notifier.trigger('open', 'file', [attachment.id]); assert.isAbove(attachment.attachmentLastRead, initialLastRead); stub.restore(); }); it("should update an attachment's attachmentLastRead when it is closed", async function () { let attachment = await importPDFAttachment(null); // We open the attachment at midnight on January 1 let stub = sinon.stub(Zotero.AttachmentReadObserver, '_getCurrentDate') .callsFake(() => new Date(2023, 1, 1, 0, 0, 0)); await Zotero.Notifier.trigger('open', 'file', [attachment.id]); let initialLastRead = attachment.attachmentLastRead; assert.isNumber(initialLastRead); // We close it ten minutes later stub.callsFake(() => new Date(2023, 1, 1, 0, 10, 0)); await Zotero.Notifier.trigger('close', 'file', [attachment.id]); assert.isAbove(attachment.attachmentLastRead, initialLastRead); stub.restore(); }); it("should not update an attachment's attachmentLastRead when it is revealed in the filesystem", async function () { let attachment = await importPDFAttachment(null); await Zotero.Notifier.trigger('reveal', 'file', [attachment.id]); assert.isNull(attachment.attachmentLastRead); }); it("should not mark a group attachment as unsynced when opened", async function () { let group = await createGroup(); let item = await createDataObject('item', { libraryID: group.libraryID }); let attachment = await importPDFAttachment(item); // Mark as synced attachment.synced = true; await attachment.saveTx({ skipSyncedUpdate: true }); assert.isTrue(attachment.synced); await Zotero.Notifier.trigger('open', 'file', [attachment.id]); assert.isNumber(attachment.attachmentLastRead); assert.isTrue(attachment.synced); }); it("should update an attachment's attachmentLastRead every five minutes when the page changes", async function () { let attachment = await importPDFAttachment(null); // We open the attachment at midnight on January 1 let stub = sinon.stub(Zotero.AttachmentReadObserver, '_getCurrentDate') .callsFake(() => new Date(2023, 1, 1, 0, 0, 0)); await Zotero.Notifier.trigger('open', 'file', [attachment.id]); let initialLastRead = attachment.attachmentLastRead; assert.isNumber(initialLastRead); // We change pages, only five seconds later stub.callsFake(() => new Date(2023, 1, 1, 0, 0, 5)); await Zotero.Notifier.trigger('pageChange', 'file', [attachment.id]); assert.equal(attachment.attachmentLastRead, initialLastRead); // We change pages again, five minutes later stub.callsFake(() => new Date(2023, 1, 1, 0, 5, 5)); await Zotero.Notifier.trigger('pageChange', 'file', [attachment.id]); let updatedLastRead = attachment.attachmentLastRead; assert.isAbove(updatedLastRead, initialLastRead); // We change pages again, a minute after that stub.callsFake(() => new Date(2023, 1, 1, 0, 6, 5)); await Zotero.Notifier.trigger('pageChange', 'file', [attachment.id]); assert.equal(attachment.attachmentLastRead, updatedLastRead); stub.restore(); }); }); describe("setting events", function () { it("should update a group attachment's attachmentLastRead when the associated synced setting changes", async function () { let group = await createGroup(); let item = await createDataObject('item', { libraryID: group.libraryID }); let attachment = await importPDFAttachment(item); let key = attachment._getLastReadSettingKey(); let firstValue = 1674668000; await Zotero.SyncedSettings.set(Zotero.Libraries.userLibraryID, key, firstValue); assert.equal(attachment.attachmentLastRead, firstValue); let secondValue = 1674668123; await Zotero.SyncedSettings.set(Zotero.Libraries.userLibraryID, key, secondValue); assert.equal(attachment.attachmentLastRead, secondValue); }); it("should update a read-only group attachment's attachmentLastRead when the associated synced setting changes", async function () { let group = await createGroup(); let item = await createDataObject('item', { libraryID: group.libraryID }); let attachment = await importPDFAttachment(item); let key = attachment._getLastReadSettingKey(); // Make the group read-only after creating test data group.editable = false; await group.saveTx(); let value = 1674668000; await Zotero.SyncedSettings.set(Zotero.Libraries.userLibraryID, key, value); assert.equal(attachment.attachmentLastRead, value); // Verify persisted to DB, not just set in memory let dbVal = await Zotero.DB.valueQueryAsync( "SELECT lastRead FROM itemAttachments WHERE itemID=?", attachment.id ); assert.equal(dbVal, value); }); it("should not mark a group attachment as unsynced when the associated synced setting changes", async function () { let group = await createGroup(); let item = await createDataObject('item', { libraryID: group.libraryID }); let attachment = await importPDFAttachment(item); let key = attachment._getLastReadSettingKey(); // Mark as synced attachment.synced = true; await attachment.saveTx({ skipSyncedUpdate: true }); assert.isTrue(attachment.synced); let value = 1674668000; await Zotero.SyncedSettings.set(Zotero.Libraries.userLibraryID, key, value); assert.equal(attachment.attachmentLastRead, value); // Verify item is still synced await attachment.reload(); assert.isTrue(attachment.synced); }); }); });