1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
3 import { expect } from 'chai'
4 import { inspect } from 'util'
9 UserNotificationSetting,
10 UserNotificationSettingValue,
12 } from '@shared/models'
13 import { createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
14 import { MockSmtpServer } from './mock-servers'
16 type CheckerBaseParams = {
17 server: PeerTubeServer
19 socketNotifications: UserNotification[]
21 check?: { web: boolean, mail: boolean }
24 type CheckerType = 'presence' | 'absence'
26 function getAllNotificationsSettings (): UserNotificationSetting {
28 newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
29 newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
30 abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
31 videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
32 blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
33 myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
34 myVideoPublished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
35 commentMention: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
36 newFollow: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
37 newUserRegistration: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
38 newInstanceFollower: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
39 abuseNewMessage: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
40 abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
41 autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
42 newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
43 newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL
47 async function checkNewVideoFromSubscription (options: CheckerBaseParams & {
50 checkType: CheckerType
52 const { videoName, shortUUID } = options
53 const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION
55 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
56 if (checkType === 'presence') {
57 expect(notification).to.not.be.undefined
58 expect(notification.type).to.equal(notificationType)
60 checkVideo(notification.video, videoName, shortUUID)
61 checkActor(notification.video.channel)
63 expect(notification).to.satisfy((n: UserNotification) => {
64 return n === undefined || n.type !== UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION || n.video.name !== videoName
69 function emailNotificationFinder (email: object) {
70 const text = email['text']
71 return text.indexOf(shortUUID) !== -1 && text.indexOf('Your subscription') !== -1
74 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
77 async function checkVideoIsPublished (options: CheckerBaseParams & {
80 checkType: CheckerType
82 const { videoName, shortUUID } = options
83 const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED
85 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
86 if (checkType === 'presence') {
87 expect(notification).to.not.be.undefined
88 expect(notification.type).to.equal(notificationType)
90 checkVideo(notification.video, videoName, shortUUID)
91 checkActor(notification.video.channel)
93 expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName)
97 function emailNotificationFinder (email: object) {
98 const text: string = email['text']
99 return text.includes(shortUUID) && text.includes('Your video')
102 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
105 async function checkMyVideoImportIsFinished (options: CheckerBaseParams & {
110 checkType: CheckerType
112 const { videoName, shortUUID, url, success } = options
114 const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR
116 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
117 if (checkType === 'presence') {
118 expect(notification).to.not.be.undefined
119 expect(notification.type).to.equal(notificationType)
121 expect(notification.videoImport.targetUrl).to.equal(url)
123 if (success) checkVideo(notification.videoImport.video, videoName, shortUUID)
125 expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url)
129 function emailNotificationFinder (email: object) {
130 const text: string = email['text']
131 const toFind = success ? ' finished' : ' error'
133 return text.includes(url) && text.includes(toFind)
136 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
139 async function checkUserRegistered (options: CheckerBaseParams & {
141 checkType: CheckerType
143 const { username } = options
144 const notificationType = UserNotificationType.NEW_USER_REGISTRATION
146 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
147 if (checkType === 'presence') {
148 expect(notification).to.not.be.undefined
149 expect(notification.type).to.equal(notificationType)
151 checkActor(notification.account)
152 expect(notification.account.name).to.equal(username)
154 expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username)
158 function emailNotificationFinder (email: object) {
159 const text: string = email['text']
161 return text.includes(' registered.') && text.includes(username)
164 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
167 async function checkNewActorFollow (options: CheckerBaseParams & {
168 followType: 'channel' | 'account'
170 followerDisplayName: string
171 followingDisplayName: string
172 checkType: CheckerType
174 const { followType, followerName, followerDisplayName, followingDisplayName } = options
175 const notificationType = UserNotificationType.NEW_FOLLOW
177 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
178 if (checkType === 'presence') {
179 expect(notification).to.not.be.undefined
180 expect(notification.type).to.equal(notificationType)
182 checkActor(notification.actorFollow.follower)
183 expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName)
184 expect(notification.actorFollow.follower.name).to.equal(followerName)
185 expect(notification.actorFollow.follower.host).to.not.be.undefined
187 const following = notification.actorFollow.following
188 expect(following.displayName).to.equal(followingDisplayName)
189 expect(following.type).to.equal(followType)
191 expect(notification).to.satisfy(n => {
192 return n.type !== notificationType ||
193 (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName)
198 function emailNotificationFinder (email: object) {
199 const text: string = email['text']
201 return text.includes(followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
204 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
207 async function checkNewInstanceFollower (options: CheckerBaseParams & {
209 checkType: CheckerType
211 const { followerHost } = options
212 const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER
214 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
215 if (checkType === 'presence') {
216 expect(notification).to.not.be.undefined
217 expect(notification.type).to.equal(notificationType)
219 checkActor(notification.actorFollow.follower)
220 expect(notification.actorFollow.follower.name).to.equal('peertube')
221 expect(notification.actorFollow.follower.host).to.equal(followerHost)
223 expect(notification.actorFollow.following.name).to.equal('peertube')
225 expect(notification).to.satisfy(n => {
226 return n.type !== notificationType || n.actorFollow.follower.host !== followerHost
231 function emailNotificationFinder (email: object) {
232 const text: string = email['text']
234 return text.includes('instance has a new follower') && text.includes(followerHost)
237 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
240 async function checkAutoInstanceFollowing (options: CheckerBaseParams & {
242 followingHost: string
243 checkType: CheckerType
245 const { followerHost, followingHost } = options
246 const notificationType = UserNotificationType.AUTO_INSTANCE_FOLLOWING
248 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
249 if (checkType === 'presence') {
250 expect(notification).to.not.be.undefined
251 expect(notification.type).to.equal(notificationType)
253 const following = notification.actorFollow.following
254 checkActor(following)
255 expect(following.name).to.equal('peertube')
256 expect(following.host).to.equal(followingHost)
258 expect(notification.actorFollow.follower.name).to.equal('peertube')
259 expect(notification.actorFollow.follower.host).to.equal(followerHost)
261 expect(notification).to.satisfy(n => {
262 return n.type !== notificationType || n.actorFollow.following.host !== followingHost
267 function emailNotificationFinder (email: object) {
268 const text: string = email['text']
270 return text.includes(' automatically followed a new instance') && text.includes(followingHost)
273 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
276 async function checkCommentMention (options: CheckerBaseParams & {
280 byAccountDisplayName: string
281 checkType: CheckerType
283 const { shortUUID, commentId, threadId, byAccountDisplayName } = options
284 const notificationType = UserNotificationType.COMMENT_MENTION
286 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
287 if (checkType === 'presence') {
288 expect(notification).to.not.be.undefined
289 expect(notification.type).to.equal(notificationType)
291 checkComment(notification.comment, commentId, threadId)
292 checkActor(notification.comment.account)
293 expect(notification.comment.account.displayName).to.equal(byAccountDisplayName)
295 checkVideo(notification.comment.video, undefined, shortUUID)
297 expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId)
301 function emailNotificationFinder (email: object) {
302 const text: string = email['text']
304 return text.includes(' mentioned ') && text.includes(shortUUID) && text.includes(byAccountDisplayName)
307 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
310 let lastEmailCount = 0
312 async function checkNewCommentOnMyVideo (options: CheckerBaseParams & {
316 checkType: CheckerType
318 const { server, shortUUID, commentId, threadId, checkType, emails } = options
319 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
321 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
322 if (checkType === 'presence') {
323 expect(notification).to.not.be.undefined
324 expect(notification.type).to.equal(notificationType)
326 checkComment(notification.comment, commentId, threadId)
327 checkActor(notification.comment.account)
328 checkVideo(notification.comment.video, undefined, shortUUID)
330 expect(notification).to.satisfy((n: UserNotification) => {
331 return n === undefined || n.comment === undefined || n.comment.id !== commentId
336 const commentUrl = `http://localhost:${server.port}/w/${shortUUID};threadId=${threadId}`
338 function emailNotificationFinder (email: object) {
339 return email['text'].indexOf(commentUrl) !== -1
342 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
344 if (checkType === 'presence') {
345 // We cannot detect email duplicates, so check we received another email
346 expect(emails).to.have.length.above(lastEmailCount)
347 lastEmailCount = emails.length
351 async function checkNewVideoAbuseForModerators (options: CheckerBaseParams & {
354 checkType: CheckerType
356 const { shortUUID, videoName } = options
357 const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
359 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
360 if (checkType === 'presence') {
361 expect(notification).to.not.be.undefined
362 expect(notification.type).to.equal(notificationType)
364 expect(notification.abuse.id).to.be.a('number')
365 checkVideo(notification.abuse.video, videoName, shortUUID)
367 expect(notification).to.satisfy((n: UserNotification) => {
368 return n === undefined || n.abuse === undefined || n.abuse.video.shortUUID !== shortUUID
373 function emailNotificationFinder (email: object) {
374 const text = email['text']
375 return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1
378 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
381 async function checkNewAbuseMessage (options: CheckerBaseParams & {
385 checkType: CheckerType
387 const { abuseId, message, toEmail } = options
388 const notificationType = UserNotificationType.ABUSE_NEW_MESSAGE
390 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
391 if (checkType === 'presence') {
392 expect(notification).to.not.be.undefined
393 expect(notification.type).to.equal(notificationType)
395 expect(notification.abuse.id).to.equal(abuseId)
397 expect(notification).to.satisfy((n: UserNotification) => {
398 return n === undefined || n.type !== notificationType || n.abuse === undefined || n.abuse.id !== abuseId
403 function emailNotificationFinder (email: object) {
404 const text = email['text']
405 const to = email['to'].filter(t => t.address === toEmail)
407 return text.indexOf(message) !== -1 && to.length !== 0
410 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
413 async function checkAbuseStateChange (options: CheckerBaseParams & {
416 checkType: CheckerType
418 const { abuseId, state } = options
419 const notificationType = UserNotificationType.ABUSE_STATE_CHANGE
421 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
422 if (checkType === 'presence') {
423 expect(notification).to.not.be.undefined
424 expect(notification.type).to.equal(notificationType)
426 expect(notification.abuse.id).to.equal(abuseId)
427 expect(notification.abuse.state).to.equal(state)
429 expect(notification).to.satisfy((n: UserNotification) => {
430 return n === undefined || n.abuse === undefined || n.abuse.id !== abuseId
435 function emailNotificationFinder (email: object) {
436 const text = email['text']
438 const contains = state === AbuseState.ACCEPTED
442 return text.indexOf(contains) !== -1
445 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
448 async function checkNewCommentAbuseForModerators (options: CheckerBaseParams & {
451 checkType: CheckerType
453 const { shortUUID, videoName } = options
454 const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
456 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
457 if (checkType === 'presence') {
458 expect(notification).to.not.be.undefined
459 expect(notification.type).to.equal(notificationType)
461 expect(notification.abuse.id).to.be.a('number')
462 checkVideo(notification.abuse.comment.video, videoName, shortUUID)
464 expect(notification).to.satisfy((n: UserNotification) => {
465 return n === undefined || n.abuse === undefined || n.abuse.comment.video.shortUUID !== shortUUID
470 function emailNotificationFinder (email: object) {
471 const text = email['text']
472 return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1
475 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
478 async function checkNewAccountAbuseForModerators (options: CheckerBaseParams & {
480 checkType: CheckerType
482 const { displayName } = options
483 const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
485 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
486 if (checkType === 'presence') {
487 expect(notification).to.not.be.undefined
488 expect(notification.type).to.equal(notificationType)
490 expect(notification.abuse.id).to.be.a('number')
491 expect(notification.abuse.account.displayName).to.equal(displayName)
493 expect(notification).to.satisfy((n: UserNotification) => {
494 return n === undefined || n.abuse === undefined || n.abuse.account.displayName !== displayName
499 function emailNotificationFinder (email: object) {
500 const text = email['text']
501 return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1
504 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
507 async function checkVideoAutoBlacklistForModerators (options: CheckerBaseParams & {
510 checkType: CheckerType
512 const { shortUUID, videoName } = options
513 const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS
515 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
516 if (checkType === 'presence') {
517 expect(notification).to.not.be.undefined
518 expect(notification.type).to.equal(notificationType)
520 expect(notification.videoBlacklist.video.id).to.be.a('number')
521 checkVideo(notification.videoBlacklist.video, videoName, shortUUID)
523 expect(notification).to.satisfy((n: UserNotification) => {
524 return n === undefined || n.video === undefined || n.video.shortUUID !== shortUUID
529 function emailNotificationFinder (email: object) {
530 const text = email['text']
531 return text.indexOf(shortUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1
534 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
537 async function checkNewBlacklistOnMyVideo (options: CheckerBaseParams & {
540 blacklistType: 'blacklist' | 'unblacklist'
542 const { videoName, shortUUID, blacklistType } = options
543 const notificationType = blacklistType === 'blacklist'
544 ? UserNotificationType.BLACKLIST_ON_MY_VIDEO
545 : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO
547 function notificationChecker (notification: UserNotification) {
548 expect(notification).to.not.be.undefined
549 expect(notification.type).to.equal(notificationType)
551 const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video
553 checkVideo(video, videoName, shortUUID)
556 function emailNotificationFinder (email: object) {
557 const text = email['text']
558 const blacklistText = blacklistType === 'blacklist'
562 return text.includes(shortUUID) && text.includes(blacklistText)
565 await checkNotification({ ...options, notificationChecker, emailNotificationFinder, checkType: 'presence' })
568 async function checkNewPeerTubeVersion (options: CheckerBaseParams & {
569 latestVersion: string
570 checkType: CheckerType
572 const { latestVersion } = options
573 const notificationType = UserNotificationType.NEW_PEERTUBE_VERSION
575 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
576 if (checkType === 'presence') {
577 expect(notification).to.not.be.undefined
578 expect(notification.type).to.equal(notificationType)
580 expect(notification.peertube).to.exist
581 expect(notification.peertube.latestVersion).to.equal(latestVersion)
583 expect(notification).to.satisfy((n: UserNotification) => {
584 return n === undefined || n.peertube === undefined || n.peertube.latestVersion !== latestVersion
589 function emailNotificationFinder (email: object) {
590 const text = email['text']
592 return text.includes(latestVersion)
595 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
598 async function checkNewPluginVersion (options: CheckerBaseParams & {
599 pluginType: PluginType
601 checkType: CheckerType
603 const { pluginName, pluginType } = options
604 const notificationType = UserNotificationType.NEW_PLUGIN_VERSION
606 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
607 if (checkType === 'presence') {
608 expect(notification).to.not.be.undefined
609 expect(notification.type).to.equal(notificationType)
611 expect(notification.plugin.name).to.equal(pluginName)
612 expect(notification.plugin.type).to.equal(pluginType)
614 expect(notification).to.satisfy((n: UserNotification) => {
615 return n === undefined || n.plugin === undefined || n.plugin.name !== pluginName
620 function emailNotificationFinder (email: object) {
621 const text = email['text']
623 return text.includes(pluginName)
626 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
629 async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: any = {}) {
630 const userNotifications: UserNotification[] = []
631 const adminNotifications: UserNotification[] = []
632 const adminNotificationsServer2: UserNotification[] = []
633 const emails: object[] = []
635 const port = await MockSmtpServer.Instance.collectEmails(emails)
637 const overrideConfig = {
639 hostname: 'localhost',
646 const servers = await createMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg))
648 await setAccessTokensToServers(servers)
650 if (serversCount > 1) {
651 await doubleFollow(servers[0], servers[1])
654 const user = { username: 'user_1', password: 'super password' }
655 await servers[0].users.create({ ...user, videoQuota: 10 * 1000 * 1000 })
656 const userAccessToken = await servers[0].login.getAccessToken(user)
658 await servers[0].notifications.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() })
659 await servers[0].notifications.updateMySettings({ settings: getAllNotificationsSettings() })
661 if (serversCount > 1) {
662 await servers[1].notifications.updateMySettings({ settings: getAllNotificationsSettings() })
666 const socket = servers[0].socketIO.getUserNotificationSocket({ token: userAccessToken })
667 socket.on('new-notification', n => userNotifications.push(n))
670 const socket = servers[0].socketIO.getUserNotificationSocket()
671 socket.on('new-notification', n => adminNotifications.push(n))
674 if (serversCount > 1) {
675 const socket = servers[1].socketIO.getUserNotificationSocket()
676 socket.on('new-notification', n => adminNotificationsServer2.push(n))
679 const { videoChannels } = await servers[0].users.getMyInfo()
680 const channelId = videoChannels[0].id
685 adminNotificationsServer2,
693 // ---------------------------------------------------------------------------
696 getAllNotificationsSettings,
700 checkMyVideoImportIsFinished,
702 checkAutoInstanceFollowing,
703 checkVideoIsPublished,
704 checkNewVideoFromSubscription,
706 checkNewCommentOnMyVideo,
707 checkNewBlacklistOnMyVideo,
709 checkNewVideoAbuseForModerators,
710 checkVideoAutoBlacklistForModerators,
711 checkNewAbuseMessage,
712 checkAbuseStateChange,
713 checkNewInstanceFollower,
714 prepareNotificationsTest,
715 checkNewCommentAbuseForModerators,
716 checkNewAccountAbuseForModerators,
717 checkNewPeerTubeVersion,
718 checkNewPluginVersion
721 // ---------------------------------------------------------------------------
723 async function checkNotification (options: CheckerBaseParams & {
724 notificationChecker: (notification: UserNotification, checkType: CheckerType) => void
725 emailNotificationFinder: (email: object) => boolean
726 checkType: CheckerType
728 const { server, token, checkType, notificationChecker, emailNotificationFinder, socketNotifications, emails } = options
730 const check = options.check || { web: true, mail: true }
733 const notification = await server.notifications.getLatest({ token: token })
735 if (notification || checkType !== 'absence') {
736 notificationChecker(notification, checkType)
739 const socketNotification = socketNotifications.find(n => {
741 notificationChecker(n, 'presence')
748 if (checkType === 'presence') {
749 const obj = inspect(socketNotifications, { depth: 5 })
750 expect(socketNotification, 'The socket notification is absent when it should be present. ' + obj).to.not.be.undefined
752 const obj = inspect(socketNotification, { depth: 5 })
753 expect(socketNotification, 'The socket notification is present when it should not be present. ' + obj).to.be.undefined
762 .find(e => emailNotificationFinder(e))
764 if (checkType === 'presence') {
765 const texts = emails.map(e => e.text)
766 expect(email, 'The email is absent when is should be present. ' + inspect(texts)).to.not.be.undefined
768 expect(email, 'The email is present when is should not be present. ' + inspect(email)).to.be.undefined
773 function checkVideo (video: any, videoName?: string, shortUUID?: string) {
775 expect(video.name).to.be.a('string')
776 expect(video.name).to.not.be.empty
777 expect(video.name).to.equal(videoName)
781 expect(video.shortUUID).to.be.a('string')
782 expect(video.shortUUID).to.not.be.empty
783 expect(video.shortUUID).to.equal(shortUUID)
786 expect(video.id).to.be.a('number')
789 function checkActor (actor: any) {
790 expect(actor.displayName).to.be.a('string')
791 expect(actor.displayName).to.not.be.empty
792 expect(actor.host).to.not.be.undefined
795 function checkComment (comment: any, commentId: number, threadId: number) {
796 expect(comment.id).to.equal(commentId)
797 expect(comment.threadId).to.equal(threadId)