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