]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/client.ts
Introduce change ownership command
[github/Chocobozzz/PeerTube.git] / server / tests / client.ts
CommitLineData
a1587156 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
0e1dc3e7
C
2
3import 'mocha'
4import * as chai from 'chai'
012580d9 5import { omit } from 'lodash'
012580d9 6import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
65e6e260 7import { Account, HTMLServerConfig, ServerConfig, VideoPlaylistCreateResult, VideoPlaylistPrivacy } from '@shared/models'
0e1dc3e7 8import {
39433fa5 9 addVideoInPlaylist,
7c3b7976 10 cleanupTests,
39433fa5 11 createVideoPlaylist,
a59f210f
C
12 doubleFollow,
13 flushAndRunMultipleServers,
590fb506 14 getVideosList,
012580d9 15 makeGetRequest,
590fb506 16 makeHTMLRequest,
590fb506 17 ServerInfo,
a59f210f 18 setAccessTokensToServers,
39433fa5 19 setDefaultVideoChannel,
39433fa5 20 updateMyUser,
e5024f51 21 updateVideoChannel,
a59f210f
C
22 uploadVideo,
23 waitJobs
94565d52 24} from '../../shared/extra-utils'
590fb506
C
25
26const expect = chai.expect
5bcfd029 27
aea0b0e7 28function checkIndexTags (html: string, title: string, description: string, css: string, config: ServerConfig) {
5bcfd029
C
29 expect(html).to.contain('<title>' + title + '</title>')
30 expect(html).to.contain('<meta name="description" content="' + description + '" />')
31 expect(html).to.contain('<style class="custom-css-style">' + css + '</style>')
aea0b0e7
C
32
33 const htmlConfig: HTMLServerConfig = omit(config, 'signup')
34 expect(html).to.contain(`<script type="application/javascript">window.PeerTubeServerConfig = '${JSON.stringify(htmlConfig)}'</script>`)
5bcfd029 35}
0e1dc3e7
C
36
37describe('Test a client controllers', function () {
e5024f51 38 let servers: ServerInfo[] = []
39433fa5
C
39 let account: Account
40
41 const videoName = 'my super name for server 1'
a073c912
RK
42 const videoDescription = 'my<br> super __description__ for *server* 1<p></p>'
43 const videoDescriptionPlainText = 'my super description for server 1'
39433fa5
C
44
45 const playlistName = 'super playlist name'
46 const playlistDescription = 'super playlist description'
d4a8e7a6 47 let playlist: VideoPlaylistCreateResult
39433fa5
C
48
49 const channelDescription = 'my super channel description'
0e1dc3e7 50
a1eda903
C
51 const watchVideoBasePaths = [ '/videos/watch/', '/w/' ]
52 const watchPlaylistBasePaths = [ '/videos/watch/playlist/', '/w/p/' ]
53
d4a8e7a6
C
54 let videoIds: (string | number)[] = []
55 let playlistIds: (string | number)[] = []
56
0e1dc3e7
C
57 before(async function () {
58 this.timeout(120000)
59
e5024f51 60 servers = await flushAndRunMultipleServers(2)
e5024f51
TC
61
62 await setAccessTokensToServers(servers)
63
e5024f51
TC
64 await doubleFollow(servers[0], servers[1])
65
a59f210f 66 await setDefaultVideoChannel(servers)
0e1dc3e7 67
a59f210f 68 await updateVideoChannel(servers[0].url, servers[0].accessToken, servers[0].videoChannel.name, { description: channelDescription })
8d987ec6 69
39433fa5 70 // Video
8d987ec6 71
39433fa5 72 const videoAttributes = { name: videoName, description: videoDescription }
a59f210f 73 await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
0e1dc3e7 74
a59f210f 75 const resVideosRequest = await getVideosList(servers[0].url)
8d987ec6 76 const videos = resVideosRequest.body.data
0e1dc3e7
C
77 expect(videos.length).to.equal(1)
78
d4a8e7a6
C
79 const video = videos[0]
80 servers[0].video = video
81 videoIds = [ video.id, video.uuid, video.shortUUID ]
8d987ec6
K
82
83 // Playlist
84
85 const playlistAttrs = {
39433fa5
C
86 displayName: playlistName,
87 description: playlistDescription,
88 privacy: VideoPlaylistPrivacy.PUBLIC,
a59f210f 89 videoChannelId: servers[0].videoChannel.id
8d987ec6
K
90 }
91
a59f210f 92 const resVideoPlaylistRequest = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
d4a8e7a6
C
93 playlist = resVideoPlaylistRequest.body.videoPlaylist
94 playlistIds = [ playlist.id, playlist.shortUUID, playlist.uuid ]
8d987ec6
K
95
96 await addVideoInPlaylist({
a59f210f
C
97 url: servers[0].url,
98 token: servers[0].accessToken,
d4a8e7a6
C
99 playlistId: playlist.shortUUID,
100 elementAttrs: { videoId: video.id }
8d987ec6
K
101 })
102
103 // Account
104
a59f210f 105 await updateMyUser({ url: servers[0].url, accessToken: servers[0].accessToken, description: 'my account description' })
8d987ec6 106
9fff08cf 107 account = await servers[0].accountsCommand.get({ accountName: `${servers[0].user.username}@${servers[0].host}` })
a59f210f
C
108
109 await waitJobs(servers)
0e1dc3e7
C
110 })
111
6fad8e51 112 describe('oEmbed', function () {
a1eda903 113
6fad8e51 114 it('Should have valid oEmbed discovery tags for videos', async function () {
a1eda903 115 for (const basePath of watchVideoBasePaths) {
d4a8e7a6
C
116 for (const id of videoIds) {
117 const res = await makeGetRequest({
118 url: servers[0].url,
119 path: basePath + id,
120 accept: 'text/html',
121 statusCodeExpected: HttpStatusCode.OK_200
122 })
0e1dc3e7 123
d4a8e7a6 124 const port = servers[0].port
0e1dc3e7 125
d4a8e7a6
C
126 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
127 `url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2F${servers[0].video.uuid}" ` +
128 `title="${servers[0].video.name}" />`
8d987ec6 129
d4a8e7a6
C
130 expect(res.text).to.contain(expectedLink)
131 }
a1eda903 132 }
6fad8e51 133 })
8d987ec6 134
6fad8e51 135 it('Should have valid oEmbed discovery tags for a playlist', async function () {
a1eda903 136 for (const basePath of watchPlaylistBasePaths) {
d4a8e7a6
C
137 for (const id of playlistIds) {
138 const res = await makeGetRequest({
139 url: servers[0].url,
140 path: basePath + id,
141 accept: 'text/html',
142 statusCodeExpected: HttpStatusCode.OK_200
143 })
6fad8e51 144
d4a8e7a6 145 const port = servers[0].port
8d987ec6 146
d4a8e7a6
C
147 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
148 `url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2Fp%2F${playlist.uuid}" ` +
149 `title="${playlistName}" />`
8d987ec6 150
d4a8e7a6
C
151 expect(res.text).to.contain(expectedLink)
152 }
a1eda903 153 }
6fad8e51 154 })
8d987ec6
K
155 })
156
6fad8e51 157 describe('Open Graph', function () {
8d987ec6 158
012580d9
C
159 async function accountPageTest (path: string) {
160 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
161 const text = res.text
9a911038 162
012580d9
C
163 expect(text).to.contain(`<meta property="og:title" content="${account.displayName}" />`)
164 expect(text).to.contain(`<meta property="og:description" content="${account.description}" />`)
165 expect(text).to.contain('<meta property="og:type" content="website" />')
166 expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].user.username}" />`)
167 }
9a911038 168
012580d9
C
169 async function channelPageTest (path: string) {
170 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
171 const text = res.text
0e1dc3e7 172
012580d9
C
173 expect(text).to.contain(`<meta property="og:title" content="${servers[0].videoChannel.displayName}" />`)
174 expect(text).to.contain(`<meta property="og:description" content="${channelDescription}" />`)
175 expect(text).to.contain('<meta property="og:type" content="website" />')
176 expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`)
177 }
178
a1eda903
C
179 async function watchVideoPageTest (path: string) {
180 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
181 const text = res.text
182
183 expect(text).to.contain(`<meta property="og:title" content="${videoName}" />`)
184 expect(text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
185 expect(text).to.contain('<meta property="og:type" content="video" />')
186 expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/w/${servers[0].video.uuid}" />`)
187 }
188
189 async function watchPlaylistPageTest (path: string) {
190 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
191 const text = res.text
192
193 expect(text).to.contain(`<meta property="og:title" content="${playlistName}" />`)
194 expect(text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`)
195 expect(text).to.contain('<meta property="og:type" content="video" />')
d4a8e7a6 196 expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/w/p/${playlist.uuid}" />`)
a1eda903
C
197 }
198
012580d9
C
199 it('Should have valid Open Graph tags on the account page', async function () {
200 await accountPageTest('/accounts/' + servers[0].user.username)
201 await accountPageTest('/a/' + servers[0].user.username)
202 await accountPageTest('/@' + servers[0].user.username)
6fad8e51 203 })
d8755eed 204
6fad8e51 205 it('Should have valid Open Graph tags on the channel page', async function () {
012580d9
C
206 await channelPageTest('/video-channels/' + servers[0].videoChannel.name)
207 await channelPageTest('/c/' + servers[0].videoChannel.name)
208 await channelPageTest('/@' + servers[0].videoChannel.name)
6fad8e51 209 })
d8755eed 210
a1eda903 211 it('Should have valid Open Graph tags on the watch page', async function () {
d4a8e7a6
C
212 for (const path of watchVideoBasePaths) {
213 for (const id of videoIds) {
214 await watchVideoPageTest(path + id)
215 }
216 }
6fad8e51 217 })
8d987ec6 218
6fad8e51 219 it('Should have valid Open Graph tags on the watch playlist page', async function () {
d4a8e7a6
C
220 for (const path of watchPlaylistBasePaths) {
221 for (const id of playlistIds) {
222 await watchPlaylistPageTest(path + id)
223 }
224 }
6fad8e51 225 })
8d987ec6
K
226 })
227
6fad8e51 228 describe('Twitter card', async function () {
8d987ec6 229
012580d9 230 describe('Not whitelisted', function () {
8d987ec6 231
012580d9
C
232 async function accountPageTest (path: string) {
233 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
234 const text = res.text
8d987ec6 235
012580d9
C
236 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
237 expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
238 expect(text).to.contain(`<meta property="twitter:title" content="${account.name}" />`)
239 expect(text).to.contain(`<meta property="twitter:description" content="${account.description}" />`)
240 }
8be1afa1 241
012580d9
C
242 async function channelPageTest (path: string) {
243 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
244 const text = res.text
8be1afa1 245
012580d9
C
246 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
247 expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
248 expect(text).to.contain(`<meta property="twitter:title" content="${servers[0].videoChannel.displayName}" />`)
249 expect(text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`)
9a911038
K
250 }
251
a1eda903
C
252 async function watchVideoPageTest (path: string) {
253 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
254 const text = res.text
8be1afa1 255
a1eda903
C
256 expect(text).to.contain('<meta property="twitter:card" content="summary_large_image" />')
257 expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
258 expect(text).to.contain(`<meta property="twitter:title" content="${videoName}" />`)
259 expect(text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`)
260 }
261
262 async function watchPlaylistPageTest (path: string) {
263 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
264 const text = res.text
265
266 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
267 expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
268 expect(text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`)
269 expect(text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`)
270 }
271
272 it('Should have valid twitter card on the watch video page', async function () {
d4a8e7a6
C
273 for (const path of watchVideoBasePaths) {
274 for (const id of videoIds) {
275 await watchVideoPageTest(path + id)
276 }
277 }
012580d9 278 })
9a911038 279
012580d9 280 it('Should have valid twitter card on the watch playlist page', async function () {
d4a8e7a6
C
281 for (const path of watchPlaylistBasePaths) {
282 for (const id of playlistIds) {
283 await watchPlaylistPageTest(path + id)
284 }
285 }
012580d9
C
286 })
287
288 it('Should have valid twitter card on the account page', async function () {
289 await accountPageTest('/accounts/' + account.name)
290 await accountPageTest('/a/' + account.name)
291 await accountPageTest('/@' + account.name)
292 })
293
294 it('Should have valid twitter card on the channel page', async function () {
295 await channelPageTest('/video-channels/' + servers[0].videoChannel.name)
296 await channelPageTest('/c/' + servers[0].videoChannel.name)
297 await channelPageTest('/@' + servers[0].videoChannel.name)
298 })
6fad8e51 299 })
8d987ec6 300
012580d9 301 describe('Whitelisted', function () {
8d987ec6 302
012580d9 303 before(async function () {
65e6e260 304 const config = await servers[0].configCommand.getCustomConfig()
012580d9
C
305 config.services.twitter = {
306 username: '@Kuja',
307 whitelisted: true
308 }
8d987ec6 309
65e6e260 310 await servers[0].configCommand.updateCustomConfig({ newCustomConfig: config })
012580d9 311 })
8d987ec6 312
012580d9
C
313 async function accountPageTest (path: string) {
314 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
315 const text = res.text
8be1afa1 316
012580d9
C
317 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
318 expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />')
9a911038
K
319 }
320
012580d9
C
321 async function channelPageTest (path: string) {
322 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
323 const text = res.text
9a911038 324
012580d9
C
325 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
326 expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />')
327 }
9a911038 328
a1eda903
C
329 async function watchVideoPageTest (path: string) {
330 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
331 const text = res.text
6fad8e51 332
a1eda903
C
333 expect(text).to.contain('<meta property="twitter:card" content="player" />')
334 expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />')
335 }
336
337 async function watchPlaylistPageTest (path: string) {
338 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
339 const text = res.text
340
341 expect(text).to.contain('<meta property="twitter:card" content="player" />')
342 expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />')
343 }
344
345 it('Should have valid twitter card on the watch video page', async function () {
d4a8e7a6
C
346 for (const path of watchVideoBasePaths) {
347 for (const id of videoIds) {
348 await watchVideoPageTest(path + id)
349 }
350 }
012580d9 351 })
9a911038 352
012580d9 353 it('Should have valid twitter card on the watch playlist page', async function () {
d4a8e7a6
C
354 for (const path of watchPlaylistBasePaths) {
355 for (const id of playlistIds) {
356 await watchPlaylistPageTest(path + id)
357 }
358 }
012580d9
C
359 })
360
361 it('Should have valid twitter card on the account page', async function () {
362 await accountPageTest('/accounts/' + account.name)
363 await accountPageTest('/a/' + account.name)
364 await accountPageTest('/@' + account.name)
365 })
366
367 it('Should have valid twitter card on the channel page', async function () {
368 await channelPageTest('/video-channels/' + servers[0].videoChannel.name)
369 await channelPageTest('/c/' + servers[0].videoChannel.name)
370 await channelPageTest('/@' + servers[0].videoChannel.name)
371 })
6fad8e51 372 })
5bcfd029
C
373 })
374
6fad8e51
C
375 describe('Index HTML', function () {
376
377 it('Should have valid index html tags (title, description...)', async function () {
65e6e260 378 const config = await servers[0].configCommand.getConfig()
a59f210f 379 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
6fad8e51
C
380
381 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.'
65e6e260 382 checkIndexTags(res.text, 'PeerTube', description, '', config)
590fb506 383 })
5bcfd029 384
6fad8e51 385 it('Should update the customized configuration and have the correct index html tags', async function () {
65e6e260
C
386 await servers[0].configCommand.updateCustomSubConfig({
387 newConfig: {
388 instance: {
389 name: 'PeerTube updated',
390 shortDescription: 'my short description',
391 description: 'my super description',
392 terms: 'my super terms',
393 defaultNSFWPolicy: 'blur',
394 defaultClientRoute: '/videos/recently-added',
395 customizations: {
396 javascript: 'alert("coucou")',
397 css: 'body { background-color: red; }'
398 }
6fad8e51
C
399 }
400 }
401 })
5bcfd029 402
65e6e260 403 const config = await servers[0].configCommand.getConfig()
a59f210f 404 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
6fad8e51 405
65e6e260 406 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config)
6fad8e51 407 })
5bcfd029 408
6fad8e51 409 it('Should have valid index html updated tags (title, description...)', async function () {
65e6e260 410 const config = await servers[0].configCommand.getConfig()
a59f210f 411 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
5bcfd029 412
65e6e260 413 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config)
6fad8e51 414 })
e5024f51
TC
415
416 it('Should use the original video URL for the canonical tag', async function () {
a1eda903 417 for (const basePath of watchVideoBasePaths) {
d4a8e7a6
C
418 for (const id of videoIds) {
419 const res = await makeHTMLRequest(servers[1].url, basePath + id)
420 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
421 }
a1eda903 422 }
a59f210f
C
423 })
424
425 it('Should use the original account URL for the canonical tag', async function () {
65e6e260 426 const accountURLtest = res => {
9a911038
K
427 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/accounts/root" />`)
428 }
429
430 accountURLtest(await makeHTMLRequest(servers[1].url, '/accounts/root@' + servers[0].host))
431 accountURLtest(await makeHTMLRequest(servers[1].url, '/a/root@' + servers[0].host))
432 accountURLtest(await makeHTMLRequest(servers[1].url, '/@root@' + servers[0].host))
a59f210f
C
433 })
434
435 it('Should use the original channel URL for the canonical tag', async function () {
65e6e260 436 const channelURLtests = res => {
9a911038
K
437 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-channels/root_channel" />`)
438 }
439
440 channelURLtests(await makeHTMLRequest(servers[1].url, '/video-channels/root_channel@' + servers[0].host))
441 channelURLtests(await makeHTMLRequest(servers[1].url, '/c/root_channel@' + servers[0].host))
442 channelURLtests(await makeHTMLRequest(servers[1].url, '/@root_channel@' + servers[0].host))
a59f210f
C
443 })
444
445 it('Should use the original playlist URL for the canonical tag', async function () {
a1eda903 446 for (const basePath of watchPlaylistBasePaths) {
d4a8e7a6
C
447 for (const id of playlistIds) {
448 const res = await makeHTMLRequest(servers[1].url, basePath + id)
449 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlist.uuid}" />`)
450 }
a1eda903 451 }
e5024f51 452 })
5bcfd029
C
453 })
454
aea0b0e7
C
455 describe('Embed HTML', function () {
456
457 it('Should have the correct embed html tags', async function () {
65e6e260 458 const config = await servers[0].configCommand.getConfig()
aea0b0e7
C
459 const res = await makeHTMLRequest(servers[0].url, servers[0].video.embedPath)
460
65e6e260 461 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config)
aea0b0e7
C
462 })
463 })
464
7c3b7976 465 after(async function () {
a59f210f 466 await cleanupTests(servers)
0e1dc3e7
C
467 })
468})