]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/client.ts
Inject server config in HTML
[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'
5import * as request from 'supertest'
aea0b0e7 6import { Account, HTMLServerConfig, ServerConfig, VideoPlaylistPrivacy } from '@shared/models'
0e1dc3e7 7import {
39433fa5 8 addVideoInPlaylist,
7c3b7976 9 cleanupTests,
39433fa5 10 createVideoPlaylist,
a59f210f
C
11 doubleFollow,
12 flushAndRunMultipleServers,
39433fa5 13 getAccount,
aea0b0e7 14 getConfig,
590fb506
C
15 getCustomConfig,
16 getVideosList,
590fb506 17 makeHTMLRequest,
590fb506 18 ServerInfo,
a59f210f 19 setAccessTokensToServers,
39433fa5 20 setDefaultVideoChannel,
590fb506
C
21 updateCustomConfig,
22 updateCustomSubConfig,
39433fa5 23 updateMyUser,
e5024f51 24 updateVideoChannel,
a59f210f
C
25 uploadVideo,
26 waitJobs
94565d52 27} from '../../shared/extra-utils'
2d53be02 28import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
aea0b0e7 29import { omit } from 'lodash'
590fb506
C
30
31const expect = chai.expect
5bcfd029 32
aea0b0e7 33function checkIndexTags (html: string, title: string, description: string, css: string, config: ServerConfig) {
5bcfd029
C
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>')
aea0b0e7
C
37
38 const htmlConfig: HTMLServerConfig = omit(config, 'signup')
39 expect(html).to.contain(`<script type="application/javascript">window.PeerTubeServerConfig = '${JSON.stringify(htmlConfig)}'</script>`)
5bcfd029 40}
0e1dc3e7
C
41
42describe('Test a client controllers', function () {
e5024f51 43 let servers: ServerInfo[] = []
39433fa5
C
44 let account: Account
45
46 const videoName = 'my super name for server 1'
a073c912
RK
47 const videoDescription = 'my<br> super __description__ for *server* 1<p></p>'
48 const videoDescriptionPlainText = 'my super description for server 1'
39433fa5
C
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'
0e1dc3e7
C
55
56 before(async function () {
57 this.timeout(120000)
58
e5024f51 59 servers = await flushAndRunMultipleServers(2)
e5024f51
TC
60
61 await setAccessTokensToServers(servers)
62
e5024f51
TC
63 await doubleFollow(servers[0], servers[1])
64
a59f210f 65 await setDefaultVideoChannel(servers)
0e1dc3e7 66
a59f210f 67 await updateVideoChannel(servers[0].url, servers[0].accessToken, servers[0].videoChannel.name, { description: channelDescription })
8d987ec6 68
39433fa5 69 // Video
8d987ec6 70
39433fa5 71 const videoAttributes = { name: videoName, description: videoDescription }
a59f210f 72 await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
0e1dc3e7 73
a59f210f 74 const resVideosRequest = await getVideosList(servers[0].url)
8d987ec6 75 const videos = resVideosRequest.body.data
0e1dc3e7
C
76 expect(videos.length).to.equal(1)
77
a59f210f 78 servers[0].video = videos[0]
8d987ec6
K
79
80 // Playlist
81
82 const playlistAttrs = {
39433fa5
C
83 displayName: playlistName,
84 description: playlistDescription,
85 privacy: VideoPlaylistPrivacy.PUBLIC,
a59f210f 86 videoChannelId: servers[0].videoChannel.id
8d987ec6
K
87 }
88
a59f210f 89 const resVideoPlaylistRequest = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
8d987ec6 90
39433fa5
C
91 const playlist = resVideoPlaylistRequest.body.videoPlaylist
92 const playlistId = playlist.id
93 playlistUUID = playlist.uuid
8d987ec6
K
94
95 await addVideoInPlaylist({
a59f210f
C
96 url: servers[0].url,
97 token: servers[0].accessToken,
39433fa5 98 playlistId,
a59f210f 99 elementAttrs: { videoId: servers[0].video.id }
8d987ec6
K
100 })
101
102 // Account
103
a59f210f 104 await updateMyUser({ url: servers[0].url, accessToken: servers[0].accessToken, description: 'my account description' })
8d987ec6 105
a59f210f 106 const resAccountRequest = await getAccount(servers[0].url, `${servers[0].user.username}@${servers[0].host}`)
39433fa5 107 account = resAccountRequest.body
a59f210f
C
108
109 await waitJobs(servers)
0e1dc3e7
C
110 })
111
6fad8e51
C
112 describe('oEmbed', function () {
113 it('Should have valid oEmbed discovery tags for videos', async function () {
a59f210f
C
114 const path = '/videos/watch/' + servers[0].video.uuid
115 const res = await request(servers[0].url)
6fad8e51
C
116 .get(path)
117 .set('Accept', 'text/html')
2d53be02 118 .expect(HttpStatusCode.OK_200)
0e1dc3e7 119
a59f210f 120 const port = servers[0].port
0e1dc3e7 121
6fad8e51 122 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
a59f210f
C
123 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2F${servers[0].video.uuid}" ` +
124 `title="${servers[0].video.name}" />`
8d987ec6 125
6fad8e51
C
126 expect(res.text).to.contain(expectedLink)
127 })
8d987ec6 128
6fad8e51 129 it('Should have valid oEmbed discovery tags for a playlist', async function () {
a59f210f 130 const res = await request(servers[0].url)
6fad8e51
C
131 .get('/videos/watch/playlist/' + playlistUUID)
132 .set('Accept', 'text/html')
2d53be02 133 .expect(HttpStatusCode.OK_200)
6fad8e51 134
a59f210f 135 const port = servers[0].port
8d987ec6 136
6fad8e51
C
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}" />`
8d987ec6 140
6fad8e51
C
141 expect(res.text).to.contain(expectedLink)
142 })
8d987ec6
K
143 })
144
6fad8e51 145 describe('Open Graph', function () {
8d987ec6 146
6fad8e51 147 it('Should have valid Open Graph tags on the account page', async function () {
a59f210f
C
148 const res = await request(servers[0].url)
149 .get('/accounts/' + servers[0].user.username)
6fad8e51 150 .set('Accept', 'text/html')
2d53be02 151 .expect(HttpStatusCode.OK_200)
0e1dc3e7 152
6fad8e51
C
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" />')
a59f210f 156 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].user.username}" />`)
6fad8e51 157 })
d8755eed 158
6fad8e51 159 it('Should have valid Open Graph tags on the channel page', async function () {
a59f210f
C
160 const res = await request(servers[0].url)
161 .get('/video-channels/' + servers[0].videoChannel.name)
6fad8e51 162 .set('Accept', 'text/html')
2d53be02 163 .expect(HttpStatusCode.OK_200)
f4659d73 164
a59f210f 165 expect(res.text).to.contain(`<meta property="og:title" content="${servers[0].videoChannel.displayName}" />`)
6fad8e51
C
166 expect(res.text).to.contain(`<meta property="og:description" content="${channelDescription}" />`)
167 expect(res.text).to.contain('<meta property="og:type" content="website" />')
a59f210f 168 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`)
6fad8e51 169 })
d8755eed 170
6fad8e51 171 it('Should have valid Open Graph tags on the watch page with video id', async function () {
a59f210f
C
172 const res = await request(servers[0].url)
173 .get('/videos/watch/' + servers[0].video.id)
6fad8e51 174 .set('Accept', 'text/html')
2d53be02 175 .expect(HttpStatusCode.OK_200)
d8755eed 176
6fad8e51 177 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
a073c912 178 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
6fad8e51 179 expect(res.text).to.contain('<meta property="og:type" content="video" />')
a59f210f 180 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
6fad8e51 181 })
8be1afa1 182
6fad8e51 183 it('Should have valid Open Graph tags on the watch page with video uuid', async function () {
a59f210f
C
184 const res = await request(servers[0].url)
185 .get('/videos/watch/' + servers[0].video.uuid)
6fad8e51 186 .set('Accept', 'text/html')
2d53be02 187 .expect(HttpStatusCode.OK_200)
8d987ec6 188
6fad8e51 189 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
a073c912 190 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
6fad8e51 191 expect(res.text).to.contain('<meta property="og:type" content="video" />')
a59f210f 192 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
6fad8e51 193 })
8d987ec6 194
6fad8e51 195 it('Should have valid Open Graph tags on the watch playlist page', async function () {
a59f210f 196 const res = await request(servers[0].url)
6fad8e51
C
197 .get('/videos/watch/playlist/' + playlistUUID)
198 .set('Accept', 'text/html')
2d53be02 199 .expect(HttpStatusCode.OK_200)
6fad8e51
C
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" />')
a59f210f 204 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/playlist/${playlistUUID}" />`)
6fad8e51 205 })
8d987ec6
K
206 })
207
6fad8e51 208 describe('Twitter card', async function () {
8d987ec6 209
6fad8e51 210 it('Should have valid twitter card on the watch video page', async function () {
a59f210f
C
211 const res = await request(servers[0].url)
212 .get('/videos/watch/' + servers[0].video.uuid)
6fad8e51 213 .set('Accept', 'text/html')
2d53be02 214 .expect(HttpStatusCode.OK_200)
8d987ec6 215
6fad8e51
C
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}" />`)
a073c912 219 expect(res.text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`)
6fad8e51 220 })
8d987ec6 221
6fad8e51 222 it('Should have valid twitter card on the watch playlist page', async function () {
a59f210f 223 const res = await request(servers[0].url)
6fad8e51
C
224 .get('/videos/watch/playlist/' + playlistUUID)
225 .set('Accept', 'text/html')
2d53be02 226 .expect(HttpStatusCode.OK_200)
8be1afa1 227
6fad8e51
C
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 })
8be1afa1 233
6fad8e51 234 it('Should have valid twitter card on the account page', async function () {
a59f210f 235 const res = await request(servers[0].url)
6fad8e51
C
236 .get('/accounts/' + account.name)
237 .set('Accept', 'text/html')
2d53be02 238 .expect(HttpStatusCode.OK_200)
8be1afa1 239
6fad8e51
C
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 })
8d987ec6 245
6fad8e51 246 it('Should have valid twitter card on the channel page', async function () {
a59f210f
C
247 const res = await request(servers[0].url)
248 .get('/video-channels/' + servers[0].videoChannel.name)
6fad8e51 249 .set('Accept', 'text/html')
2d53be02 250 .expect(HttpStatusCode.OK_200)
8d987ec6 251
6fad8e51
C
252 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
253 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
a59f210f 254 expect(res.text).to.contain(`<meta property="twitter:title" content="${servers[0].videoChannel.displayName}" />`)
6fad8e51
C
255 expect(res.text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`)
256 })
8d987ec6 257
6fad8e51 258 it('Should have valid twitter card if Twitter is whitelisted', async function () {
a59f210f 259 const res1 = await getCustomConfig(servers[0].url, servers[0].accessToken)
6fad8e51
C
260 const config = res1.body
261 config.services.twitter = {
262 username: '@Kuja',
263 whitelisted: true
264 }
a59f210f 265 await updateCustomConfig(servers[0].url, servers[0].accessToken, config)
8d987ec6 266
a59f210f
C
267 const resVideoRequest = await request(servers[0].url)
268 .get('/videos/watch/' + servers[0].video.uuid)
6fad8e51 269 .set('Accept', 'text/html')
2d53be02 270 .expect(HttpStatusCode.OK_200)
8d987ec6 271
6fad8e51
C
272 expect(resVideoRequest.text).to.contain('<meta property="twitter:card" content="player" />')
273 expect(resVideoRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
8d987ec6 274
a59f210f 275 const resVideoPlaylistRequest = await request(servers[0].url)
6fad8e51
C
276 .get('/videos/watch/playlist/' + playlistUUID)
277 .set('Accept', 'text/html')
2d53be02 278 .expect(HttpStatusCode.OK_200)
8be1afa1 279
6fad8e51
C
280 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:card" content="player" />')
281 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
5bcfd029 282
a59f210f 283 const resAccountRequest = await request(servers[0].url)
6fad8e51
C
284 .get('/accounts/' + account.name)
285 .set('Accept', 'text/html')
2d53be02 286 .expect(HttpStatusCode.OK_200)
6fad8e51
C
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
a59f210f
C
291 const resChannelRequest = await request(servers[0].url)
292 .get('/video-channels/' + servers[0].videoChannel.name)
6fad8e51 293 .set('Accept', 'text/html')
2d53be02 294 .expect(HttpStatusCode.OK_200)
6fad8e51
C
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 })
5bcfd029
C
299 })
300
6fad8e51
C
301 describe('Index HTML', function () {
302
303 it('Should have valid index html tags (title, description...)', async function () {
aea0b0e7 304 const resConfig = await getConfig(servers[0].url)
a59f210f 305 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
6fad8e51
C
306
307 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.'
aea0b0e7 308 checkIndexTags(res.text, 'PeerTube', description, '', resConfig.body)
590fb506 309 })
5bcfd029 310
6fad8e51 311 it('Should update the customized configuration and have the correct index html tags', async function () {
a59f210f 312 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
6fad8e51
C
313 instance: {
314 name: 'PeerTube updated',
315 shortDescription: 'my short description',
316 description: 'my super description',
317 terms: 'my super terms',
6fad8e51 318 defaultNSFWPolicy: 'blur',
3da68f0a 319 defaultClientRoute: '/videos/recently-added',
6fad8e51
C
320 customizations: {
321 javascript: 'alert("coucou")',
322 css: 'body { background-color: red; }'
323 }
324 }
325 })
5bcfd029 326
aea0b0e7 327 const resConfig = await getConfig(servers[0].url)
a59f210f 328 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
6fad8e51 329
aea0b0e7 330 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
6fad8e51 331 })
5bcfd029 332
6fad8e51 333 it('Should have valid index html updated tags (title, description...)', async function () {
aea0b0e7 334 const resConfig = await getConfig(servers[0].url)
a59f210f 335 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
5bcfd029 336
aea0b0e7 337 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
6fad8e51 338 })
e5024f51
TC
339
340 it('Should use the original video URL for the canonical tag', async function () {
a59f210f
C
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}" />`)
e5024f51 358 })
5bcfd029
C
359 })
360
aea0b0e7
C
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
7c3b7976 371 after(async function () {
a59f210f 372 await cleanupTests(servers)
0e1dc3e7
C
373 })
374})