www

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

feedTest.js (15944B)


      1 describe("Zotero.Feed", function() {
      2 	// Clean up after after tests
      3 	after(function* () {
      4 		yield clearFeeds();
      5 	});
      6 	
      7 	it("should be an instance of Zotero.Library", function() {
      8 		let feed = new Zotero.Feed();
      9 		assert.instanceOf(feed, Zotero.Library);
     10 	});
     11 	
     12 	describe("#constructor()", function() {
     13 		it("should accept required fields as arguments", function* () {
     14 			let feed = new Zotero.Feed();
     15 			yield assert.isRejected(feed.saveTx(), /^Feed name not set$/);
     16 			
     17 			feed = new Zotero.Feed({
     18 				name: 'Test ' + Zotero.randomString(),
     19 				url: 'http://www.' + Zotero.randomString() + '.com'
     20 			});
     21 			yield assert.isFulfilled(feed.saveTx());
     22 		});
     23 	});
     24 	
     25 	describe("#isFeed", function() {
     26 		it("should be true", function() {
     27 			let feed = new Zotero.Feed();
     28 			assert.isTrue(feed.isFeed);
     29 		});
     30 		it("should be falsy for regular Library", function() {
     31 			let library = new Zotero.Library();
     32 			assert.notOk(library.isFeed);
     33 		});
     34 	});
     35 	
     36 	describe("#editable", function() {
     37 		it("should always be not editable", function* () {
     38 			let feed = yield createFeed();
     39 			assert.isFalse(feed.editable);
     40 			feed.editable = true;
     41 			assert.isFalse(feed.editable);
     42 			yield feed.saveTx();
     43 			assert.isFalse(feed.editable);
     44 		});
     45 		it("should allow adding items without editCheck override", function* () {
     46 			let feed = yield createFeed();
     47 			let feedItem = new Zotero.FeedItem('book', { guid: Zotero.randomString() });
     48 			feedItem.libraryID = feed.libraryID;
     49 			yield assert.isFulfilled(feedItem.saveTx());
     50 		});
     51 	});
     52 	
     53 	describe("#libraryTypeID", function () {
     54 		it("should be undefind", function* () {
     55 			let feed = yield createFeed();
     56 			assert.isUndefined(feed.libraryTypeID);
     57 		});
     58 	});
     59 	
     60 	describe("#url", function() {
     61 		it("should throw if trying to set an invalid URL", function *() {
     62 			let feed = new Zotero.Feed({ name: 'Test ' + Zotero.randomString() });
     63 			
     64 			assert.throws(function() {feed.url = 'foo'}, /^Invalid feed URL /);
     65 			assert.throws(function() {feed.url = 'ftp://example.com'}, /^Invalid feed URL /);
     66 		});
     67 	});
     68 	
     69 	describe("#save()", function() {
     70 		it("should save a new feed to the feed library", function* () {
     71 			let props = {
     72 				name: 'Test ' + Zotero.randomString(),
     73 				url: 'http://' + Zotero.randomString() + '.com/'
     74 			};
     75 			let feed = yield createFeed(props);
     76 			
     77 			assert.equal(feed.name, props.name, "name is correct");
     78 			assert.equal(feed.url.toLowerCase(), props.url.toLowerCase(), "url is correct");
     79 		});
     80 		it("should save a feed with all fields set", function* () {
     81 			let props = {
     82 				name: 'Test ' + Zotero.randomString(),
     83 				url: 'http://' + Zotero.randomString() + '.com/',
     84 				refreshInterval: 30,
     85 				cleanupReadAfter: 1,
     86 				cleanupUnreadAfter: 30
     87 			};
     88 			
     89 			let feed = yield createFeed(props);
     90 			
     91 			assert.equal(feed.name, props.name, "name is correct");
     92 			assert.equal(feed.url.toLowerCase(), props.url.toLowerCase(), "url is correct");
     93 			assert.equal(feed.refreshInterval, props.refreshInterval, "refreshInterval is correct");
     94 			assert.equal(feed.cleanupReadAfter, props.cleanupReadAfter, "cleanupReadAfter is correct");
     95 			assert.equal(feed.cleanupUnreadAfter, props.cleanupUnreadAfter, "cleanupUnreadAfter is correct");
     96 			
     97 			assert.isNull(feed.lastCheck, "lastCheck is null");
     98 			assert.isNull(feed.lastUpdate, "lastUpdate is null");
     99 			assert.isNull(feed.lastCheckError, "lastCheckError is null");
    100 		});
    101 		it("should throw if name or url are missing", function *() {
    102 			let feed = new Zotero.Feed();
    103 			yield assert.isRejected(feed.saveTx(), /^Feed name not set$/);
    104 			
    105 			feed.name = 'Test ' + Zotero.randomString();
    106 			yield assert.isRejected(feed.saveTx(), /^Feed URL not set$/);
    107 			
    108 			feed = new Zotero.Feed();
    109 			feed.url = 'http://' + Zotero.randomString() + '.com';
    110 			yield assert.isRejected(feed.saveTx(), /^Feed name not set$/);
    111 		});
    112 		it("should not allow saving a feed with the same url", function *() {
    113 			let url = 'http://' + Zotero.randomString() + '.com';
    114 			let feed1 = yield createFeed({ url });
    115 			
    116 			let feed2 = new Zotero.Feed({ name: 'Test ' + Zotero.randomString(), url });
    117 			yield assert.isRejected(feed2.saveTx(), /^Feed for URL already exists: /);
    118 			
    119 			// Perform check with normalized URL
    120 			feed2.url = url + '/';
    121 			yield assert.isRejected(feed2.saveTx(), /^Feed for URL already exists: /);
    122 			
    123 			feed2.url = url.toUpperCase();
    124 			yield assert.isRejected(feed2.saveTx(), /^Feed for URL already exists: /);
    125 		});
    126 		it("should allow saving a feed with the same name", function *() {
    127 			let name = 'Test ' + Zotero.randomString();
    128 			let feed1 = yield createFeed({ name });
    129 			
    130 			let feed2 = new Zotero.Feed({ name , url: 'http://' + Zotero.randomString() + '.com' });
    131 			
    132 			yield assert.isFulfilled(feed2.saveTx(), "allow saving feed with an existing name");
    133 			
    134 			assert.equal(feed1.name, feed2.name, "feed names remain the same");
    135 		});
    136 		it("should save field to DB after editing", function* () {
    137 			let feed = yield createFeed();
    138 			
    139 			feed.name = 'bar';
    140 			yield feed.saveTx();
    141 			
    142 			let dbVal = yield Zotero.DB.valueQueryAsync('SELECT name FROM feeds WHERE libraryID=?', feed.libraryID);
    143 			assert.equal(feed.name, 'bar');
    144 			assert.equal(dbVal, feed.name);
    145 		});
    146 		it("should add a new synced setting after creation", function* () {
    147 			let url = 'http://' + Zotero.Utilities.randomString(10, 'abcde') + '.com/feed.rss';
    148 			
    149 			let syncedFeeds = Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, 'feeds');
    150 			assert.notOk(syncedFeeds[url]);
    151 			
    152 			yield createFeed({url});
    153 			
    154 			syncedFeeds = Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, 'feeds');
    155 			assert.ok(syncedFeeds[url]);
    156 		});
    157 		it("should remove previous feed and add a new one if url changed", function* () {
    158 			let feed = yield createFeed();
    159 			
    160 			let syncedFeeds = Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, 'feeds');
    161 			assert.ok(syncedFeeds[feed.url]);
    162 
    163 			let oldUrl = feed.url;
    164 			feed.url = 'http://' + Zotero.Utilities.randomString(10, 'abcde') + '.com/feed.rss';
    165 			yield feed.saveTx();
    166 
    167 			syncedFeeds = Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, 'feeds');
    168 			assert.notOk(syncedFeeds[oldUrl]);
    169 			assert.ok(syncedFeeds[feed.url]);
    170 		});
    171 		it('should update syncedSettings if `name`, `url`, `refreshInterval` or `cleanupUnreadAfter` was modified', function* () {
    172 			let feed = yield createFeed();
    173 			let syncedSetting = Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, 'feeds');
    174 			yield Zotero.SyncedSettings.set(Zotero.Libraries.userLibraryID, 'feeds', syncedSetting, 0, true);
    175 			
    176 			feed.name = "New name";
    177 			yield feed.saveTx();
    178 			assert.isFalse(Zotero.SyncedSettings.getMetadata(Zotero.Libraries.userLibraryID, 'feeds').synced)
    179 		});
    180 		it('should not update syncedSettings if `name`, `url`, `refreshInterval` or `cleanupUnreadAfter` were not modified', function* () {
    181 			let feed = yield createFeed();
    182 			let syncedSetting = Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, 'feeds');
    183 			yield Zotero.SyncedSettings.set(Zotero.Libraries.userLibraryID, 'feeds', syncedSetting, 0, true);
    184 
    185 			feed._set('_feedLastCheck', Zotero.Date.dateToSQL(new Date(), true));
    186 			yield feed.saveTx();
    187 			assert.isTrue(Zotero.SyncedSettings.getMetadata(Zotero.Libraries.userLibraryID, 'feeds').synced)
    188 		});
    189 	});
    190 	describe("#erase()", function() {
    191 		it("should erase a saved feed", function* () {
    192 			let feed = yield createFeed();
    193 			let id = feed.libraryID;
    194 			let url = feed.url;
    195 			
    196 			yield feed.eraseTx();
    197 			
    198 			assert.isFalse(Zotero.Libraries.exists(id));
    199 			assert.isFalse(Zotero.Feeds.existsByURL(url));
    200 			
    201 			let dbValue = yield Zotero.DB.valueQueryAsync('SELECT COUNT(*) FROM feeds WHERE libraryID=?', id);
    202 			assert.equal(dbValue, '0');
    203 		});
    204 		it("should clear feedItems from cache", function* () {
    205 			let feed = yield createFeed();
    206 			
    207 			let feedItem = yield createDataObject('feedItem', { libraryID: feed.libraryID });
    208 			assert.ok(yield Zotero.FeedItems.getAsync(feedItem.id));
    209 			
    210 			yield feed.eraseTx();
    211 			
    212 			assert.notOk(yield Zotero.FeedItems.getAsync(feedItem.id));
    213 		});
    214 		it("should remove synced settings", function* () {
    215 			let url = 'http://' + Zotero.Utilities.randomString(10, 'abcde') + '.com/feed.rss';
    216 			let feed = yield createFeed({url});
    217 			
    218 			let syncedFeeds = Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, 'feeds');
    219 			assert.ok(syncedFeeds[feed.url]);
    220 			
    221 			yield feed.eraseTx();
    222 			
    223 			syncedFeeds = Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, 'feeds');
    224 			assert.notOk(syncedFeeds[url]);
    225 
    226 		});
    227 	});
    228 	
    229 	describe("#storeSyncedSettings", function() {
    230 		it("should store settings for feed in compact format", function* () {
    231 			let url = 'http://' + Zotero.Utilities.randomString().toLowerCase() + '.com/feed.rss';
    232 			let settings = [Zotero.Utilities.randomString(), 1, 30, 1];
    233 			let feed = yield createFeed({
    234 				url,
    235 				name: settings[0],
    236 				cleanupReadAfter: settings[1],
    237 				cleanupUnreadAfter: settings[2],
    238 				refreshInterval: settings[3]
    239 			});
    240 			
    241 			let syncedFeeds = Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, 'feeds');
    242 			assert.deepEqual(syncedFeeds[url], settings);
    243 		});
    244 	});
    245 	
    246 	describe("#clearExpiredItems()", function() {
    247 		var feed, readExpiredFI, unreadExpiredFI, readFeedItem, feedItem, readStillInFeed, feedItemIDs;
    248 		
    249 		before(function* (){
    250 			feed = yield createFeed({cleanupReadAfter: 1, cleanupUnreadAfter: 3});
    251 			
    252 			readExpiredFI = yield createDataObject('feedItem', { libraryID: feed.libraryID });
    253 			// Read 2 days ago
    254 			readExpiredFI.isRead = true;
    255 			readExpiredFI._feedItemReadTime = Zotero.Date.dateToSQL(
    256 					new Date(Date.now() - 2 * 24*60*60*1000), true);
    257 			yield readExpiredFI.saveTx();
    258 
    259 			// Added 5 days ago
    260 			unreadExpiredFI = yield createDataObject('feedItem', { 
    261 				libraryID: feed.libraryID,
    262 				dateAdded: Zotero.Date.dateToSQL(new Date(Date.now() - 5 * 24*60*60*1000), true),
    263 				dateModified: Zotero.Date.dateToSQL(new Date(Date.now() - 5 * 24*60*60*1000), true)
    264 			});
    265 			yield unreadExpiredFI.saveTx();
    266 			
    267 			readStillInFeed = yield createDataObject('feedItem', { libraryID: feed.libraryID });
    268 			// Read 2 days ago
    269 			readStillInFeed.isRead = true;
    270 			readStillInFeed._feedItemReadTime = Zotero.Date.dateToSQL(
    271 					new Date(Date.now() - 2 * 24*60*60*1000), true);
    272 			yield readStillInFeed.saveTx();
    273 			
    274 			readFeedItem = yield createDataObject('feedItem', { libraryID: feed.libraryID });
    275 			readFeedItem.isRead = true;
    276 			yield readFeedItem.saveTx();
    277 			
    278 			feedItem = yield createDataObject('feedItem', { libraryID: feed.libraryID });
    279 			
    280 			feedItemIDs = yield Zotero.FeedItems.getAll(feed.libraryID).map((row) => row.id);
    281 			
    282 			assert.include(feedItemIDs, feedItem.id, "feed contains unread feed item");
    283 			assert.include(feedItemIDs, readFeedItem.id, "feed contains read feed item");
    284 			assert.include(feedItemIDs, readExpiredFI.id, "feed contains expired feed item");
    285 			assert.include(feedItemIDs, readStillInFeed.id, "feed contains expired but still in rss feed item");
    286 			
    287 			yield feed.clearExpiredItems(new Set([readStillInFeed.id]));
    288 			
    289 			feedItemIDs = yield Zotero.FeedItems.getAll(feed.libraryID).map((row) => row.id);
    290 		});
    291 	
    292 		it('should clear expired items', function() {
    293 			assert.notInclude(feedItemIDs, readExpiredFI.id, "feed no longer contains expired read feed item");
    294 			assert.notInclude(feedItemIDs, unreadExpiredFI.id, "feed no longer contains expired feed item");	
    295 		});
    296 		
    297 		it('should not clear read items that have not expired yet', function() {
    298 			assert.include(feedItemIDs, readFeedItem.id, "feed still contains new feed item");
    299 		});
    300 		
    301 		it('should not clear read items that are still in rss', function() {
    302 			assert.include(feedItemIDs, readStillInFeed.id, "feed still contains read still in rss feed item");
    303 		});
    304 		
    305 		it('should not clear unread items', function() {
    306 			assert.include(feedItemIDs, feedItem.id, "feed still contains new feed item");
    307 		});
    308 	});
    309 	
    310 	describe('#updateFeed()', function() {
    311 		var feed, scheduleNextFeedCheck;
    312 		var feedUrl = getTestDataUrl("feed.rss");
    313 		var modifiedFeedUrl = getTestDataUrl("feedModified.rss");
    314 		
    315 		before(function() {
    316 			scheduleNextFeedCheck = sinon.stub(Zotero.Feeds, 'scheduleNextFeedCheck').resolves();
    317 		});
    318 		
    319 		beforeEach(function* (){
    320 			scheduleNextFeedCheck.resetHistory();
    321 			feed = yield createFeed();
    322 			feed._feedUrl = feedUrl;
    323 			yield feed.updateFeed();
    324 		});
    325 		
    326 		afterEach(function* () {
    327 			yield clearFeeds();
    328 		});
    329 		
    330 		after(function() {
    331 			scheduleNextFeedCheck.restore();
    332 		});
    333 		
    334 		it('should schedule next feed check', function* () {
    335 			let feed = yield createFeed();
    336 			feed._feedUrl = feedUrl;
    337 			yield feed.updateFeed();
    338 			assert.equal(scheduleNextFeedCheck.called, true);
    339 		});
    340 		
    341 		it('should add new feed items', function* () {
    342 			let feedItems = yield Zotero.FeedItems.getAll(feed.id, true);
    343 			assert.equal(feedItems.length, 3);
    344 		});
    345 		
    346 		it('should set lastCheck and lastUpdated values', function* () {
    347 			yield clearFeeds();
    348 			let feed = yield createFeed();
    349 			feed._feedUrl = feedUrl;
    350 			
    351 			assert.notOk(feed.lastCheck);
    352 			assert.notOk(feed.lastUpdate);
    353 			
    354 			yield feed.updateFeed();
    355 			
    356 			assert.isTrue(feed.lastCheck > Zotero.Date.dateToSQL(new Date(Date.now() - 1000*60), true), 'feed.lastCheck updated');
    357 			assert.isTrue(feed.lastUpdate > Zotero.Date.dateToSQL(new Date(Date.now() - 1000*60), true), 'feed.lastUpdate updated');
    358 		});
    359 		it('should update modified items and set unread', function* () {
    360 			let feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573");
    361 			feedItem.isRead = true;
    362 			yield feedItem.saveTx();
    363 			feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573");
    364 			assert.isTrue(feedItem.isRead);
    365 			
    366 			let oldDateModified = feedItem.getField('date');
    367 			
    368 			feed._feedUrl = modifiedFeedUrl;
    369 			yield feed.updateFeed();
    370 			
    371 			feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573");
    372 			
    373 			assert.notEqual(oldDateModified, feedItem.getField('date'));
    374 			assert.isFalse(feedItem.isRead)
    375 		});
    376 		it('should skip items that are not modified', function* () {
    377 			let save = sinon.spy(Zotero.FeedItem.prototype, 'save');
    378 			
    379 			feed._feedUrl = modifiedFeedUrl;
    380 			yield feed.updateFeed();
    381 			
    382 			assert.equal(save.thisValues[0].guid, "http://liftoff.msfc.nasa.gov/2003/06/03.html#item573");
    383 			save.restore();
    384 		});
    385 		it('should update unread count', function* () {
    386 			assert.equal(feed.unreadCount, 3);
    387 
    388 			let feedItems = yield Zotero.FeedItems.getAll(feed.id);
    389 			for (let feedItem of feedItems) {
    390 				feedItem.isRead = true;
    391 				yield feedItem.saveTx();
    392 			}
    393 			
    394 			feed._feedUrl = modifiedFeedUrl;
    395 			yield feed.updateFeed();
    396 			
    397 			assert.equal(feed.unreadCount, 2);
    398 		});
    399 		it('should add a link to enclosed pdfs from <enclosure/> elements', function* () {
    400 			let feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573");
    401 			let pdf = yield Zotero.Items.getAsync(feedItem.getAttachments()[0]);
    402 			
    403 			assert.equal(pdf.getField('url'), "http://www.example.com/example.pdf");
    404 		});
    405 	});
    406 	
    407 	describe("Adding items", function() {
    408 		let feed;
    409 		before(function* () {
    410 			feed = yield createFeed();
    411 		})
    412 		it("should not allow adding collections", function* () {
    413 			let collection = new Zotero.Collection({ name: 'test', libraryID: feed.libraryID });
    414 			yield assert.isRejected(collection.saveTx({ skipEditCheck: true }), /^Cannot add /);
    415 		});
    416 		it("should not allow adding saved search", function* () {
    417 			let search = new Zotero.Search({ name: 'test', libraryID: feed.libraryID });
    418 			yield assert.isRejected(search.saveTx({ skipEditCheck: true }), /^Cannot add /);
    419 		});
    420 		it("should allow adding feed item", function* () {
    421 			let feedItem = new Zotero.FeedItem('book', { guid: Zotero.randomString() });
    422 			feedItem.libraryID = feed.libraryID;
    423 			yield assert.isFulfilled(feedItem.saveTx());
    424 		});
    425 	});
    426 })