]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/client.ts
Cleanup
[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
C
56
57 before(async function () {
58 this.timeout(120000)
59
e5024f51 60 servers = await flushAndRunMultipleServers(2)
e5024f51
TC
61
62 await setAccessTokensToServers(servers)
63
e5024f51
TC
64 await doubleFollow(servers[0], servers[1])
65
a59f210f 66 await setDefaultVideoChannel(servers)
0e1dc3e7 67
a59f210f 68 await updateVideoChannel(servers[0].url, servers[0].accessToken, servers[0].videoChannel.name, { description: channelDescription })
8d987ec6 69
39433fa5 70 // Video
8d987ec6 71
39433fa5 72 const videoAttributes = { name: videoName, description: videoDescription }
a59f210f 73 await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
0e1dc3e7 74
a59f210f 75 const resVideosRequest = await getVideosList(servers[0].url)
8d987ec6 76 const videos = resVideosRequest.body.data
0e1dc3e7
C
77 expect(videos.length).to.equal(1)
78
a59f210f 79 servers[0].video = videos[0]
8d987ec6
K
80
81 // Playlist
82
83 const playlistAttrs = {
39433fa5
C
84 displayName: playlistName,
85 description: playlistDescription,
86 privacy: VideoPlaylistPrivacy.PUBLIC,
a59f210f 87 videoChannelId: servers[0].videoChannel.id
8d987ec6
K
88 }
89
a59f210f 90 const resVideoPlaylistRequest = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
8d987ec6 91
39433fa5
C
92 const playlist = resVideoPlaylistRequest.body.videoPlaylist
93 const playlistId = playlist.id
94 playlistUUID = playlist.uuid
8d987ec6
K
95
96 await addVideoInPlaylist({
a59f210f
C
97 url: servers[0].url,
98 token: servers[0].accessToken,
39433fa5 99 playlistId,
a59f210f 100 elementAttrs: { videoId: servers[0].video.id }
8d987ec6
K
101 })
102
103 // Account
104
a59f210f 105 await updateMyUser({ url: servers[0].url, accessToken: servers[0].accessToken, description: 'my account description' })
8d987ec6 106
a59f210f 107 const resAccountRequest = await getAccount(servers[0].url, `${servers[0].user.username}@${servers[0].host}`)
39433fa5 108 account = resAccountRequest.body
a59f210f
C
109
110 await waitJobs(servers)
0e1dc3e7
C
111 })
112
6fad8e51
C
113 describe('oEmbed', function () {
114 it('Should have valid oEmbed discovery tags for videos', async function () {
a59f210f
C
115 const path = '/videos/watch/' + servers[0].video.uuid
116 const res = await request(servers[0].url)
6fad8e51
C
117 .get(path)
118 .set('Accept', 'text/html')
2d53be02 119 .expect(HttpStatusCode.OK_200)
0e1dc3e7 120
a59f210f 121 const port = servers[0].port
0e1dc3e7 122
6fad8e51 123 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
a59f210f
C
124 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2F${servers[0].video.uuid}" ` +
125 `title="${servers[0].video.name}" />`
8d987ec6 126
6fad8e51
C
127 expect(res.text).to.contain(expectedLink)
128 })
8d987ec6 129
6fad8e51 130 it('Should have valid oEmbed discovery tags for a playlist', async function () {
a59f210f 131 const res = await request(servers[0].url)
6fad8e51
C
132 .get('/videos/watch/playlist/' + playlistUUID)
133 .set('Accept', 'text/html')
2d53be02 134 .expect(HttpStatusCode.OK_200)
6fad8e51 135
a59f210f 136 const port = servers[0].port
8d987ec6 137
6fad8e51
C
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}" />`
8d987ec6 141
6fad8e51
C
142 expect(res.text).to.contain(expectedLink)
143 })
8d987ec6
K
144 })
145
6fad8e51 146 describe('Open Graph', function () {
8d987ec6 147
012580d9
C
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
9a911038 151
012580d9
C
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 }
9a911038 157
012580d9
C
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
0e1dc3e7 161
012580d9
C
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)
6fad8e51 172 })
d8755eed 173
6fad8e51 174 it('Should have valid Open Graph tags on the channel page', async function () {
012580d9
C
175 await channelPageTest('/video-channels/' + servers[0].videoChannel.name)
176 await channelPageTest('/c/' + servers[0].videoChannel.name)
177 await channelPageTest('/@' + servers[0].videoChannel.name)
6fad8e51 178 })
d8755eed 179
6fad8e51 180 it('Should have valid Open Graph tags on the watch page with video id', async function () {
a59f210f
C
181 const res = await request(servers[0].url)
182 .get('/videos/watch/' + servers[0].video.id)
6fad8e51 183 .set('Accept', 'text/html')
2d53be02 184 .expect(HttpStatusCode.OK_200)
d8755eed 185
6fad8e51 186 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
a073c912 187 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
6fad8e51 188 expect(res.text).to.contain('<meta property="og:type" content="video" />')
a59f210f 189 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
6fad8e51 190 })
8be1afa1 191
6fad8e51 192 it('Should have valid Open Graph tags on the watch page with video uuid', async function () {
a59f210f
C
193 const res = await request(servers[0].url)
194 .get('/videos/watch/' + servers[0].video.uuid)
6fad8e51 195 .set('Accept', 'text/html')
2d53be02 196 .expect(HttpStatusCode.OK_200)
8d987ec6 197
6fad8e51 198 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
a073c912 199 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
6fad8e51 200 expect(res.text).to.contain('<meta property="og:type" content="video" />')
a59f210f 201 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
6fad8e51 202 })
8d987ec6 203
6fad8e51 204 it('Should have valid Open Graph tags on the watch playlist page', async function () {
a59f210f 205 const res = await request(servers[0].url)
6fad8e51
C
206 .get('/videos/watch/playlist/' + playlistUUID)
207 .set('Accept', 'text/html')
2d53be02 208 .expect(HttpStatusCode.OK_200)
6fad8e51
C
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" />')
a59f210f 213 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/playlist/${playlistUUID}" />`)
6fad8e51 214 })
8d987ec6
K
215 })
216
6fad8e51 217 describe('Twitter card', async function () {
8d987ec6 218
012580d9 219 describe('Not whitelisted', function () {
8d987ec6 220
012580d9
C
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
8d987ec6 224
012580d9
C
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 }
8be1afa1 230
012580d9
C
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
8be1afa1 234
012580d9
C
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}" />`)
9a911038
K
239 }
240
012580d9
C
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)
8be1afa1 246
012580d9
C
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 })
9a911038 252
012580d9
C
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)
8d987ec6 258
9a911038
K
259 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
260 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
012580d9
C
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 })
6fad8e51 276 })
8d987ec6 277
012580d9 278 describe('Whitelisted', function () {
8d987ec6 279
012580d9
C
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 }
8d987ec6 287
012580d9
C
288 await updateCustomConfig(servers[0].url, servers[0].accessToken, config)
289 })
8d987ec6 290
012580d9
C
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
8be1afa1 294
012580d9
C
295 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
296 expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />')
9a911038
K
297 }
298
012580d9
C
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
9a911038 302
012580d9
C
303 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
304 expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />')
305 }
9a911038 306
012580d9
C
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)
6fad8e51 312
012580d9 313 expect(res.text).to.contain('<meta property="twitter:card" content="player" />')
9a911038 314 expect(res.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
012580d9 315 })
9a911038 316
012580d9
C
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)
6fad8e51 322
012580d9
C
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 })
6fad8e51 338 })
5bcfd029
C
339 })
340
6fad8e51
C
341 describe('Index HTML', function () {
342
343 it('Should have valid index html tags (title, description...)', async function () {
aea0b0e7 344 const resConfig = await getConfig(servers[0].url)
a59f210f 345 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
6fad8e51
C
346
347 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.'
aea0b0e7 348 checkIndexTags(res.text, 'PeerTube', description, '', resConfig.body)
590fb506 349 })
5bcfd029 350
6fad8e51 351 it('Should update the customized configuration and have the correct index html tags', async function () {
a59f210f 352 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
6fad8e51
C
353 instance: {
354 name: 'PeerTube updated',
355 shortDescription: 'my short description',
356 description: 'my super description',
357 terms: 'my super terms',
6fad8e51 358 defaultNSFWPolicy: 'blur',
3da68f0a 359 defaultClientRoute: '/videos/recently-added',
6fad8e51
C
360 customizations: {
361 javascript: 'alert("coucou")',
362 css: 'body { background-color: red; }'
363 }
364 }
365 })
5bcfd029 366
aea0b0e7 367 const resConfig = await getConfig(servers[0].url)
a59f210f 368 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
6fad8e51 369
aea0b0e7 370 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
6fad8e51 371 })
5bcfd029 372
6fad8e51 373 it('Should have valid index html updated tags (title, description...)', async function () {
aea0b0e7 374 const resConfig = await getConfig(servers[0].url)
a59f210f 375 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
5bcfd029 376
aea0b0e7 377 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
6fad8e51 378 })
e5024f51
TC
379
380 it('Should use the original video URL for the canonical tag', async function () {
a59f210f
C
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 () {
9a911038
K
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))
a59f210f
C
393 })
394
395 it('Should use the original channel URL for the canonical tag', async function () {
9a911038
K
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))
a59f210f
C
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}" />`)
e5024f51 408 })
5bcfd029
C
409 })
410
aea0b0e7
C
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
7c3b7976 421 after(async function () {
a59f210f 422 await cleanupTests(servers)
0e1dc3e7
C
423 })
424})