1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
3 import { expect } from 'chai'
4 import { inspect } from 'util'
5 import { AbuseState, PluginType } from '@shared/models'
6 import { UserNotification, UserNotificationSetting, UserNotificationSettingValue, UserNotificationType } from '../../models/users'
7 import { MockSmtpServer } from '../mock-servers/mock-email'
8 import { PeerTubeServer } from '../server'
9 import { doubleFollow } from '../server/follows'
10 import { createMultipleServers } from '../server/servers'
11 import { setAccessTokensToServers } from './login'
13 type CheckerBaseParams = {
14 server: PeerTubeServer
16 socketNotifications: UserNotification[]
18 check?: { web: boolean, mail: boolean }
21 type CheckerType = 'presence' | 'absence'
23 function getAllNotificationsSettings (): UserNotificationSetting {
25 newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
26 newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
27 abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
28 videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
29 blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
30 myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
31 myVideoPublished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
32 commentMention: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
33 newFollow: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
34 newUserRegistration: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
35 newInstanceFollower: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
36 abuseNewMessage: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
37 abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
38 autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
39 newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
40 newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL
44 async function checkNewVideoFromSubscription (options: CheckerBaseParams & {
47 checkType: CheckerType
49 const { videoName, shortUUID } = options
50 const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION
52 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
53 if (checkType === 'presence') {
54 expect(notification).to.not.be.undefined
55 expect(notification.type).to.equal(notificationType)
57 checkVideo(notification.video, videoName, shortUUID)
58 checkActor(notification.video.channel)
60 expect(notification).to.satisfy((n: UserNotification) => {
61 return n === undefined || n.type !== UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION || n.video.name !== videoName
66 function emailNotificationFinder (email: object) {
67 const text = email['text']
68 return text.indexOf(shortUUID) !== -1 && text.indexOf('Your subscription') !== -1
71 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
74 async function checkVideoIsPublished (options: CheckerBaseParams & {
77 checkType: CheckerType
79 const { videoName, shortUUID } = options
80 const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED
82 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
83 if (checkType === 'presence') {
84 expect(notification).to.not.be.undefined
85 expect(notification.type).to.equal(notificationType)
87 checkVideo(notification.video, videoName, shortUUID)
88 checkActor(notification.video.channel)
90 expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName)
94 function emailNotificationFinder (email: object) {
95 const text: string = email['text']
96 return text.includes(shortUUID) && text.includes('Your video')
99 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
102 async function checkMyVideoImportIsFinished (options: CheckerBaseParams & {
107 checkType: CheckerType
109 const { videoName, shortUUID, url, success } = options
111 const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR
113 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
114 if (checkType === 'presence') {
115 expect(notification).to.not.be.undefined
116 expect(notification.type).to.equal(notificationType)
118 expect(notification.videoImport.targetUrl).to.equal(url)
120 if (success) checkVideo(notification.videoImport.video, videoName, shortUUID)
122 expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url)
126 function emailNotificationFinder (email: object) {
127 const text: string = email['text']
128 const toFind = success ? ' finished' : ' error'
130 return text.includes(url) && text.includes(toFind)
133 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
136 async function checkUserRegistered (options: CheckerBaseParams & {
138 checkType: CheckerType
140 const { username } = options
141 const notificationType = UserNotificationType.NEW_USER_REGISTRATION
143 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
144 if (checkType === 'presence') {
145 expect(notification).to.not.be.undefined
146 expect(notification.type).to.equal(notificationType)
148 checkActor(notification.account)
149 expect(notification.account.name).to.equal(username)
151 expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username)
155 function emailNotificationFinder (email: object) {
156 const text: string = email['text']
158 return text.includes(' registered.') && text.includes(username)
161 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
164 async function checkNewActorFollow (options: CheckerBaseParams & {
165 followType: 'channel' | 'account'
167 followerDisplayName: string
168 followingDisplayName: string
169 checkType: CheckerType
171 const { followType, followerName, followerDisplayName, followingDisplayName } = options
172 const notificationType = UserNotificationType.NEW_FOLLOW
174 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
175 if (checkType === 'presence') {
176 expect(notification).to.not.be.undefined
177 expect(notification.type).to.equal(notificationType)
179 checkActor(notification.actorFollow.follower)
180 expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName)
181 expect(notification.actorFollow.follower.name).to.equal(followerName)
182 expect(notification.actorFollow.follower.host).to.not.be.undefined
184 const following = notification.actorFollow.following
185 expect(following.displayName).to.equal(followingDisplayName)
186 expect(following.type).to.equal(followType)
188 expect(notification).to.satisfy(n => {
189 return n.type !== notificationType ||
190 (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName)
195 function emailNotificationFinder (email: object) {
196 const text: string = email['text']
198 return text.includes(followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
201 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
204 async function checkNewInstanceFollower (options: CheckerBaseParams & {
206 checkType: CheckerType
208 const { followerHost } = options
209 const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER
211 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
212 if (checkType === 'presence') {
213 expect(notification).to.not.be.undefined
214 expect(notification.type).to.equal(notificationType)
216 checkActor(notification.actorFollow.follower)
217 expect(notification.actorFollow.follower.name).to.equal('peertube')
218 expect(notification.actorFollow.follower.host).to.equal(followerHost)
220 expect(notification.actorFollow.following.name).to.equal('peertube')
222 expect(notification).to.satisfy(n => {
223 return n.type !== notificationType || n.actorFollow.follower.host !== followerHost
228 function emailNotificationFinder (email: object) {
229 const text: string = email['text']
231 return text.includes('instance has a new follower') && text.includes(followerHost)
234 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
237 async function checkAutoInstanceFollowing (options: CheckerBaseParams & {
239 followingHost: string
240 checkType: CheckerType
242 const { followerHost, followingHost } = options
243 const notificationType = UserNotificationType.AUTO_INSTANCE_FOLLOWING
245 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
246 if (checkType === 'presence') {
247 expect(notification).to.not.be.undefined
248 expect(notification.type).to.equal(notificationType)
250 const following = notification.actorFollow.following
251 checkActor(following)
252 expect(following.name).to.equal('peertube')
253 expect(following.host).to.equal(followingHost)
255 expect(notification.actorFollow.follower.name).to.equal('peertube')
256 expect(notification.actorFollow.follower.host).to.equal(followerHost)
258 expect(notification).to.satisfy(n => {
259 return n.type !== notificationType || n.actorFollow.following.host !== followingHost
264 function emailNotificationFinder (email: object) {
265 const text: string = email['text']
267 return text.includes(' automatically followed a new instance') && text.includes(followingHost)
270 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
273 async function checkCommentMention (options: CheckerBaseParams & {
277 byAccountDisplayName: string
278 checkType: CheckerType
280 const { shortUUID, commentId, threadId, byAccountDisplayName } = options
281 const notificationType = UserNotificationType.COMMENT_MENTION
283 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
284 if (checkType === 'presence') {
285 expect(notification).to.not.be.undefined
286 expect(notification.type).to.equal(notificationType)
288 checkComment(notification.comment, commentId, threadId)
289 checkActor(notification.comment.account)
290 expect(notification.comment.account.displayName).to.equal(byAccountDisplayName)
292 checkVideo(notification.comment.video, undefined, shortUUID)
294 expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId)
298 function emailNotificationFinder (email: object) {
299 const text: string = email['text']
301 return text.includes(' mentioned ') && text.includes(shortUUID) && text.includes(byAccountDisplayName)
304 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
307 let lastEmailCount = 0
309 async function checkNewCommentOnMyVideo (options: CheckerBaseParams & {
313 checkType: CheckerType
315 const { server, shortUUID, commentId, threadId, checkType, emails } = options
316 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
318 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
319 if (checkType === 'presence') {
320 expect(notification).to.not.be.undefined
321 expect(notification.type).to.equal(notificationType)
323 checkComment(notification.comment, commentId, threadId)
324 checkActor(notification.comment.account)
325 checkVideo(notification.comment.video, undefined, shortUUID)
327 expect(notification).to.satisfy((n: UserNotification) => {
328 return n === undefined || n.comment === undefined || n.comment.id !== commentId
333 const commentUrl = `http://localhost:${server.port}/w/${shortUUID};threadId=${threadId}`
335 function emailNotificationFinder (email: object) {
336 return email['text'].indexOf(commentUrl) !== -1
339 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
341 if (checkType === 'presence') {
342 // We cannot detect email duplicates, so check we received another email
343 expect(emails).to.have.length.above(lastEmailCount)
344 lastEmailCount = emails.length
348 async function checkNewVideoAbuseForModerators (options: CheckerBaseParams & {
351 checkType: CheckerType
353 const { shortUUID, videoName } = options
354 const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
356 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
357 if (checkType === 'presence') {
358 expect(notification).to.not.be.undefined
359 expect(notification.type).to.equal(notificationType)
361 expect(notification.abuse.id).to.be.a('number')
362 checkVideo(notification.abuse.video, videoName, shortUUID)
364 expect(notification).to.satisfy((n: UserNotification) => {
365 return n === undefined || n.abuse === undefined || n.abuse.video.shortUUID !== shortUUID
370 function emailNotificationFinder (email: object) {
371 const text = email['text']
372 return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1
375 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
378 async function checkNewAbuseMessage (options: CheckerBaseParams & {
382 checkType: CheckerType
384 const { abuseId, message, toEmail } = options
385 const notificationType = UserNotificationType.ABUSE_NEW_MESSAGE
387 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
388 if (checkType === 'presence') {
389 expect(notification).to.not.be.undefined
390 expect(notification.type).to.equal(notificationType)
392 expect(notification.abuse.id).to.equal(abuseId)
394 expect(notification).to.satisfy((n: UserNotification) => {
395 return n === undefined || n.type !== notificationType || n.abuse === undefined || n.abuse.id !== abuseId
400 function emailNotificationFinder (email: object) {
401 const text = email['text']
402 const to = email['to'].filter(t => t.address === toEmail)
404 return text.indexOf(message) !== -1 && to.length !== 0
407 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
410 async function checkAbuseStateChange (options: CheckerBaseParams & {
413 checkType: CheckerType
415 const { abuseId, state } = options
416 const notificationType = UserNotificationType.ABUSE_STATE_CHANGE
418 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
419 if (checkType === 'presence') {
420 expect(notification).to.not.be.undefined
421 expect(notification.type).to.equal(notificationType)
423 expect(notification.abuse.id).to.equal(abuseId)
424 expect(notification.abuse.state).to.equal(state)
426 expect(notification).to.satisfy((n: UserNotification) => {
427 return n === undefined || n.abuse === undefined || n.abuse.id !== abuseId
432 function emailNotificationFinder (email: object) {
433 const text = email['text']
435 const contains = state === AbuseState.ACCEPTED
439 return text.indexOf(contains) !== -1
442 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
445 async function checkNewCommentAbuseForModerators (options: CheckerBaseParams & {
448 checkType: CheckerType
450 const { shortUUID, videoName } = options
451 const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
453 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
454 if (checkType === 'presence') {
455 expect(notification).to.not.be.undefined
456 expect(notification.type).to.equal(notificationType)
458 expect(notification.abuse.id).to.be.a('number')
459 checkVideo(notification.abuse.comment.video, videoName, shortUUID)
461 expect(notification).to.satisfy((n: UserNotification) => {
462 return n === undefined || n.abuse === undefined || n.abuse.comment.video.shortUUID !== shortUUID
467 function emailNotificationFinder (email: object) {
468 const text = email['text']
469 return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1
472 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
475 async function checkNewAccountAbuseForModerators (options: CheckerBaseParams & {
477 checkType: CheckerType
479 const { displayName } = options
480 const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
482 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
483 if (checkType === 'presence') {
484 expect(notification).to.not.be.undefined
485 expect(notification.type).to.equal(notificationType)
487 expect(notification.abuse.id).to.be.a('number')
488 expect(notification.abuse.account.displayName).to.equal(displayName)
490 expect(notification).to.satisfy((n: UserNotification) => {
491 return n === undefined || n.abuse === undefined || n.abuse.account.displayName !== displayName
496 function emailNotificationFinder (email: object) {
497 const text = email['text']
498 return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1
501 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
504 async function checkVideoAutoBlacklistForModerators (options: CheckerBaseParams & {
507 checkType: CheckerType
509 const { shortUUID, videoName } = options
510 const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS
512 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
513 if (checkType === 'presence') {
514 expect(notification).to.not.be.undefined
515 expect(notification.type).to.equal(notificationType)
517 expect(notification.videoBlacklist.video.id).to.be.a('number')
518 checkVideo(notification.videoBlacklist.video, videoName, shortUUID)
520 expect(notification).to.satisfy((n: UserNotification) => {
521 return n === undefined || n.video === undefined || n.video.shortUUID !== shortUUID
526 function emailNotificationFinder (email: object) {
527 const text = email['text']
528 return text.indexOf(shortUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1
531 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
534 async function checkNewBlacklistOnMyVideo (options: CheckerBaseParams & {
537 blacklistType: 'blacklist' | 'unblacklist'
539 const { videoName, shortUUID, blacklistType } = options
540 const notificationType = blacklistType === 'blacklist'
541 ? UserNotificationType.BLACKLIST_ON_MY_VIDEO
542 : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO
544 function notificationChecker (notification: UserNotification) {
545 expect(notification).to.not.be.undefined
546 expect(notification.type).to.equal(notificationType)
548 const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video
550 checkVideo(video, videoName, shortUUID)
553 function emailNotificationFinder (email: object) {
554 const text = email['text']
555 const blacklistText = blacklistType === 'blacklist'
559 return text.includes(shortUUID) && text.includes(blacklistText)
562 await checkNotification({ ...options, notificationChecker, emailNotificationFinder, checkType: 'presence' })
565 async function checkNewPeerTubeVersion (options: CheckerBaseParams & {
566 latestVersion: string
567 checkType: CheckerType
569 const { latestVersion } = options
570 const notificationType = UserNotificationType.NEW_PEERTUBE_VERSION
572 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
573 if (checkType === 'presence') {
574 expect(notification).to.not.be.undefined
575 expect(notification.type).to.equal(notificationType)
577 expect(notification.peertube).to.exist
578 expect(notification.peertube.latestVersion).to.equal(latestVersion)
580 expect(notification).to.satisfy((n: UserNotification) => {
581 return n === undefined || n.peertube === undefined || n.peertube.latestVersion !== latestVersion
586 function emailNotificationFinder (email: object) {
587 const text = email['text']
589 return text.includes(latestVersion)
592 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
595 async function checkNewPluginVersion (options: CheckerBaseParams & {
596 pluginType: PluginType
598 checkType: CheckerType
600 const { pluginName, pluginType } = options
601 const notificationType = UserNotificationType.NEW_PLUGIN_VERSION
603 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
604 if (checkType === 'presence') {
605 expect(notification).to.not.be.undefined
606 expect(notification.type).to.equal(notificationType)
608 expect(notification.plugin.name).to.equal(pluginName)
609 expect(notification.plugin.type).to.equal(pluginType)
611 expect(notification).to.satisfy((n: UserNotification) => {
612 return n === undefined || n.plugin === undefined || n.plugin.name !== pluginName
617 function emailNotificationFinder (email: object) {
618 const text = email['text']
620 return text.includes(pluginName)
623 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
626 async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: any = {}) {
627 const userNotifications: UserNotification[] = []
628 const adminNotifications: UserNotification[] = []
629 const adminNotificationsServer2: UserNotification[] = []
630 const emails: object[] = []
632 const port = await MockSmtpServer.Instance.collectEmails(emails)
634 const overrideConfig = {
636 hostname: 'localhost',
643 const servers = await createMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg))
645 await setAccessTokensToServers(servers)
647 if (serversCount > 1) {
648 await doubleFollow(servers[0], servers[1])
651 const user = { username: 'user_1', password: 'super password' }
652 await servers[0].users.create({ ...user, videoQuota: 10 * 1000 * 1000 })
653 const userAccessToken = await servers[0].login.getAccessToken(user)
655 await servers[0].notifications.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() })
656 await servers[0].notifications.updateMySettings({ settings: getAllNotificationsSettings() })
658 if (serversCount > 1) {
659 await servers[1].notifications.updateMySettings({ settings: getAllNotificationsSettings() })
663 const socket = servers[0].socketIO.getUserNotificationSocket({ token: userAccessToken })
664 socket.on('new-notification', n => userNotifications.push(n))
667 const socket = servers[0].socketIO.getUserNotificationSocket()
668 socket.on('new-notification', n => adminNotifications.push(n))
671 if (serversCount > 1) {
672 const socket = servers[1].socketIO.getUserNotificationSocket()
673 socket.on('new-notification', n => adminNotificationsServer2.push(n))
676 const { videoChannels } = await servers[0].users.getMyInfo()
677 const channelId = videoChannels[0].id
682 adminNotificationsServer2,
690 // ---------------------------------------------------------------------------
693 getAllNotificationsSettings,
697 checkMyVideoImportIsFinished,
699 checkAutoInstanceFollowing,
700 checkVideoIsPublished,
701 checkNewVideoFromSubscription,
703 checkNewCommentOnMyVideo,
704 checkNewBlacklistOnMyVideo,
706 checkNewVideoAbuseForModerators,
707 checkVideoAutoBlacklistForModerators,
708 checkNewAbuseMessage,
709 checkAbuseStateChange,
710 checkNewInstanceFollower,
711 prepareNotificationsTest,
712 checkNewCommentAbuseForModerators,
713 checkNewAccountAbuseForModerators,
714 checkNewPeerTubeVersion,
715 checkNewPluginVersion
718 // ---------------------------------------------------------------------------
720 async function checkNotification (options: CheckerBaseParams & {
721 notificationChecker: (notification: UserNotification, checkType: CheckerType) => void
722 emailNotificationFinder: (email: object) => boolean
723 checkType: CheckerType
725 const { server, token, checkType, notificationChecker, emailNotificationFinder, socketNotifications, emails } = options
727 const check = options.check || { web: true, mail: true }
730 const notification = await server.notifications.getLastest({ token: token })
732 if (notification || checkType !== 'absence') {
733 notificationChecker(notification, checkType)
736 const socketNotification = socketNotifications.find(n => {
738 notificationChecker(n, 'presence')
745 if (checkType === 'presence') {
746 const obj = inspect(socketNotifications, { depth: 5 })
747 expect(socketNotification, 'The socket notification is absent when it should be present. ' + obj).to.not.be.undefined
749 const obj = inspect(socketNotification, { depth: 5 })
750 expect(socketNotification, 'The socket notification is present when it should not be present. ' + obj).to.be.undefined
759 .find(e => emailNotificationFinder(e))
761 if (checkType === 'presence') {
762 const texts = emails.map(e => e.text)
763 expect(email, 'The email is absent when is should be present. ' + inspect(texts)).to.not.be.undefined
765 expect(email, 'The email is present when is should not be present. ' + inspect(email)).to.be.undefined
770 function checkVideo (video: any, videoName?: string, shortUUID?: string) {
772 expect(video.name).to.be.a('string')
773 expect(video.name).to.not.be.empty
774 expect(video.name).to.equal(videoName)
778 expect(video.shortUUID).to.be.a('string')
779 expect(video.shortUUID).to.not.be.empty
780 expect(video.shortUUID).to.equal(shortUUID)
783 expect(video.id).to.be.a('number')
786 function checkActor (actor: any) {
787 expect(actor.displayName).to.be.a('string')
788 expect(actor.displayName).to.not.be.empty
789 expect(actor.host).to.not.be.undefined
792 function checkComment (comment: any, commentId: number, threadId: number) {
793 expect(comment.id).to.equal(commentId)
794 expect(comment.threadId).to.equal(threadId)