Begin unit tests

This commit is contained in:
Chocobozzz 2017-12-22 12:10:40 +01:00
parent bf1f650817
commit d3ea897591
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
9 changed files with 252 additions and 42 deletions

View File

@ -78,9 +78,9 @@ function addVideoCommentThread (req: express.Request, res: express.Response) {
return sequelizeTypescript.transaction(async t => {
return createVideoComment({
text: videoCommentInfo.text,
inReplyToComment: null,
inReplyToCommentId: null,
video: res.locals.video,
actorId: res.locals.oauth.token.User.Account.Actor.id
accountId: res.locals.oauth.token.User.Account.id
}, t)
})
}
@ -106,9 +106,9 @@ function addVideoCommentReply (req: express.Request, res: express.Response, next
return sequelizeTypescript.transaction(async t => {
return createVideoComment({
text: videoCommentInfo.text,
inReplyToComment: res.locals.videoComment.id,
inReplyToCommentId: res.locals.videoComment.id,
video: res.locals.video,
actorId: res.locals.oauth.token.User.Account.Actor.id
accountId: res.locals.oauth.token.User.Account.id
}, t)
})
}

View File

@ -267,7 +267,7 @@ function createVideoComment (byActor: ActorModel, activity: ActivityCreate) {
originCommentId: null,
inReplyToComment: null,
videoId: video.id,
actorId: byActor.id
accountId: byAccount.id
}, { transaction: t })
}
@ -281,7 +281,7 @@ function createVideoComment (byActor: ActorModel, activity: ActivityCreate) {
originCommentId,
inReplyToCommentId: inReplyToComment.id,
videoId: inReplyToComment.videoId,
actorId: byActor.id
accountId: byAccount.id
}, { transaction: t })
})
}

View File

