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