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