@ -1,19 +1,20 @@
import * as Sequelize from 'sequelize'
import { ResultList } from '../../shared/models'
import { VideoCommentThread } from '../../shared/models/videos/video-comment.model'
import { VideoCommentThreadTree } from '../../shared/models/videos/video-comment.model'
import { VideoModel } from '../models/video/video'
import { VideoCommentModel } from '../models/video/video-comment'
import { getVideoCommentActivityPubUrl } from './activitypub'
async function createVideoComment (obj: {
text: string,
inReplyToComment: number,
inReplyToCommentId: number,
video: VideoModel
actorId: number
accountId: number
}, t: Sequelize.Transaction) {
let originCommentId: number = null
if (obj.inReplyToComment) {
const repliedComment = await VideoCommentModel.loadById(obj.inReplyToComment)
if (obj.inReplyToCommentId) {
const repliedComment = await VideoCommentModel.loadById(obj.inReplyToCommentId)
if (!repliedComment) throw new Error('Unknown replied comment.')
originCommentId = repliedComment.originCommentId || repliedComment.id
@ -22,22 +23,23 @@ async function createVideoComment (obj: {
const comment = await VideoCommentModel.create({
text: obj.text,
originCommentId,
inReplyToComment: obj.inReplyToComment,
inReplyToCommentId: obj.inReplyToCommentId,
videoId: obj.video.id,
actorId: obj.actorId
}, { transaction: t })
accountId: obj.accountId,
url: 'fake url'
}, { transaction: t, validate: false })
comment.set('url', getVideoCommentActivityPubUrl(obj.video, comment))
return comment.save({ transaction: t })
}
function buildFormattedCommentTree (resultList: ResultList<VideoCommentModel>): VideoCommentThread {
function buildFormattedCommentTree (resultList: ResultList<VideoCommentModel>): VideoCommentThreadTree {
// Comments are sorted by id ASC
const comments = resultList.data
const comment = comments.shift()
const thread: VideoCommentThread = {
const thread: VideoCommentThreadTree = {
comment: comment.toFormattedJSON(),
children: []
}
@ -48,7 +50,7 @@ function buildFormattedCommentTree (resultList: ResultList<VideoCommentModel>):
while (comments.length !== 0) {
const childComment = comments.shift()
const childCommentThread: VideoCommentThread = {
const childCommentThread: VideoCommentThreadTree = {
comment: childComment.toFormattedJSON(),
children: []
}

View File

@ -4,6 +4,7 @@ import { logger } from '../../helpers'
import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc'
import { isValidVideoCommentText } from '../../helpers/custom-validators/video-comments'
import { isVideoExist } from '../../helpers/custom-validators/videos'
import { VideoModel } from '../../models/video/video'
import { VideoCommentModel } from '../../models/video/video-comment'
import { areValidationErrors } from './utils'
@ -11,7 +12,7 @@ const listVideoCommentThreadsValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking blacklistRemove parameters.', { parameters: req.params })
logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params })
if (areValidationErrors(req, res)) return
if (!await isVideoExist(req.params.videoId, res)) return
@ -25,11 +26,11 @@ const listVideoThreadCommentsValidator = [
param('threadId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid threadId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking blacklistRemove parameters.', { parameters: req.params })
logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params })
if (areValidationErrors(req, res)) return
if (!await isVideoExist(req.params.videoId, res)) return
if (!await isVideoCommentThreadExist(req.params.threadId, req.params.videoId, res)) return
if (!await isVideoCommentThreadExist(req.params.threadId, res.locals.video, res)) return
return next()
}
@ -40,7 +41,7 @@ const addVideoCommentThreadValidator = [
body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking blacklistRemove parameters.', { parameters: req.params })
logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params })
if (areValidationErrors(req, res)) return
if (!await isVideoExist(req.params.videoId, res)) return
@ -55,11 +56,11 @@ const addVideoCommentReplyValidator = [
body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking blacklistRemove parameters.', { parameters: req.params })
logger.debug('Checking addVideoCommentReply parameters.', { parameters: req.params })
if (areValidationErrors(req, res)) return
if (!await isVideoExist(req.params.videoId, res)) return
if (!await isVideoCommentExist(req.params.commentId, req.params.videoId, res)) return
if (!await isVideoCommentExist(req.params.commentId, res.locals.video, res)) return
return next()
}
@ -76,7 +77,7 @@ export {
// ---------------------------------------------------------------------------
async function isVideoCommentThreadExist (id: number, videoId: number, res: express.Response) {
async function isVideoCommentThreadExist (id: number, video: VideoModel, res: express.Response) {
const videoComment = await VideoCommentModel.loadById(id)
if (!videoComment) {
@ -87,7 +88,7 @@ async function isVideoCommentThreadExist (id: number, videoId: number, res: expr
return false
}
if (videoComment.videoId !== videoId) {
if (videoComment.videoId !== video.id) {
res.status(400)
.json({ error: 'Video comment is associated to this video.' })
.end()
@ -107,7 +108,7 @@ async function isVideoCommentThreadExist (id: number, videoId: number, res: expr
return true
}
async function isVideoCommentExist (id: number, videoId: number, res: express.Response) {
async function isVideoCommentExist (id: number, video: VideoModel, res: express.Response) {
const videoComment = await VideoCommentModel.loadById(id)
if (!videoComment) {
@ -118,7 +119,7 @@ async function isVideoCommentExist (id: number, videoId: number, res: express.Re
return false
}
if (videoComment.videoId !== videoId) {
if (videoComment.videoId !== video.id) {
res.status(400)
.json({ error: 'Video comment is associated to this video.' })
.end()

View File

@ -6,18 +6,18 @@ import {
import { VideoComment } from '../../../shared/models/videos/video-comment.model'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub'
import { CONSTRAINTS_FIELDS } from '../../initializers'
import { ActorModel } from '../activitypub/actor'
import { AccountModel } from '../account/account'
import { getSort, throwIfNotValid } from '../utils'
import { VideoModel } from './video'
enum ScopeNames {
WITH_ACTOR = 'WITH_ACTOR'
WITH_ACCOUNT = 'WITH_ACCOUNT'
}
@Scopes({
[ScopeNames.WITH_ACTOR]: {
[ScopeNames.WITH_ACCOUNT]: {
include: [
() => ActorModel
() => AccountModel
]
}
})
@ -84,17 +84,17 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
})
Video: VideoModel
@ForeignKey(() => ActorModel)
@ForeignKey(() => AccountModel)
@Column
actorId: number
accountId: number
@BelongsTo(() => ActorModel, {
@BelongsTo(() => AccountModel, {
foreignKey: {
allowNull: false
},
onDelete: 'CASCADE'
})
Actor: ActorModel
Account: AccountModel
@AfterDestroy
static sendDeleteIfOwned (instance: VideoCommentModel) {
@ -132,12 +132,13 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
limit: count,
order: [ getSort(sort) ],
where: {
videoId
videoId,
inReplyToCommentId: null
}
}
return VideoCommentModel
.scope([ ScopeNames.WITH_ACTOR ])
.scope([ ScopeNames.WITH_ACCOUNT ])
.findAndCountAll(query)
.then(({ rows, count }) => {
return { total: count, data: rows }
@ -146,7 +147,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
static listThreadCommentsForApi (videoId: number, threadId: number) {
const query = {
order: [ 'id', 'ASC' ],
order: [ [ 'id', 'ASC' ] ],
where: {
videoId,
[ Sequelize.Op.or ]: [
@ -157,7 +158,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
}
return VideoCommentModel
.scope([ ScopeNames.WITH_ACTOR ])
.scope([ ScopeNames.WITH_ACCOUNT ])
.findAndCountAll(query)
.then(({ rows, count }) => {
return { total: count, data: rows }
@ -173,7 +174,10 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
inReplyToCommentId: this.inReplyToCommentId,
videoId: this.videoId,
createdAt: this.createdAt,
updatedAt: this.updatedAt
updatedAt: this.updatedAt,
account: {
name: this.Account.name
}
} as VideoComment
}
}

View File

@ -4,3 +4,4 @@ import './video-transcoder'
import './multiple-servers'
import './follows'
import './jobs'
import './video-comments'

View File

@ -0,0 +1,135 @@
/* tslint:disable:no-unused-expression */
import * as chai from 'chai'
import 'mocha'
import { VideoComment, VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model'
import { dateIsValid, flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers, uploadVideo } from '../utils'
import { addVideoCommentReply, addVideoCommentThread, getVideoCommentThreads, getVideoThreadComments } from '../utils/video-comments'
const expect = chai.expect
describe('Test a video comments', function () {
let server: ServerInfo
let videoId
let videoUUID
let threadId
before(async function () {
this.timeout(10000)
await flushTests()
server = await runServer(1)
await setAccessTokensToServers([ server ])
const res = await uploadVideo(server.url, server.accessToken, {})
videoUUID = res.body.video.uuid
videoId = res.body.video.id
})
it('Should not have threads on this video', async function () {
const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(0)
})
it('Should create a thread in this video', async function () {
const text = 'my super first comment'
await addVideoCommentThread(server.url, server.accessToken, videoUUID, text)
})
it('Should list threads of this video', async function () {
const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(1)
const comment: VideoComment = res.body.data[0]
expect(comment.inReplyToCommentId).to.be.null
expect(comment.text).equal('my super first comment')
expect(comment.videoId).to.equal(videoId)
expect(comment.id).to.equal(comment.threadId)
expect(comment.account.name).to.equal('root')
expect(dateIsValid(comment.createdAt as string)).to.be.true
expect(dateIsValid(comment.updatedAt as string)).to.be.true
threadId = comment.threadId
})
it('Should get all the thread created', async function () {
const res = await getVideoThreadComments(server.url, videoUUID, threadId)
const rootComment = res.body.comment
expect(rootComment.inReplyToCommentId).to.be.null
expect(rootComment.text).equal('my super first comment')
expect(rootComment.videoId).to.equal(videoId)
expect(dateIsValid(rootComment.createdAt as string)).to.be.true
expect(dateIsValid(rootComment.updatedAt as string)).to.be.true
})
it('Should create multiple replies in this thread', async function () {
const text1 = 'my super answer to thread 1'
const childCommentRes = await addVideoCommentReply(server.url, server.accessToken, videoId, threadId, text1)
const childCommentId = childCommentRes.body.comment.id
const text2 = 'my super answer to answer of thread 1'
await addVideoCommentReply(server.url, server.accessToken, videoId, childCommentId, text2)
const text3 = 'my second answer to thread 1'
await addVideoCommentReply(server.url, server.accessToken, videoId, threadId, text3)
})
it('Should get correctly the replies', async function () {
const res = await getVideoThreadComments(server.url, videoUUID, threadId)
const tree: VideoCommentThreadTree = res.body
expect(tree.comment.text).equal('my super first comment')
expect(tree.children).to.have.lengthOf(2)
const firstChild = tree.children[0]
expect(firstChild.comment.text).to.equal('my super answer to thread 1')
expect(firstChild.children).to.have.lengthOf(1)
const childOfFirstChild = firstChild.children[0]
expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1')
expect(childOfFirstChild.children).to.have.lengthOf(0)
const secondChild = tree.children[1]
expect(secondChild.comment.text).to.equal('my second answer to thread 1')
expect(secondChild.children).to.have.lengthOf(0)
})
it('Should create other threads', async function () {
const text1 = 'super thread 2'
await addVideoCommentThread(server.url, server.accessToken, videoUUID, text1)
const text2 = 'super thread 3'
await addVideoCommentThread(server.url, server.accessToken, videoUUID, text2)
})
it('Should list the threads', async function () {
const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5, 'createdAt')
expect(res.body.total).to.equal(3)
expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(3)
expect(res.body.data[0].text).to.equal('my super first comment')
expect(res.body.data[1].text).to.equal('super thread 2')
expect(res.body.data[2].text).to.equal('super thread 3')
})
after(async function () {
killallServers([ server ])
// Keep the logs if the test failed
if (this['ok']) {
await flushTests()
}
})
})

View File

@ -0,0 +1,64 @@
import * as request from 'supertest'
function getVideoCommentThreads (url: string, videoId: number, start: number, count: number, sort?: string) {
const path = '/api/v1/videos/' + videoId + '/comment-threads'
const req = request(url)
.get(path)
.query({ start: start })
.query({ count: count })
if (sort) req.query({ sort })
return req.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
}
function getVideoThreadComments (url: string, videoId: number, threadId: number) {
const path = '/api/v1/videos/' + videoId + '/comment-threads/' + threadId
return request(url)
.get(path)
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
}
function addVideoCommentThread (url: string, token: string, videoId: number, text: string, expectedStatus = 200) {
const path = '/api/v1/videos/' + videoId + '/comment-threads'
return request(url)
.post(path)
.send({ text })
.set('Accept', 'application/json')
.set('Authorization', 'Bearer ' + token)
.expect(expectedStatus)
}
function addVideoCommentReply (
url: string,
token: string,
videoId: number,
inReplyToCommentId: number,
text: string,
expectedStatus = 200
) {
const path = '/api/v1/videos/' + videoId + '/comments/' + inReplyToCommentId
return request(url)
.post(path)
.send({ text })
.set('Accept', 'application/json')
.set('Authorization', 'Bearer ' + token)
.expect(expectedStatus)
}
// ---------------------------------------------------------------------------
export {
getVideoCommentThreads,
getVideoThreadComments,
addVideoCommentThread,
addVideoCommentReply
}

View File

@ -7,11 +7,14 @@ export interface VideoComment {
videoId: number
createdAt: Date | string
updatedAt: Date | string
account: {
name: string
}
}
export interface VideoCommentThread {
export interface VideoCommentThreadTree {
comment: VideoComment
children: VideoCommentThread[]
children: VideoCommentThreadTree[]
}
export interface VideoCommentCreate {