1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
10 generateUserAccessToken,
11 getAccountPlaylistsListWithToken,
15 removeVideoFromPlaylist,
16 reorderVideosPlaylist,
18 setAccessTokensToServers,
19 setDefaultVideoChannel,
21 updateVideoPlaylistElement,
23 } from '../../../../shared/extra-utils'
25 checkBadCountPagination,
26 checkBadSortPagination,
27 checkBadStartPagination
28 } from '../../../../shared/extra-utils/requests/check-api-params'
29 import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
30 import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
31 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
33 describe('Test video playlists API validator', function () {
34 let server: ServerInfo
35 let userAccessToken: string
36 let playlistUUID: string
37 let privatePlaylistUUID: string
38 let watchLaterPlaylistId: number
40 let playlistElementId: number
42 // ---------------------------------------------------------------
44 before(async function () {
47 server = await flushAndRunServer(1)
49 await setAccessTokensToServers([ server ])
50 await setDefaultVideoChannel([ server ])
52 userAccessToken = await generateUserAccessToken(server, 'user1')
53 videoId = (await uploadVideoAndGetId({ server, videoName: 'video 1' })).id
56 const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER)
57 watchLaterPlaylistId = res.body.data[0].id
61 const res = await createVideoPlaylist({
63 token: server.accessToken,
65 displayName: 'super playlist',
66 privacy: VideoPlaylistPrivacy.PUBLIC,
67 videoChannelId: server.videoChannel.id
70 playlistUUID = res.body.videoPlaylist.uuid
74 const res = await createVideoPlaylist({
76 token: server.accessToken,
78 displayName: 'private',
79 privacy: VideoPlaylistPrivacy.PRIVATE
82 privatePlaylistUUID = res.body.videoPlaylist.uuid
86 describe('When listing playlists', function () {
87 const globalPath = '/api/v1/video-playlists'
88 const accountPath = '/api/v1/accounts/root/video-playlists'
89 const videoChannelPath = '/api/v1/video-channels/root_channel/video-playlists'
91 it('Should fail with a bad start pagination', async function () {
92 await checkBadStartPagination(server.url, globalPath, server.accessToken)
93 await checkBadStartPagination(server.url, accountPath, server.accessToken)
94 await checkBadStartPagination(server.url, videoChannelPath, server.accessToken)
97 it('Should fail with a bad count pagination', async function () {
98 await checkBadCountPagination(server.url, globalPath, server.accessToken)
99 await checkBadCountPagination(server.url, accountPath, server.accessToken)
100 await checkBadCountPagination(server.url, videoChannelPath, server.accessToken)
103 it('Should fail with an incorrect sort', async function () {
104 await checkBadSortPagination(server.url, globalPath, server.accessToken)
105 await checkBadSortPagination(server.url, accountPath, server.accessToken)
106 await checkBadSortPagination(server.url, videoChannelPath, server.accessToken)
109 it('Should fail with a bad playlist type', async function () {
110 await makeGetRequest({ url: server.url, path: globalPath, query: { playlistType: 3 } })
111 await makeGetRequest({ url: server.url, path: accountPath, query: { playlistType: 3 } })
112 await makeGetRequest({ url: server.url, path: videoChannelPath, query: { playlistType: 3 } })
115 it('Should fail with a bad account parameter', async function () {
116 const accountPath = '/api/v1/accounts/root2/video-playlists'
118 await makeGetRequest({
121 statusCodeExpected: HttpStatusCode.NOT_FOUND_404,
122 token: server.accessToken
126 it('Should fail with a bad video channel parameter', async function () {
127 const accountPath = '/api/v1/video-channels/bad_channel/video-playlists'
129 await makeGetRequest({
132 statusCodeExpected: HttpStatusCode.NOT_FOUND_404,
133 token: server.accessToken
137 it('Should success with the correct parameters', async function () {
138 await makeGetRequest({ url: server.url, path: globalPath, statusCodeExpected: HttpStatusCode.OK_200, token: server.accessToken })
139 await makeGetRequest({ url: server.url, path: accountPath, statusCodeExpected: HttpStatusCode.OK_200, token: server.accessToken })
140 await makeGetRequest({
142 path: videoChannelPath,
143 statusCodeExpected: HttpStatusCode.OK_200,
144 token: server.accessToken
149 describe('When listing videos of a playlist', function () {
150 const path = '/api/v1/video-playlists/'
152 it('Should fail with a bad start pagination', async function () {
153 await checkBadStartPagination(server.url, path + playlistUUID + '/videos', server.accessToken)
156 it('Should fail with a bad count pagination', async function () {
157 await checkBadCountPagination(server.url, path + playlistUUID + '/videos', server.accessToken)
160 it('Should success with the correct parameters', async function () {
161 await makeGetRequest({ url: server.url, path: path + playlistUUID + '/videos', statusCodeExpected: HttpStatusCode.OK_200 })
165 describe('When getting a video playlist', function () {
166 it('Should fail with a bad id or uuid', async function () {
167 await getVideoPlaylist(server.url, 'toto', HttpStatusCode.BAD_REQUEST_400)
170 it('Should fail with an unknown playlist', async function () {
171 await getVideoPlaylist(server.url, 42, HttpStatusCode.NOT_FOUND_404)
174 it('Should fail to get an unlisted playlist with the number id', async function () {
175 const res = await createVideoPlaylist({
177 token: server.accessToken,
179 displayName: 'super playlist',
180 privacy: VideoPlaylistPrivacy.UNLISTED
183 const playlist = res.body.videoPlaylist
185 await getVideoPlaylist(server.url, playlist.id, HttpStatusCode.NOT_FOUND_404)
186 await getVideoPlaylist(server.url, playlist.uuid, HttpStatusCode.OK_200)
189 it('Should succeed with the correct params', async function () {
190 await getVideoPlaylist(server.url, playlistUUID, HttpStatusCode.OK_200)
194 describe('When creating/updating a video playlist', function () {
195 const getBase = (playlistAttrs: any = {}, wrapper: any = {}) => {
196 return Object.assign({
197 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
199 token: server.accessToken,
200 playlistAttrs: Object.assign({
201 displayName: 'display name',
202 privacy: VideoPlaylistPrivacy.UNLISTED,
203 thumbnailfile: 'thumbnail.jpg',
204 videoChannelId: server.videoChannel.id
208 const getUpdate = (params: any, playlistId: number | string) => {
209 return immutableAssign(params, { playlistId: playlistId })
212 it('Should fail with an unauthenticated user', async function () {
213 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
215 await createVideoPlaylist(params)
216 await updateVideoPlaylist(getUpdate(params, playlistUUID))
219 it('Should fail without displayName', async function () {
220 const params = getBase({ displayName: undefined })
222 await createVideoPlaylist(params)
225 it('Should fail with an incorrect display name', async function () {
226 const params = getBase({ displayName: 's'.repeat(300) })
228 await createVideoPlaylist(params)
229 await updateVideoPlaylist(getUpdate(params, playlistUUID))
232 it('Should fail with an incorrect description', async function () {
233 const params = getBase({ description: 't' })
235 await createVideoPlaylist(params)
236 await updateVideoPlaylist(getUpdate(params, playlistUUID))
239 it('Should fail with an incorrect privacy', async function () {
240 const params = getBase({ privacy: 45 })
242 await createVideoPlaylist(params)
243 await updateVideoPlaylist(getUpdate(params, playlistUUID))
246 it('Should fail with an unknown video channel id', async function () {
247 const params = getBase({ videoChannelId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 })
249 await createVideoPlaylist(params)
250 await updateVideoPlaylist(getUpdate(params, playlistUUID))
253 it('Should fail with an incorrect thumbnail file', async function () {
254 const params = getBase({ thumbnailfile: 'avatar.png' })
256 await createVideoPlaylist(params)
257 await updateVideoPlaylist(getUpdate(params, playlistUUID))
260 it('Should fail to set "public" a playlist not assigned to a channel', async function () {
261 const params = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: undefined })
262 const params2 = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: 'null' })
263 const params3 = getBase({ privacy: undefined, videoChannelId: 'null' })
265 await createVideoPlaylist(params)
266 await createVideoPlaylist(params2)
267 await updateVideoPlaylist(getUpdate(params, privatePlaylistUUID))
268 await updateVideoPlaylist(getUpdate(params2, playlistUUID))
269 await updateVideoPlaylist(getUpdate(params3, playlistUUID))
272 it('Should fail with an unknown playlist to update', async function () {
273 await updateVideoPlaylist(getUpdate(
274 getBase({}, { expectedStatus: HttpStatusCode.NOT_FOUND_404 }),
279 it('Should fail to update a playlist of another user', async function () {
280 await updateVideoPlaylist(getUpdate(
281 getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }),
286 it('Should fail to update the watch later playlist', async function () {
287 await updateVideoPlaylist(getUpdate(
288 getBase({}, { expectedStatus: HttpStatusCode.BAD_REQUEST_400 }),
293 it('Should succeed with the correct params', async function () {
295 const params = getBase({}, { expectedStatus: HttpStatusCode.OK_200 })
296 await createVideoPlaylist(params)
300 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
301 await updateVideoPlaylist(getUpdate(params, playlistUUID))
306 describe('When adding an element in a playlist', function () {
307 const getBase = (elementAttrs: any = {}, wrapper: any = {}) => {
308 return Object.assign({
309 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
311 token: server.accessToken,
312 playlistId: playlistUUID,
313 elementAttrs: Object.assign({
321 it('Should fail with an unauthenticated user', async function () {
322 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
323 await addVideoInPlaylist(params)
326 it('Should fail with the playlist of another user', async function () {
327 const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
328 await addVideoInPlaylist(params)
331 it('Should fail with an unknown or incorrect playlist id', async function () {
333 const params = getBase({}, { playlistId: 'toto' })
334 await addVideoInPlaylist(params)
338 const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
339 await addVideoInPlaylist(params)
343 it('Should fail with an unknown or incorrect video id', async function () {
344 const params = getBase({ videoId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 })
345 await addVideoInPlaylist(params)
348 it('Should fail with a bad start/stop timestamp', async function () {
350 const params = getBase({ startTimestamp: -42 })
351 await addVideoInPlaylist(params)
355 const params = getBase({ stopTimestamp: 'toto' as any })
356 await addVideoInPlaylist(params)
360 it('Succeed with the correct params', async function () {
361 const params = getBase({}, { expectedStatus: HttpStatusCode.OK_200 })
362 const res = await addVideoInPlaylist(params)
363 playlistElementId = res.body.videoPlaylistElement.id
367 describe('When updating an element in a playlist', function () {
368 const getBase = (elementAttrs: any = {}, wrapper: any = {}) => {
369 return Object.assign({
371 token: server.accessToken,
372 elementAttrs: Object.assign({
377 playlistId: playlistUUID,
378 expectedStatus: HttpStatusCode.BAD_REQUEST_400
382 it('Should fail with an unauthenticated user', async function () {
383 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
384 await updateVideoPlaylistElement(params)
387 it('Should fail with the playlist of another user', async function () {
388 const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
389 await updateVideoPlaylistElement(params)
392 it('Should fail with an unknown or incorrect playlist id', async function () {
394 const params = getBase({}, { playlistId: 'toto' })
395 await updateVideoPlaylistElement(params)
399 const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
400 await updateVideoPlaylistElement(params)
404 it('Should fail with an unknown or incorrect playlistElement id', async function () {
406 const params = getBase({}, { playlistElementId: 'toto' })
407 await updateVideoPlaylistElement(params)
411 const params = getBase({}, { playlistElementId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
412 await updateVideoPlaylistElement(params)
416 it('Should fail with a bad start/stop timestamp', async function () {
418 const params = getBase({ startTimestamp: 'toto' as any })
419 await updateVideoPlaylistElement(params)
423 const params = getBase({ stopTimestamp: -42 })
424 await updateVideoPlaylistElement(params)
428 it('Should fail with an unknown element', async function () {
429 const params = getBase({}, { playlistElementId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
430 await updateVideoPlaylistElement(params)
433 it('Succeed with the correct params', async function () {
434 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
435 await updateVideoPlaylistElement(params)
439 describe('When reordering elements of a playlist', function () {
443 const getBase = (elementAttrs: any = {}, wrapper: any = {}) => {
444 return Object.assign({
446 token: server.accessToken,
447 playlistId: playlistUUID,
448 elementAttrs: Object.assign({
450 insertAfterPosition: 2,
453 expectedStatus: HttpStatusCode.BAD_REQUEST_400
457 before(async function () {
458 videoId3 = (await uploadVideoAndGetId({ server, videoName: 'video 3' })).id
459 videoId4 = (await uploadVideoAndGetId({ server, videoName: 'video 4' })).id
461 for (const id of [ videoId3, videoId4 ]) {
462 await addVideoInPlaylist({
464 token: server.accessToken,
465 playlistId: playlistUUID,
466 elementAttrs: { videoId: id }
471 it('Should fail with an unauthenticated user', async function () {
472 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
473 await reorderVideosPlaylist(params)
476 it('Should fail with the playlist of another user', async function () {
477 const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
478 await reorderVideosPlaylist(params)
481 it('Should fail with an invalid playlist', async function () {
483 const params = getBase({}, { playlistId: 'toto' })
484 await reorderVideosPlaylist(params)
488 const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
489 await reorderVideosPlaylist(params)
493 it('Should fail with an invalid start position', async function () {
495 const params = getBase({ startPosition: -1 })
496 await reorderVideosPlaylist(params)
500 const params = getBase({ startPosition: 'toto' as any })
501 await reorderVideosPlaylist(params)
505 const params = getBase({ startPosition: 42 })
506 await reorderVideosPlaylist(params)
510 it('Should fail with an invalid insert after position', async function () {
512 const params = getBase({ insertAfterPosition: 'toto' as any })
513 await reorderVideosPlaylist(params)
517 const params = getBase({ insertAfterPosition: -2 })
518 await reorderVideosPlaylist(params)
522 const params = getBase({ insertAfterPosition: 42 })
523 await reorderVideosPlaylist(params)
527 it('Should fail with an invalid reorder length', async function () {
529 const params = getBase({ reorderLength: 'toto' as any })
530 await reorderVideosPlaylist(params)
534 const params = getBase({ reorderLength: -2 })
535 await reorderVideosPlaylist(params)
539 const params = getBase({ reorderLength: 42 })
540 await reorderVideosPlaylist(params)
544 it('Succeed with the correct params', async function () {
545 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
546 await reorderVideosPlaylist(params)
550 describe('When checking exists in playlist endpoint', function () {
551 const path = '/api/v1/users/me/video-playlists/videos-exist'
553 it('Should fail with an unauthenticated user', async function () {
554 await makeGetRequest({
557 query: { videoIds: [ 1, 2 ] },
558 statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
562 it('Should fail with invalid video ids', async function () {
563 await makeGetRequest({
565 token: server.accessToken,
567 query: { videoIds: 'toto' }
570 await makeGetRequest({
572 token: server.accessToken,
574 query: { videoIds: [ 'toto' ] }
577 await makeGetRequest({
579 token: server.accessToken,
581 query: { videoIds: [ 1, 'toto' ] }
585 it('Should succeed with the correct params', async function () {
586 await makeGetRequest({
588 token: server.accessToken,
590 query: { videoIds: [ 1, 2 ] },
591 statusCodeExpected: HttpStatusCode.OK_200
596 describe('When deleting an element in a playlist', function () {
597 const getBase = (wrapper: any = {}) => {
598 return Object.assign({
600 token: server.accessToken,
602 playlistId: playlistUUID,
603 expectedStatus: HttpStatusCode.BAD_REQUEST_400
607 it('Should fail with an unauthenticated user', async function () {
608 const params = getBase({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
609 await removeVideoFromPlaylist(params)
612 it('Should fail with the playlist of another user', async function () {
613 const params = getBase({ token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
614 await removeVideoFromPlaylist(params)
617 it('Should fail with an unknown or incorrect playlist id', async function () {
619 const params = getBase({ playlistId: 'toto' })
620 await removeVideoFromPlaylist(params)
624 const params = getBase({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
625 await removeVideoFromPlaylist(params)
629 it('Should fail with an unknown or incorrect video id', async function () {
631 const params = getBase({ playlistElementId: 'toto' })
632 await removeVideoFromPlaylist(params)
636 const params = getBase({ playlistElementId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
637 await removeVideoFromPlaylist(params)
641 it('Should fail with an unknown element', async function () {
642 const params = getBase({ playlistElementId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
643 await removeVideoFromPlaylist(params)
646 it('Succeed with the correct params', async function () {
647 const params = getBase({ expectedStatus: HttpStatusCode.NO_CONTENT_204 })
648 await removeVideoFromPlaylist(params)
652 describe('When deleting a playlist', function () {
653 it('Should fail with an unknown playlist', async function () {
654 await deleteVideoPlaylist(server.url, server.accessToken, 42, HttpStatusCode.NOT_FOUND_404)
657 it('Should fail with a playlist of another user', async function () {
658 await deleteVideoPlaylist(server.url, userAccessToken, playlistUUID, HttpStatusCode.FORBIDDEN_403)
661 it('Should fail with the watch later playlist', async function () {
662 await deleteVideoPlaylist(server.url, server.accessToken, watchLaterPlaylistId, HttpStatusCode.BAD_REQUEST_400)
665 it('Should succeed with the correct params', async function () {
666 await deleteVideoPlaylist(server.url, server.accessToken, playlistUUID)
670 after(async function () {
671 await cleanupTests([ server ])