]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/client.ts
Merge branch 'release/3.2.0' into develop
[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 res = await request(servers[0].url)
149 .get('/accounts/' + servers[0].user.username)
150 .set('Accept', 'text/html')
151 .expect(HttpStatusCode.OK_200)
152
153 expect(res.text).to.contain(`<meta property="og:title" content="${account.displayName}" />`)
154 expect(res.text).to.contain(`<meta property="og:description" content="${account.description}" />`)
155 expect(res.text).to.contain('<meta property="og:type" content="website" />')
156 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].user.username}" />`)
157 })
158
159 it('Should have valid Open Graph tags on the channel page', async function () {
160 const res = await request(servers[0].url)
161 .get('/video-channels/' + servers[0].videoChannel.name)
162 .set('Accept', 'text/html')
163 .expect(HttpStatusCode.OK_200)
164
165 expect(res.text).to.contain(`<meta property="og:title" content="${servers[0].videoChannel.displayName}" />`)
166 expect(res.text).to.contain(`<meta property="og:description" content="${channelDescription}" />`)
167 expect(res.text).to.contain('<meta property="og:type" content="website" />')
168 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`)
169 })
170
171 it('Should have valid Open Graph tags on the watch page with video id', async function () {
172 const res = await request(servers[0].url)
173 .get('/videos/watch/' + servers[0].video.id)
174 .set('Accept', 'text/html')
175 .expect(HttpStatusCode.OK_200)
176
177 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
178 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
179 expect(res.text).to.contain('<meta property="og:type" content="video" />')
180 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
181 })
182
183 it('Should have valid Open Graph tags on the watch page with video uuid', async function () {
184 const res = await request(servers[0].url)
185 .get('/videos/watch/' + servers[0].video.uuid)
186 .set('Accept', 'text/html')
187 .expect(HttpStatusCode.OK_200)
188
189 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
190 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
191 expect(res.text).to.contain('<meta property="og:type" content="video" />')
192 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
193 })
194
195 it('Should have valid Open Graph tags on the watch playlist page', async function () {
196 const res = await request(servers[0].url)
197 .get('/videos/watch/playlist/' + playlistUUID)
198 .set('Accept', 'text/html')
199 .expect(HttpStatusCode.OK_200)
200
201 expect(res.text).to.contain(`<meta property="og:title" content="${playlistName}" />`)
202 expect(res.text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`)
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/playlist/${playlistUUID}" />`)
205 })
206 })
207
208 describe('Twitter card', async function () {
209
210 it('Should have valid twitter card on the watch video page', async function () {
211 const res = await request(servers[0].url)
212 .get('/videos/watch/' + servers[0].video.uuid)
213 .set('Accept', 'text/html')
214 .expect(HttpStatusCode.OK_200)
215
216 expect(res.text).to.contain('<meta property="twitter:card" content="summary_large_image" />')
217 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
218 expect(res.text).to.contain(`<meta property="twitter:title" content="${videoName}" />`)
219 expect(res.text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`)
220 })
221
222 it('Should have valid twitter card on the watch playlist page', async function () {
223 const res = await request(servers[0].url)
224 .get('/videos/watch/playlist/' + playlistUUID)
225 .set('Accept', 'text/html')
226 .expect(HttpStatusCode.OK_200)
227
228 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
229 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
230 expect(res.text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`)
231 expect(res.text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`)
232 })
233
234 it('Should have valid twitter card on the account page', async function () {
235 const res = await request(servers[0].url)
236 .get('/accounts/' + account.name)
237 .set('Accept', 'text/html')
238 .expect(HttpStatusCode.OK_200)
239
240 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
241 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
242 expect(res.text).to.contain(`<meta property="twitter:title" content="${account.name}" />`)
243 expect(res.text).to.contain(`<meta property="twitter:description" content="${account.description}" />`)
244 })
245
246 it('Should have valid twitter card on the channel page', async function () {
247 const res = await request(servers[0].url)
248 .get('/video-channels/' + servers[0].videoChannel.name)
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="${servers[0].videoChannel.displayName}" />`)
255 expect(res.text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`)
256 })
257
258 it('Should have valid twitter card if Twitter is whitelisted', async function () {
259 const res1 = await getCustomConfig(servers[0].url, servers[0].accessToken)
260 const config = res1.body
261 config.services.twitter = {
262 username: '@Kuja',
263 whitelisted: true
264 }
265 await updateCustomConfig(servers[0].url, servers[0].accessToken, config)
266
267 const resVideoRequest = await request(servers[0].url)
268 .get('/videos/watch/' + servers[0].video.uuid)
269 .set('Accept', 'text/html')
270 .expect(HttpStatusCode.OK_200)
271
272 expect(resVideoRequest.text).to.contain('<meta property="twitter:card" content="player" />')
273 expect(resVideoRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
274
275 const resVideoPlaylistRequest = await request(servers[0].url)
276 .get('/videos/watch/playlist/' + playlistUUID)
277 .set('Accept', 'text/html')
278 .expect(HttpStatusCode.OK_200)
279
280 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:card" content="player" />')
281 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
282
283 const resAccountRequest = await request(servers[0].url)
284 .get('/accounts/' + account.name)
285 .set('Accept', 'text/html')
286 .expect(HttpStatusCode.OK_200)
287
288 expect(resAccountRequest.text).to.contain('<meta property="twitter:card" content="summary" />')
289 expect(resAccountRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
290
291 const resChannelRequest = await request(servers[0].url)
292 .get('/video-channels/' + servers[0].videoChannel.name)
293 .set('Accept', 'text/html')
294 .expect(HttpStatusCode.OK_200)
295
296 expect(resChannelRequest.text).to.contain('<meta property="twitter:card" content="summary" />')
297 expect(resChannelRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
298 })
299 })
300
301 describe('Index HTML', function () {
302
303 it('Should have valid index html tags (title, description...)', async function () {
304 const resConfig = await getConfig(servers[0].url)
305 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
306
307 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.'
308 checkIndexTags(res.text, 'PeerTube', description, '', resConfig.body)
309 })
310
311 it('Should update the customized configuration and have the correct index html tags', async function () {
312 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
313 instance: {
314 name: 'PeerTube updated',
315 shortDescription: 'my short description',
316 description: 'my super description',
317 terms: 'my super terms',
318 defaultNSFWPolicy: 'blur',
319 defaultClientRoute: '/videos/recently-added',
320 customizations: {
321 javascript: 'alert("coucou")',
322 css: 'body { background-color: red; }'
323 }
324 }
325 })
326
327 const resConfig = await getConfig(servers[0].url)
328 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
329
330 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
331 })
332
333 it('Should have valid index html updated tags (title, description...)', async function () {
334 const resConfig = await getConfig(servers[0].url)
335 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
336
337 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
338 })
339
340 it('Should use the original video URL for the canonical tag', async function () {
341 const res = await makeHTMLRequest(servers[1].url, '/videos/watch/' + servers[0].video.uuid)
342 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
343 })
344
345 it('Should use the original account URL for the canonical tag', async function () {
346 const res = await makeHTMLRequest(servers[1].url, '/accounts/root@' + servers[0].host)
347 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/accounts/root" />`)
348 })
349
350 it('Should use the original channel URL for the canonical tag', async function () {
351 const res = await makeHTMLRequest(servers[1].url, '/video-channels/root_channel@' + servers[0].host)
352 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-channels/root_channel" />`)
353 })
354
355 it('Should use the original playlist URL for the canonical tag', async function () {
356 const res = await makeHTMLRequest(servers[1].url, '/videos/watch/playlist/' + playlistUUID)
357 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlistUUID}" />`)
358 })
359 })
360
361 describe('Embed HTML', function () {
362
363 it('Should have the correct embed html tags', async function () {
364 const resConfig = await getConfig(servers[0].url)
365 const res = await makeHTMLRequest(servers[0].url, servers[0].video.embedPath)
366
367 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
368 })
369 })
370
371 after(async function () {
372 await cleanupTests(servers)
373 })
374 })