mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 19:15:58 +01:00 
			
		
		
		
	* feat: als * fix: up test timeout * fix: don't overwrite caller if it already exists * fix: up test timeout for psql
		
			
				
	
	
		
			486 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			486 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| 
 | |
| const assert = require('assert');
 | |
| const async = require('async');
 | |
| const nconf = require('nconf');
 | |
| 
 | |
| const db = require('./mocks/databasemock');
 | |
| const meta = require('../src/meta');
 | |
| const user = require('../src/user');
 | |
| const topics = require('../src/topics');
 | |
| const categories = require('../src/categories');
 | |
| const groups = require('../src/groups');
 | |
| const notifications = require('../src/notifications');
 | |
| const socketNotifications = require('../src/socket.io/notifications');
 | |
| 
 | |
| describe('Notifications', () => {
 | |
| 	let uid;
 | |
| 	let notification;
 | |
| 
 | |
| 	before((done) => {
 | |
| 		user.create({ username: 'poster' }, (err, _uid) => {
 | |
| 			if (err) {
 | |
| 				return done(err);
 | |
| 			}
 | |
| 
 | |
| 			uid = _uid;
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should fail to create notification without a nid', (done) => {
 | |
| 		notifications.create({}, (err) => {
 | |
| 			assert.equal(err.message, '[[error:no-notification-id]]');
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should create a notification', (done) => {
 | |
| 		notifications.create({
 | |
| 			bodyShort: 'bodyShort',
 | |
| 			nid: 'notification_id',
 | |
| 			path: '/notification/path',
 | |
| 			pid: 1,
 | |
| 		}, (err, _notification) => {
 | |
| 			notification = _notification;
 | |
| 			assert.ifError(err);
 | |
| 			assert(notification);
 | |
| 			db.exists(`notifications:${notification.nid}`, (err, exists) => {
 | |
| 				assert.ifError(err);
 | |
| 				assert(exists);
 | |
| 				db.isSortedSetMember('notifications', notification.nid, (err, isMember) => {
 | |
| 					assert.ifError(err);
 | |
| 					assert(isMember);
 | |
| 					done();
 | |
| 				});
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should return null if pid is same and importance is lower', (done) => {
 | |
| 		notifications.create({
 | |
| 			bodyShort: 'bodyShort',
 | |
| 			nid: 'notification_id',
 | |
| 			path: '/notification/path',
 | |
| 			pid: 1,
 | |
| 			importance: 1,
 | |
| 		}, (err, notification) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert.strictEqual(notification, null);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should get empty array', (done) => {
 | |
| 		notifications.getMultiple(null, (err, data) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert(Array.isArray(data));
 | |
| 			assert.equal(data.length, 0);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should get notifications', (done) => {
 | |
| 		notifications.getMultiple([notification.nid], (err, notificationsData) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert(Array.isArray(notificationsData));
 | |
| 			assert(notificationsData[0]);
 | |
| 			assert.equal(notification.nid, notificationsData[0].nid);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should do nothing', (done) => {
 | |
| 		notifications.push(null, [], (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			notifications.push({ nid: null }, [], (err) => {
 | |
| 				assert.ifError(err);
 | |
| 				notifications.push(notification, [], (err) => {
 | |
| 					assert.ifError(err);
 | |
| 					done();
 | |
| 				});
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should push a notification to uid', (done) => {
 | |
| 		notifications.push(notification, [uid], (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			setTimeout(() => {
 | |
| 				db.isSortedSetMember(`uid:${uid}:notifications:unread`, notification.nid, (err, isMember) => {
 | |
| 					assert.ifError(err);
 | |
| 					assert(isMember);
 | |
| 					done();
 | |
| 				});
 | |
| 			}, 2000);
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should push a notification to a group', (done) => {
 | |
| 		notifications.pushGroup(notification, 'registered-users', (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			setTimeout(() => {
 | |
| 				db.isSortedSetMember(`uid:${uid}:notifications:unread`, notification.nid, (err, isMember) => {
 | |
| 					assert.ifError(err);
 | |
| 					assert(isMember);
 | |
| 					done();
 | |
| 				});
 | |
| 			}, 2000);
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should push a notification to groups', (done) => {
 | |
| 		notifications.pushGroups(notification, ['registered-users', 'administrators'], (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			setTimeout(() => {
 | |
| 				db.isSortedSetMember(`uid:${uid}:notifications:unread`, notification.nid, (err, isMember) => {
 | |
| 					assert.ifError(err);
 | |
| 					assert(isMember);
 | |
| 					done();
 | |
| 				});
 | |
| 			}, 2000);
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should not mark anything with invalid uid or nid', (done) => {
 | |
| 		socketNotifications.markRead({ uid: null }, null, (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			socketNotifications.markRead({ uid: uid }, null, (err) => {
 | |
| 				assert.ifError(err);
 | |
| 				done();
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should mark a notification read', (done) => {
 | |
| 		socketNotifications.markRead({ uid: uid }, notification.nid, (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			db.isSortedSetMember(`uid:${uid}:notifications:unread`, notification.nid, (err, isMember) => {
 | |
| 				assert.ifError(err);
 | |
| 				assert.equal(isMember, false);
 | |
| 				db.isSortedSetMember(`uid:${uid}:notifications:read`, notification.nid, (err, isMember) => {
 | |
| 					assert.ifError(err);
 | |
| 					assert.equal(isMember, true);
 | |
| 					done();
 | |
| 				});
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should not mark anything with invalid uid or nid', (done) => {
 | |
| 		socketNotifications.markUnread({ uid: null }, null, (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			socketNotifications.markUnread({ uid: uid }, null, (err) => {
 | |
| 				assert.ifError(err);
 | |
| 				done();
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should error if notification does not exist', (done) => {
 | |
| 		socketNotifications.markUnread({ uid: uid }, 123123, (err) => {
 | |
| 			assert.equal(err.message, '[[error:no-notification]]');
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should mark a notification unread', (done) => {
 | |
| 		socketNotifications.markUnread({ uid: uid }, notification.nid, (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			db.isSortedSetMember(`uid:${uid}:notifications:unread`, notification.nid, (err, isMember) => {
 | |
| 				assert.ifError(err);
 | |
| 				assert.equal(isMember, true);
 | |
| 				db.isSortedSetMember(`uid:${uid}:notifications:read`, notification.nid, (err, isMember) => {
 | |
| 					assert.ifError(err);
 | |
| 					assert.equal(isMember, false);
 | |
| 					socketNotifications.getCount({ uid: uid }, null, (err, count) => {
 | |
| 						assert.ifError(err);
 | |
| 						assert.equal(count, 1);
 | |
| 						done();
 | |
| 					});
 | |
| 				});
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should mark all notifications read', (done) => {
 | |
| 		socketNotifications.markAllRead({ uid: uid }, null, (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			db.isSortedSetMember(`uid:${uid}:notifications:unread`, notification.nid, (err, isMember) => {
 | |
| 				assert.ifError(err);
 | |
| 				assert.equal(isMember, false);
 | |
| 				db.isSortedSetMember(`uid:${uid}:notifications:read`, notification.nid, (err, isMember) => {
 | |
| 					assert.ifError(err);
 | |
| 					assert.equal(isMember, true);
 | |
| 					done();
 | |
| 				});
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should not do anything', (done) => {
 | |
| 		socketNotifications.markAllRead({ uid: 1000 }, null, (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should link to the first unread post in a watched topic', (done) => {
 | |
| 		const categories = require('../src/categories');
 | |
| 		const topics = require('../src/topics');
 | |
| 		let watcherUid;
 | |
| 		let cid;
 | |
| 		let tid;
 | |
| 		let pid;
 | |
| 
 | |
| 		async.waterfall([
 | |
| 			function (next) {
 | |
| 				user.create({ username: 'watcher' }, next);
 | |
| 			},
 | |
| 			function (_watcherUid, next) {
 | |
| 				watcherUid = _watcherUid;
 | |
| 
 | |
| 				categories.create({
 | |
| 					name: 'Test Category',
 | |
| 					description: 'Test category created by testing script',
 | |
| 				}, next);
 | |
| 			},
 | |
| 			function (category, next) {
 | |
| 				cid = category.cid;
 | |
| 
 | |
| 				topics.post({
 | |
| 					uid: watcherUid,
 | |
| 					cid: cid,
 | |
| 					title: 'Test Topic Title',
 | |
| 					content: 'The content of test topic',
 | |
| 				}, next);
 | |
| 			},
 | |
| 			function (topic, next) {
 | |
| 				tid = topic.topicData.tid;
 | |
| 
 | |
| 				topics.follow(tid, watcherUid, next);
 | |
| 			},
 | |
| 			function (next) {
 | |
| 				topics.reply({
 | |
| 					uid: uid,
 | |
| 					content: 'This is the first reply.',
 | |
| 					tid: tid,
 | |
| 				}, next);
 | |
| 			},
 | |
| 			function (post, next) {
 | |
| 				pid = post.pid;
 | |
| 
 | |
| 				topics.reply({
 | |
| 					uid: uid,
 | |
| 					content: 'This is the second reply.',
 | |
| 					tid: tid,
 | |
| 				}, next);
 | |
| 			},
 | |
| 			function (post, next) {
 | |
| 				// notifications are sent asynchronously with a 1 second delay.
 | |
| 				setTimeout(next, 3000);
 | |
| 			},
 | |
| 			function (next) {
 | |
| 				user.notifications.get(watcherUid, next);
 | |
| 			},
 | |
| 			function (notifications, next) {
 | |
| 				assert.equal(notifications.unread.length, 1, 'there should be 1 unread notification');
 | |
| 				assert.equal(`${nconf.get('relative_path')}/post/${pid}`, notifications.unread[0].path, 'the notification should link to the first unread post');
 | |
| 				next();
 | |
| 			},
 | |
| 		], (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should get notification by nid', (done) => {
 | |
| 		socketNotifications.get({ uid: uid }, { nids: [notification.nid] }, (err, data) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert.equal(data[0].bodyShort, 'bodyShort');
 | |
| 			assert.equal(data[0].nid, 'notification_id');
 | |
| 			assert.equal(data[0].path, `${nconf.get('relative_path')}/notification/path`);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should get user\'s notifications', (done) => {
 | |
| 		socketNotifications.get({ uid: uid }, {}, (err, data) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert.equal(data.unread.length, 0);
 | |
| 			assert.equal(data.read[0].nid, 'notification_id');
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should error if not logged in', (done) => {
 | |
| 		socketNotifications.deleteAll({ uid: 0 }, null, (err) => {
 | |
| 			assert.equal(err.message, '[[error:no-privileges]]');
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should delete all user notifications', (done) => {
 | |
| 		socketNotifications.deleteAll({ uid: uid }, null, (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			socketNotifications.get({ uid: uid }, {}, (err, data) => {
 | |
| 				assert.ifError(err);
 | |
| 				assert.equal(data.unread.length, 0);
 | |
| 				assert.equal(data.read.length, 0);
 | |
| 				done();
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should return empty with falsy uid', (done) => {
 | |
| 		user.notifications.get(0, (err, data) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert.equal(data.read.length, 0);
 | |
| 			assert.equal(data.unread.length, 0);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should get all notifications and filter', (done) => {
 | |
| 		const nid = 'willbefiltered';
 | |
| 		notifications.create({
 | |
| 			bodyShort: 'bodyShort',
 | |
| 			nid: nid,
 | |
| 			path: '/notification/path',
 | |
| 			type: 'post',
 | |
| 		}, (err, notification) => {
 | |
| 			assert.ifError(err);
 | |
| 			notifications.push(notification, [uid], (err) => {
 | |
| 				assert.ifError(err);
 | |
| 				setTimeout(() => {
 | |
| 					user.notifications.getAll(uid, 'post', (err, nids) => {
 | |
| 						assert.ifError(err);
 | |
| 						assert(nids.includes(nid));
 | |
| 						done();
 | |
| 					});
 | |
| 				}, 3000);
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should not get anything if notifications does not exist', (done) => {
 | |
| 		user.notifications.getNotifications(['doesnotexistnid1', 'doesnotexistnid2'], uid, (err, data) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert.deepEqual(data, []);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should get daily notifications', (done) => {
 | |
| 		user.notifications.getDailyUnread(uid, (err, data) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert.equal(data[0].nid, 'willbefiltered');
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should return empty array for invalid interval', (done) => {
 | |
| 		user.notifications.getUnreadInterval(uid, '2 aeons', (err, data) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert.deepEqual(data, []);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should return 0 for falsy uid', (done) => {
 | |
| 		user.notifications.getUnreadCount(0, (err, count) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert.equal(count, 0);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should not do anything if uid is falsy', (done) => {
 | |
| 		user.notifications.deleteAll(0, (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should send notification to followers of user when he posts', (done) => {
 | |
| 		let followerUid;
 | |
| 		async.waterfall([
 | |
| 			function (next) {
 | |
| 				user.create({ username: 'follower' }, next);
 | |
| 			},
 | |
| 			function (_followerUid, next) {
 | |
| 				followerUid = _followerUid;
 | |
| 				user.follow(followerUid, uid, next);
 | |
| 			},
 | |
| 			function (next) {
 | |
| 				categories.create({
 | |
| 					name: 'Test Category',
 | |
| 					description: 'Test category created by testing script',
 | |
| 				}, next);
 | |
| 			},
 | |
| 			function (category, next) {
 | |
| 				topics.post({
 | |
| 					uid: uid,
 | |
| 					cid: category.cid,
 | |
| 					title: 'Test Topic Title',
 | |
| 					content: 'The content of test topic',
 | |
| 				}, next);
 | |
| 			},
 | |
| 			function (data, next) {
 | |
| 				setTimeout(next, 1100);
 | |
| 			},
 | |
| 			function (next) {
 | |
| 				user.notifications.getAll(followerUid, '', next);
 | |
| 			},
 | |
| 		], (err, data) => {
 | |
| 			assert.ifError(err);
 | |
| 			assert(data);
 | |
| 			done();
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should send welcome notification', (done) => {
 | |
| 		meta.config.welcomeNotification = 'welcome to the forums';
 | |
| 		user.notifications.sendWelcomeNotification(uid, (err) => {
 | |
| 			assert.ifError(err);
 | |
| 			user.notifications.sendWelcomeNotification(uid, (err) => {
 | |
| 				assert.ifError(err);
 | |
| 				setTimeout(() => {
 | |
| 					user.notifications.getAll(uid, '', (err, data) => {
 | |
| 						meta.config.welcomeNotification = '';
 | |
| 						assert.ifError(err);
 | |
| 						assert(data.includes(`welcome_${uid}`), data);
 | |
| 						done();
 | |
| 					});
 | |
| 				}, 2000);
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	it('should prune notifications', (done) => {
 | |
| 		notifications.create({
 | |
| 			bodyShort: 'bodyShort',
 | |
| 			nid: 'tobedeleted',
 | |
| 			path: '/notification/path',
 | |
| 		}, (err, notification) => {
 | |
| 			assert.ifError(err);
 | |
| 			notifications.prune((err) => {
 | |
| 				assert.ifError(err);
 | |
| 				const month = 2592000000;
 | |
| 				db.sortedSetAdd('notifications', Date.now() - (2 * month), notification.nid, (err) => {
 | |
| 					assert.ifError(err);
 | |
| 					notifications.prune((err) => {
 | |
| 						assert.ifError(err);
 | |
| 						notifications.get(notification.nid, (err, data) => {
 | |
| 							assert.ifError(err);
 | |
| 							assert(!data);
 | |
| 							done();
 | |
| 						});
 | |
| 					});
 | |
| 				});
 | |
| 			});
 | |
| 		});
 | |
| 	});
 | |
| });
 |