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