zotero/test/tests/duplicatesTest.js
Jakob Nylin e3da52bebc
Match duplicate books by ISBN-10/13 equivalence (#6028)
---------

Co-authored-by: Dan Stillman <dstillman@zotero.org>
2026-09-03 12:42:04 -04:00

131 lines
3.8 KiB
JavaScript

"use strict";
describe("Duplicate Items", function () {
var win, zp, cv;
before(function* () {
yield resetDB({
thisArg: this,
skipBundledFiles: true
});
Zotero.Prefs.clear('duplicateLibraries');
win = yield loadZoteroPane();
zp = win.ZoteroPane;
cv = zp.collectionsView;
});
beforeEach(function* () {
return selectLibrary(win);
})
after(function () {
win.close();
});
describe("ISBN matching", function () {
it("should match books with equivalent ISBN-10 and ISBN-13", async function () {
var item1 = await createDataObject('item', { itemType: 'book', title: 'Effective Java' });
item1.setField('ISBN', '0134685997');
await item1.saveTx();
var item2 = await createDataObject('item', { itemType: 'book', title: 'Effective Java, 3rd Edition' });
item2.setField('ISBN', '9780134685991');
await item2.saveTx();
var duplicates = new Zotero.Duplicates(Zotero.Libraries.userLibraryID);
await duplicates.getSearchObject();
assert.sameMembers(duplicates.getSetItemsByItemID(item1.id), [item1.id, item2.id]);
});
});
async function merge(itemID) {
var userLibraryID = Zotero.Libraries.userLibraryID;
var selected = await cv.selectByID('D' + userLibraryID);
assert.ok(selected);
await waitForItemsLoad(win);
// Select the first item, which should select both
var iv = zp.itemsView;
var row = iv.getRowIndexByID(itemID);
var promise = iv.waitForSelect();
clickOnItemsRow(win, iv, row);
await promise;
// Click merge button
var button = win.document.getElementById('zotero-duplicates-merge-button');
button.click();
await waitForNotifierEvent('refresh', 'trash');
}
describe("Merging", function () {
it("should merge two items in duplicates view", async function () {
var item1 = await createDataObject('item', { setTitle: true });
var item2 = item1.clone();
await item2.saveTx();
var uri2 = Zotero.URI.getItemURI(item2);
await merge(item1.id);
// Items should be gone
var iv = zp.itemsView;
assert.isFalse(iv.getRowIndexByID(item1.id));
assert.isFalse(iv.getRowIndexByID(item2.id));
assert.isTrue(item2.deleted);
var rels = item1.getRelations();
var pred = Zotero.Relations.replacedItemPredicate;
assert.property(rels, pred);
assert.equal(rels[pred], uri2);
});
it("should combine collections from all items", async function () {
var collection1 = await createDataObject('collection');
var collection2 = await createDataObject('collection');
var item1 = await createDataObject('item', { setTitle: true, collections: [collection1.id] });
var item2 = item1.clone();
item2.setCollections([collection2.id]);
await item2.saveTx();
await merge(item1.id);
// Items should be gone
var iv = zp.itemsView;
assert.isFalse(iv.getRowIndexByID(item1.id));
assert.isFalse(iv.getRowIndexByID(item2.id));
assert.isTrue(item2.deleted);
assert.isTrue(collection1.hasItem(item1.id));
assert.isTrue(collection2.hasItem(item1.id));
});
it("should not create a relation to self if related items are merged", async function () {
// Create 3 items related to each other
// item1 <-> item2, item2 <-> item3
var item1 = await createDataObject('item', { setTitle: true });
var item2 = item1.clone();
var item3 = item1.clone();
await item2.saveTx();
await item3.saveTx();
item1.addRelatedItem(item2);
item2.addRelatedItem(item1);
item2.addRelatedItem(item3);
item3.addRelatedItem(item2);
await item1.saveTx();
await item2.saveTx();
await item3.saveTx();
// Merge all 3 items into item1
await merge(item1.id);
// Item 1 should now be related to item2 and item3
assert.sameMembers(item1.relatedItems, [item2.key, item3.key]);
assert.sameMembers(item2.relatedItems, [item1.key]);
assert.sameMembers(item3.relatedItems, [item1.key]);
});
});
});