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