www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

itemsTest.js (18249B)


      1 describe("Zotero.Items", function () {
      2 	var win, collectionsView, zp;
      3 	
      4 	before(function* () {
      5 		this.timeout(10000);
      6 		win = yield loadZoteroPane();
      7 		collectionsView = win.ZoteroPane.collectionsView;
      8 		zp = win.ZoteroPane;
      9 	})
     10 	beforeEach(function () {
     11 		return selectLibrary(win);
     12 	})
     13 	after(function () {
     14 		win.close();
     15 	})
     16 	
     17 	
     18 	describe("#addToPublications", function () {
     19 		it("should add an item to My Publications", function* () {
     20 			var item = yield createDataObject('item');
     21 			yield Zotero.Items.addToPublications([item]);
     22 			assert.isTrue(item.inPublications);
     23 			assert.equal(
     24 				(yield Zotero.DB.valueQueryAsync(
     25 					"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", item.id)),
     26 				1
     27 			);
     28 		});
     29 		
     30 		describe("#license", function () {
     31 			it("should set a license if specified", function* () {
     32 				var item = createUnsavedDataObject('item');
     33 				item.setField('rights', 'Test');
     34 				yield item.saveTx();
     35 				yield Zotero.Items.addToPublications(
     36 					[item],
     37 					{
     38 						license: 'reserved',
     39 						licenseName: 'All Rights Reserved',
     40 						keepRights: false
     41 					}
     42 				);
     43 				assert.equal(item.getField('rights'), 'All Rights Reserved');
     44 			});
     45 			
     46 			it("should keep existing Rights field if .keepRights is true", function* () {
     47 				var item1 = createUnsavedDataObject('item');
     48 				item1.setField('rights', 'Test');
     49 				yield item1.saveTx();
     50 				var item2 = yield createDataObject('item');
     51 				yield Zotero.Items.addToPublications(
     52 					[item1, item2],
     53 					{
     54 						license: 'reserved',
     55 						licenseName: 'All Rights Reserved',
     56 						keepRights: true
     57 					}
     58 				);
     59 				assert.equal(item1.getField('rights'), 'Test');
     60 				assert.equal(item2.getField('rights'), 'All Rights Reserved');
     61 			});
     62 			
     63 			it("shouldn't set a license if not specified", function* () {
     64 				var item = createUnsavedDataObject('item');
     65 				item.setField('rights', 'Test');
     66 				yield item.saveTx();
     67 				yield Zotero.Items.addToPublications([item]);
     68 				assert.equal(item.getField('rights'), 'Test');
     69 			});
     70 		});
     71 		
     72 		it("should add child notes if .childNotes is true", function* () {
     73 			var item = yield createDataObject('item');
     74 			var note = yield createDataObject('item', { itemType: 'note', parentID: item.id });
     75 			var attachment = yield Zotero.Attachments.linkFromURL({
     76 				url: "http://example.com",
     77 				parentItemID: item.id,
     78 				title: "Example"
     79 			});
     80 			
     81 			yield Zotero.Items.addToPublications([item], { childNotes: true });
     82 			assert.isTrue(note.inPublications);
     83 			assert.equal(
     84 				(yield Zotero.DB.valueQueryAsync(
     85 					"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", note.id)),
     86 				1
     87 			);
     88 			assert.isFalse(attachment.inPublications);
     89 		});
     90 		
     91 		it("should add child link attachments if .childLinks is true", function* () {
     92 			var item = yield createDataObject('item');
     93 			var attachment1 = yield Zotero.Attachments.linkFromURL({
     94 				url: "http://example.com",
     95 				parentItemID: item.id,
     96 				title: "Example"
     97 			});
     98 			var attachment2 = yield importFileAttachment('test.png', { parentItemID: item.id });
     99 			var note = yield createDataObject('item', { itemType: 'note', parentID: item.id });
    100 			
    101 			yield Zotero.Items.addToPublications([item], { childLinks: true });
    102 			assert.isTrue(attachment1.inPublications);
    103 			assert.equal(
    104 				(yield Zotero.DB.valueQueryAsync(
    105 					"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", attachment1.id)),
    106 				1
    107 			);
    108 			assert.isFalse(attachment2.inPublications);
    109 			assert.isFalse(note.inPublications);
    110 		});
    111 		
    112 		it("should add child file attachments if .childFileAttachments is true", function* () {
    113 			var item = yield createDataObject('item');
    114 			var attachment1 = yield importFileAttachment('test.png', { parentItemID: item.id });
    115 			var attachment2 = yield Zotero.Attachments.linkFromURL({
    116 				url: "http://example.com",
    117 				parentItemID: item.id,
    118 				title: "Example"
    119 			});
    120 			var note = yield createDataObject('item', { itemType: 'note', parentID: item.id });
    121 			
    122 			yield Zotero.Items.addToPublications([item], { childFileAttachments: true });
    123 			assert.isTrue(attachment1.inPublications);
    124 			assert.equal(
    125 				(yield Zotero.DB.valueQueryAsync(
    126 					"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", attachment1.id)),
    127 				1
    128 			);
    129 			assert.isFalse(attachment2.inPublications);
    130 			assert.isFalse(note.inPublications);
    131 		});
    132 	});
    133 	
    134 	
    135 	describe("#removeFromPublications", function () {
    136 		it("should remove an item from My Publications", function* () {
    137 			var item = yield createDataObject('item');
    138 			item.inPublications = true;
    139 			yield item.saveTx();
    140 			assert.equal(
    141 				(yield Zotero.DB.valueQueryAsync(
    142 					"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", item.id)),
    143 				1
    144 			);
    145 			yield Zotero.Items.removeFromPublications([item]);
    146 			assert.isFalse(item.inPublications);
    147 			assert.equal(
    148 				(yield Zotero.DB.valueQueryAsync(
    149 					"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", item.id)),
    150 				0
    151 			);
    152 		});
    153 	});
    154 	
    155 	
    156 	describe("#merge()", function () {
    157 		it("should merge two items", function* () {
    158 			var item1 = yield createDataObject('item');
    159 			var item2 = yield createDataObject('item');
    160 			var item2URI = Zotero.URI.getItemURI(item2);
    161 			
    162 			yield Zotero.Items.merge(item1, [item2]);
    163 			
    164 			assert.isFalse(item1.deleted);
    165 			assert.isTrue(item2.deleted);
    166 			
    167 			// Check for merge-tracking relation
    168 			assert.isFalse(item1.hasChanged());
    169 			var rels = item1.getRelationsByPredicate(Zotero.Relations.replacedItemPredicate);
    170 			assert.lengthOf(rels, 1);
    171 			assert.equal(rels[0], item2URI);
    172 		})
    173 		
    174 		it("should merge three items", async function () {
    175 			var item1 = await createDataObject('item');
    176 			var item2 = await createDataObject('item');
    177 			var item3 = await createDataObject('item');
    178 			var item2URI = Zotero.URI.getItemURI(item2);
    179 			var item3URI = Zotero.URI.getItemURI(item3);
    180 			
    181 			await Zotero.Items.merge(item1, [item2, item3]);
    182 			
    183 			assert.isFalse(item1.deleted);
    184 			assert.isTrue(item2.deleted);
    185 			assert.isTrue(item3.deleted);
    186 			
    187 			// Check for merge-tracking relation
    188 			assert.isFalse(item1.hasChanged());
    189 			var rels = item1.getRelationsByPredicate(Zotero.Relations.replacedItemPredicate);
    190 			assert.lengthOf(rels, 2);
    191 			assert.sameMembers(rels, [item2URI, item3URI]);
    192 		})
    193 		
    194 		it("should merge two items when servant is linked to an item absent from cache", function* () {
    195 			// two group libraries
    196 			var groupOneInfo = yield createGroup({
    197 				id: 25026,
    198 				name: "Group One"
    199 			});
    200 			var libraryOneID = Zotero.Groups.getLibraryIDFromGroupID(groupOneInfo.id);
    201 
    202 			var groupTwoInfo = yield createGroup({
    203 				id: 11592,
    204 				name: "Group Two"
    205 			});
    206 			var libraryTwoID = Zotero.Groups.getLibraryIDFromGroupID(groupTwoInfo.id);
    207 
    208 			assert.notEqual(libraryOneID, libraryTwoID);
    209 
    210 			// two items in the first library
    211 			var item1 = yield createDataObject('item', {libraryID: libraryOneID});
    212 			var item2 = yield createDataObject('item', {libraryID: libraryOneID});
    213 			var item2URI = Zotero.URI.getItemURI(item2);
    214 
    215 			// one item in the second library, linked to item2 as if it dragged and dropped from it
    216 			var itemX = yield createDataObject('item', {libraryID: libraryTwoID});
    217 			yield itemX.addLinkedItem(item2);
    218 
    219 			// check that the owl:sameAs relation has been registered okay
    220 			var rels = itemX.getRelationsByPredicate(Zotero.Relations.linkedObjectPredicate);
    221 			assert.lengthOf(rels, 1);
    222 			assert.equal(rels[0], item2URI);
    223 
    224 			// the freshly minted item is in objectCache, but it might be absent in production,
    225 			// so we clobber it in this test
    226 			assert(!!Zotero.Items._objectCache[itemX.id], "itemX is in object cache")
    227 			delete Zotero.Items._objectCache[itemX.id];
    228 
    229 			// merge the two items in the first library
    230 			yield Zotero.Items.merge(item1, [item2]);
    231 
    232 			// check that the merge completed okay
    233 			assert.isFalse(item1.deleted);
    234 			assert.isTrue(item2.deleted);
    235 
    236 			// Check for merge-tracking relation
    237 			assert.isFalse(item1.hasChanged());
    238 			var rels = item1.getRelationsByPredicate(Zotero.Relations.replacedItemPredicate);
    239 			assert.lengthOf(rels, 1);
    240 			assert.equal(rels[0], item2URI);
    241 		})
    242 
    243 		it("should move merge-tracking relation from replaced item to master", function* () {
    244 			var item1 = yield createDataObject('item');
    245 			var item2 = yield createDataObject('item');
    246 			var item2URI = Zotero.URI.getItemURI(item2);
    247 			var item3 = yield createDataObject('item');
    248 			var item3URI = Zotero.URI.getItemURI(item3);
    249 			
    250 			yield Zotero.Items.merge(item2, [item3]);
    251 			yield Zotero.Items.merge(item1, [item2]);
    252 			
    253 			// Check for merge-tracking relation from 1 to 3
    254 			var rels = item1.getRelationsByPredicate(Zotero.Relations.replacedItemPredicate);
    255 			assert.lengthOf(rels, 2);
    256 			assert.sameMembers(rels, [item2URI, item3URI]);
    257 		})
    258 		
    259 		it("should update relations pointing to replaced item to point to master", function* () {
    260 			var item1 = yield createDataObject('item');
    261 			var item1URI = Zotero.URI.getItemURI(item1);
    262 			var item2 = yield createDataObject('item');
    263 			var item2URI = Zotero.URI.getItemURI(item2);
    264 			var item3 = createUnsavedDataObject('item');
    265 			var predicate = Zotero.Relations.relatedItemPredicate;
    266 			item3.addRelation(predicate, item2URI);
    267 			yield item3.saveTx();
    268 			
    269 			yield Zotero.Items.merge(item1, [item2]);
    270 			
    271 			// Check for related-item relation from 3 to 1
    272 			var rels = item3.getRelationsByPredicate(predicate);
    273 			assert.deepEqual(rels, [item1URI]);
    274 		})
    275 		
    276 		it("should not update relations pointing to replaced item in other libraries", function* () {
    277 			var group1 = yield createGroup();
    278 			var group2 = yield createGroup();
    279 			
    280 			var item1 = yield createDataObject('item', { libraryID: group1.libraryID });
    281 			var item1URI = Zotero.URI.getItemURI(item1);
    282 			var item2 = yield createDataObject('item', { libraryID: group1.libraryID });
    283 			var item2URI = Zotero.URI.getItemURI(item2);
    284 			var item3 = createUnsavedDataObject('item', { libraryID: group2.libraryID });
    285 			var predicate = Zotero.Relations.linkedObjectPredicate;
    286 			item3.addRelation(predicate, item2URI);
    287 			yield item3.saveTx();
    288 			
    289 			yield Zotero.Items.merge(item1, [item2]);
    290 			
    291 			// Check for related-item relation from 3 to 2
    292 			var rels = item3.getRelationsByPredicate(predicate);
    293 			assert.deepEqual(rels, [item2URI]);
    294 		})
    295 	})
    296 	
    297 	
    298 	describe("#trash()", function () {
    299 		it("should send items to the trash", function* () {
    300 			var items = [];
    301 			items.push(
    302 				(yield createDataObject('item', { synced: true })),
    303 				(yield createDataObject('item', { synced: true })),
    304 				(yield createDataObject('item', { synced: true }))
    305 			);
    306 			items.forEach(item => {
    307 				// Sanity-checked as true in itemTest#deleted
    308 				assert.isUndefined(item._changed.deleted);
    309 			});
    310 			var ids = items.map(item => item.id);
    311 			yield Zotero.Items.trashTx(ids);
    312 			items.forEach(item => {
    313 				assert.isTrue(item.deleted);
    314 				// Item should be saved (can't use hasChanged() because that includes .synced)
    315 				assert.isUndefined(item._changed.deleted);
    316 				assert.isFalse(item.synced);
    317 			});
    318 			assert.equal((yield Zotero.DB.valueQueryAsync(
    319 				`SELECT COUNT(*) FROM deletedItems WHERE itemID IN (${ids})`
    320 			)), 3);
    321 			for (let item of items) {
    322 				assert.equal((yield Zotero.DB.valueQueryAsync(
    323 					`SELECT synced FROM items WHERE itemID=${item.id}`
    324 				)), 0);
    325 			}
    326 		});
    327 		
    328 		it("should update parent item when trashing child item", function* () {
    329 			var item = yield createDataObject('item');
    330 			var note = yield createDataObject('item', { itemType: 'note', parentID: item.id });
    331 			assert.lengthOf(item.getNotes(), 1);
    332 			yield Zotero.Items.trashTx([note.id]);
    333 			assert.lengthOf(item.getNotes(), 0);
    334 		});
    335 	});
    336 	
    337 	
    338 	describe("#emptyTrash()", function () {
    339 		it("should delete items in the trash", function* () {
    340 			var item1 = createUnsavedDataObject('item');
    341 			item1.setField('title', 'a');
    342 			item1.deleted = true;
    343 			var id1 = yield item1.saveTx();
    344 			
    345 			var item2 = createUnsavedDataObject('item');
    346 			item2.setField('title', 'b');
    347 			item2.deleted = true;
    348 			var id2 = yield item2.saveTx();
    349 			
    350 			var item3 = createUnsavedDataObject('item', { itemType: 'attachment', parentID: id2 });
    351 			item3.attachmentLinkMode = Zotero.Attachments.LINK_MODE_IMPORTED_URL;
    352 			item3.deleted = true;
    353 			var id3 = yield item3.saveTx();
    354 			
    355 			yield collectionsView.selectTrash(Zotero.Libraries.userLibraryID);
    356 			
    357 			yield Zotero.Items.emptyTrash(Zotero.Libraries.userLibraryID);
    358 			
    359 			assert.isFalse(yield Zotero.Items.getAsync(id1));
    360 			assert.isFalse(yield Zotero.Items.getAsync(id2));
    361 			assert.isFalse(yield Zotero.Items.getAsync(id3));
    362 			
    363 			// TEMP: This is failing on Travis due to a race condition
    364 			//assert.equal(zp.itemsView.rowCount, 0)
    365 		})
    366 	})
    367 	
    368 	describe("#getFirstCreatorFromData()", function () {
    369 		it("should handle single eligible creator", function* () {
    370 			for (let creatorType of ['author', 'editor', 'contributor']) {
    371 				assert.equal(
    372 					Zotero.Items.getFirstCreatorFromData(
    373 						Zotero.ItemTypes.getID('book'),
    374 						[
    375 							{
    376 								fieldMode: 0,
    377 								firstName: 'A',
    378 								lastName: 'B',
    379 								creatorTypeID: Zotero.CreatorTypes.getID(creatorType)
    380 							}
    381 						]
    382 					),
    383 					'B',
    384 					creatorType
    385 				);
    386 			}
    387 		});
    388 		
    389 		it("should ignore single ineligible creator", function* () {
    390 			assert.strictEqual(
    391 				Zotero.Items.getFirstCreatorFromData(
    392 					Zotero.ItemTypes.getID('book'),
    393 					[
    394 						{
    395 							fieldMode: 0,
    396 							firstName: 'A',
    397 							lastName: 'B',
    398 							creatorTypeID: Zotero.CreatorTypes.getID('translator')
    399 						}
    400 					]
    401 				),
    402 				''
    403 			);
    404 		});
    405 		
    406 		it("should handle single eligible creator after ineligible creator", function* () {
    407 			for (let creatorType of ['author', 'editor', 'contributor']) {
    408 				assert.equal(
    409 					Zotero.Items.getFirstCreatorFromData(
    410 						Zotero.ItemTypes.getID('book'),
    411 						[
    412 							{
    413 								fieldMode: 0,
    414 								firstName: 'A',
    415 								lastName: 'B',
    416 								creatorTypeID: Zotero.CreatorTypes.getID('translator')
    417 							},
    418 							{
    419 								fieldMode: 0,
    420 								firstName: 'C',
    421 								lastName: 'D',
    422 								creatorTypeID: Zotero.CreatorTypes.getID(creatorType)
    423 							}
    424 						]
    425 					),
    426 					'D',
    427 					creatorType
    428 				);
    429 			}
    430 		});
    431 		
    432 		it("should handle two eligible creators", function* () {
    433 			for (let creatorType of ['author', 'editor', 'contributor']) {
    434 				assert.equal(
    435 					Zotero.Items.getFirstCreatorFromData(
    436 						Zotero.ItemTypes.getID('book'),
    437 						[
    438 							{
    439 								fieldMode: 0,
    440 								firstName: 'A',
    441 								lastName: 'B',
    442 								creatorTypeID: Zotero.CreatorTypes.getID(creatorType)
    443 							},
    444 							{
    445 								fieldMode: 0,
    446 								firstName: 'C',
    447 								lastName: 'D',
    448 								creatorTypeID: Zotero.CreatorTypes.getID(creatorType)
    449 							}
    450 						]
    451 					),
    452 					'B ' + Zotero.getString('general.and') + ' D',
    453 					creatorType
    454 				);
    455 			}
    456 		});
    457 		
    458 		it("should handle three eligible creators", function* () {
    459 			for (let creatorType of ['author', 'editor', 'contributor']) {
    460 				assert.equal(
    461 					Zotero.Items.getFirstCreatorFromData(
    462 						Zotero.ItemTypes.getID('book'),
    463 						[
    464 							{
    465 								fieldMode: 0,
    466 								firstName: 'A',
    467 								lastName: 'B',
    468 								creatorTypeID: Zotero.CreatorTypes.getID(creatorType)
    469 							},
    470 							{
    471 								fieldMode: 0,
    472 								firstName: 'C',
    473 								lastName: 'D',
    474 								creatorTypeID: Zotero.CreatorTypes.getID(creatorType)
    475 							},
    476 							{
    477 								fieldMode: 0,
    478 								firstName: 'E',
    479 								lastName: 'F',
    480 								creatorTypeID: Zotero.CreatorTypes.getID(creatorType)
    481 							}
    482 						]
    483 					),
    484 					'B ' + Zotero.getString('general.etAl'),
    485 					creatorType
    486 				);
    487 			}
    488 		});
    489 		
    490 		it("should handle two eligible creators with intervening creators", function* () {
    491 			for (let creatorType of ['author', 'editor', 'contributor']) {
    492 				assert.equal(
    493 					Zotero.Items.getFirstCreatorFromData(
    494 						Zotero.ItemTypes.getID('book'),
    495 						[
    496 							{
    497 								fieldMode: 0,
    498 								firstName: 'A',
    499 								lastName: 'B',
    500 								creatorTypeID: Zotero.CreatorTypes.getID('translator')
    501 							},
    502 							{
    503 								fieldMode: 0,
    504 								firstName: 'C',
    505 								lastName: 'D',
    506 								creatorTypeID: Zotero.CreatorTypes.getID(creatorType)
    507 							},
    508 							{
    509 								fieldMode: 0,
    510 								firstName: 'E',
    511 								lastName: 'F',
    512 								creatorTypeID: Zotero.CreatorTypes.getID('translator')
    513 							},
    514 							{
    515 								fieldMode: 0,
    516 								firstName: 'G',
    517 								lastName: 'H',
    518 								creatorTypeID: Zotero.CreatorTypes.getID(creatorType)
    519 							}
    520 						]
    521 					),
    522 					'D ' + Zotero.getString('general.and') + ' H',
    523 					creatorType
    524 				);
    525 			}
    526 		});
    527 	});
    528 	
    529 	describe("#getAsync()", function() {
    530 		it("should return Zotero.Item for item ID", function* () {
    531 			let item = new Zotero.Item('journalArticle');
    532 			let id = yield item.saveTx();
    533 			item = yield Zotero.Items.getAsync(id);
    534 			assert.notOk(item.isFeedItem);
    535 			assert.instanceOf(item, Zotero.Item);
    536 			assert.notInstanceOf(item, Zotero.FeedItem);
    537 		});
    538 		it("should return Zotero.FeedItem for feed item ID", function* () {
    539 			let feed = new Zotero.Feed({ name: 'foo', url: 'http://www.' + Zotero.randomString() + '.com' });
    540 			yield feed.saveTx();
    541 			
    542 			let feedItem = new Zotero.FeedItem('journalArticle', { guid: Zotero.randomString() });
    543 			feedItem.libraryID = feed.libraryID;
    544 			let id = yield feedItem.saveTx();
    545 			
    546 			feedItem = yield Zotero.Items.getAsync(id);
    547 			
    548 			assert.isTrue(feedItem.isFeedItem);
    549 			assert.instanceOf(feedItem, Zotero.FeedItem);
    550 		});
    551 	});
    552 	
    553 	describe("#keepParents()", function () {
    554 		it("should remove child items of passed items", async function () {
    555 			var item1 = await createDataObject('item');
    556 			var item2 = await createDataObject('item', { itemType: 'note', parentItemID: item1.id });
    557 			var item3 = await createDataObject('item', { itemType: 'note', parentItemID: item1.id });
    558 			var item4 = await createDataObject('item');
    559 			var item5 = await createDataObject('item', { itemType: 'note', parentItemID: item4.id });
    560 			var otherItem = await createDataObject('item');
    561 			var item6 = await createDataObject('item', { itemType: 'note', parentItemID: otherItem.id });
    562 			
    563 			var items = Zotero.Items.keepParents([item1, item2, item3, item4, item5, item6]);
    564 			assert.sameMembers(
    565 				// Convert to ids for clearer output
    566 				items.map(item => item.id),
    567 				[item1, item4, item6].map(item => item.id)
    568 			);
    569 		});
    570 	});
    571 });