1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
4 import * as chai from 'chai'
5 import * as request from 'supertest'
6 import { Account, VideoPlaylistPrivacy } from '@shared/models'
12 flushAndRunMultipleServers,
18 setAccessTokensToServers,
19 setDefaultVideoChannel,
21 updateCustomSubConfig,
26 } from '../../shared/extra-utils'
27 import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
29 const expect = chai.expect
31 function checkIndexTags (html: string, title: string, description: string, css: string) {
32 expect(html).to.contain('<title>' + title + '</title>')
33 expect(html).to.contain('<meta name="description" content="' + description + '" />')
34 expect(html).to.contain('<style class="custom-css-style">' + css + '</style>')
37 describe('Test a client controllers', function () {
38 let servers: ServerInfo[] = []
41 const videoName = 'my super name for server 1'
42 const videoDescription = 'my<br> super __description__ for *server* 1<p></p>'
43 const videoDescriptionPlainText = 'my super description for server 1'
45 const playlistName = 'super playlist name'
46 const playlistDescription = 'super playlist description'
47 let playlistUUID: string
49 const channelDescription = 'my super channel description'
51 before(async function () {
54 servers = await flushAndRunMultipleServers(2)
56 await setAccessTokensToServers(servers)
58 await doubleFollow(servers[0], servers[1])
60 await setDefaultVideoChannel(servers)
62 await updateVideoChannel(servers[0].url, servers[0].accessToken, servers[0].videoChannel.name, { description: channelDescription })
66 const videoAttributes = { name: videoName, description: videoDescription }
67 await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
69 const resVideosRequest = await getVideosList(servers[0].url)
70 const videos = resVideosRequest.body.data
71 expect(videos.length).to.equal(1)
73 servers[0].video = videos[0]
77 const playlistAttrs = {
78 displayName: playlistName,
79 description: playlistDescription,
80 privacy: VideoPlaylistPrivacy.PUBLIC,
81 videoChannelId: servers[0].videoChannel.id
84 const resVideoPlaylistRequest = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
86 const playlist = resVideoPlaylistRequest.body.videoPlaylist
87 const playlistId = playlist.id
88 playlistUUID = playlist.uuid
90 await addVideoInPlaylist({
92 token: servers[0].accessToken,
94 elementAttrs: { videoId: servers[0].video.id }
99 await updateMyUser({ url: servers[0].url, accessToken: servers[0].accessToken, description: 'my account description' })
101 const resAccountRequest = await getAccount(servers[0].url, `${servers[0].user.username}@${servers[0].host}`)
102 account = resAccountRequest.body
104 await waitJobs(servers)
107 describe('oEmbed', function () {
108 it('Should have valid oEmbed discovery tags for videos', async function () {
109 const path = '/videos/watch/' + servers[0].video.uuid
110 const res = await request(servers[0].url)
112 .set('Accept', 'text/html')
113 .expect(HttpStatusCode.OK_200)
115 const port = servers[0].port
117 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
118 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2F${servers[0].video.uuid}" ` +
119 `title="${servers[0].video.name}" />`
121 expect(res.text).to.contain(expectedLink)
124 it('Should have valid oEmbed discovery tags for a playlist', async function () {
125 const res = await request(servers[0].url)
126 .get('/videos/watch/playlist/' + playlistUUID)
127 .set('Accept', 'text/html')
128 .expect(HttpStatusCode.OK_200)
130 const port = servers[0].port
132 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
133 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2Fplaylist%2F${playlistUUID}" ` +
134 `title="${playlistName}" />`
136 expect(res.text).to.contain(expectedLink)
140 describe('Open Graph', function () {
142 it('Should have valid Open Graph tags on the account page', async function () {
143 const res = await request(servers[0].url)
144 .get('/accounts/' + servers[0].user.username)
145 .set('Accept', 'text/html')
146 .expect(HttpStatusCode.OK_200)
148 expect(res.text).to.contain(`<meta property="og:title" content="${account.displayName}" />`)
149 expect(res.text).to.contain(`<meta property="og:description" content="${account.description}" />`)
150 expect(res.text).to.contain('<meta property="og:type" content="website" />')
151 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].user.username}" />`)
154 it('Should have valid Open Graph tags on the channel page', async function () {
155 const res = await request(servers[0].url)
156 .get('/video-channels/' + servers[0].videoChannel.name)
157 .set('Accept', 'text/html')
158 .expect(HttpStatusCode.OK_200)
160 expect(res.text).to.contain(`<meta property="og:title" content="${servers[0].videoChannel.displayName}" />`)
161 expect(res.text).to.contain(`<meta property="og:description" content="${channelDescription}" />`)
162 expect(res.text).to.contain('<meta property="og:type" content="website" />')
163 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`)
166 it('Should have valid Open Graph tags on the watch page with video id', async function () {
167 const res = await request(servers[0].url)
168 .get('/videos/watch/' + servers[0].video.id)
169 .set('Accept', 'text/html')
170 .expect(HttpStatusCode.OK_200)
172 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
173 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
174 expect(res.text).to.contain('<meta property="og:type" content="video" />')
175 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
178 it('Should have valid Open Graph tags on the watch page with video uuid', async function () {
179 const res = await request(servers[0].url)
180 .get('/videos/watch/' + servers[0].video.uuid)
181 .set('Accept', 'text/html')
182 .expect(HttpStatusCode.OK_200)
184 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
185 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
186 expect(res.text).to.contain('<meta property="og:type" content="video" />')
187 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
190 it('Should have valid Open Graph tags on the watch playlist page', async function () {
191 const res = await request(servers[0].url)
192 .get('/videos/watch/playlist/' + playlistUUID)
193 .set('Accept', 'text/html')
194 .expect(HttpStatusCode.OK_200)
196 expect(res.text).to.contain(`<meta property="og:title" content="${playlistName}" />`)
197 expect(res.text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`)
198 expect(res.text).to.contain('<meta property="og:type" content="video" />')
199 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/playlist/${playlistUUID}" />`)
203 describe('Twitter card', async function () {
205 it('Should have valid twitter card on the watch video page', async function () {
206 const res = await request(servers[0].url)
207 .get('/videos/watch/' + servers[0].video.uuid)
208 .set('Accept', 'text/html')
209 .expect(HttpStatusCode.OK_200)
211 expect(res.text).to.contain('<meta property="twitter:card" content="summary_large_image" />')
212 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
213 expect(res.text).to.contain(`<meta property="twitter:title" content="${videoName}" />`)
214 expect(res.text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`)
217 it('Should have valid twitter card on the watch playlist page', async function () {
218 const res = await request(servers[0].url)
219 .get('/videos/watch/playlist/' + playlistUUID)
220 .set('Accept', 'text/html')
221 .expect(HttpStatusCode.OK_200)
223 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
224 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
225 expect(res.text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`)
226 expect(res.text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`)
229 it('Should have valid twitter card on the account page', async function () {
230 const res = await request(servers[0].url)
231 .get('/accounts/' + account.name)
232 .set('Accept', 'text/html')
233 .expect(HttpStatusCode.OK_200)
235 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
236 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
237 expect(res.text).to.contain(`<meta property="twitter:title" content="${account.name}" />`)
238 expect(res.text).to.contain(`<meta property="twitter:description" content="${account.description}" />`)
241 it('Should have valid twitter card on the channel page', async function () {
242 const res = await request(servers[0].url)
243 .get('/video-channels/' + servers[0].videoChannel.name)
244 .set('Accept', 'text/html')
245 .expect(HttpStatusCode.OK_200)
247 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
248 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
249 expect(res.text).to.contain(`<meta property="twitter:title" content="${servers[0].videoChannel.displayName}" />`)
250 expect(res.text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`)
253 it('Should have valid twitter card if Twitter is whitelisted', async function () {
254 const res1 = await getCustomConfig(servers[0].url, servers[0].accessToken)
255 const config = res1.body
256 config.services.twitter = {
260 await updateCustomConfig(servers[0].url, servers[0].accessToken, config)
262 const resVideoRequest = await request(servers[0].url)
263 .get('/videos/watch/' + servers[0].video.uuid)
264 .set('Accept', 'text/html')
265 .expect(HttpStatusCode.OK_200)
267 expect(resVideoRequest.text).to.contain('<meta property="twitter:card" content="player" />')
268 expect(resVideoRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
270 const resVideoPlaylistRequest = await request(servers[0].url)
271 .get('/videos/watch/playlist/' + playlistUUID)
272 .set('Accept', 'text/html')
273 .expect(HttpStatusCode.OK_200)
275 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:card" content="player" />')
276 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
278 const resAccountRequest = await request(servers[0].url)
279 .get('/accounts/' + account.name)
280 .set('Accept', 'text/html')
281 .expect(HttpStatusCode.OK_200)
283 expect(resAccountRequest.text).to.contain('<meta property="twitter:card" content="summary" />')
284 expect(resAccountRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
286 const resChannelRequest = await request(servers[0].url)
287 .get('/video-channels/' + servers[0].videoChannel.name)
288 .set('Accept', 'text/html')
289 .expect(HttpStatusCode.OK_200)
291 expect(resChannelRequest.text).to.contain('<meta property="twitter:card" content="summary" />')
292 expect(resChannelRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
296 describe('Index HTML', function () {
298 it('Should have valid index html tags (title, description...)', async function () {
299 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
301 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.'
302 checkIndexTags(res.text, 'PeerTube', description, '')
305 it('Should update the customized configuration and have the correct index html tags', async function () {
306 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
308 name: 'PeerTube updated',
309 shortDescription: 'my short description',
310 description: 'my super description',
311 terms: 'my super terms',
312 defaultNSFWPolicy: 'blur',
313 defaultClientRoute: '/videos/recently-added',
315 javascript: 'alert("coucou")',
316 css: 'body { background-color: red; }'
321 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
323 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }')
326 it('Should have valid index html updated tags (title, description...)', async function () {
327 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
329 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }')
332 it('Should use the original video URL for the canonical tag', async function () {
333 const res = await makeHTMLRequest(servers[1].url, '/videos/watch/' + servers[0].video.uuid)
334 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
337 it('Should use the original account URL for the canonical tag', async function () {
338 const res = await makeHTMLRequest(servers[1].url, '/accounts/root@' + servers[0].host)
339 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/accounts/root" />`)
342 it('Should use the original channel URL for the canonical tag', async function () {
343 const res = await makeHTMLRequest(servers[1].url, '/video-channels/root_channel@' + servers[0].host)
344 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-channels/root_channel" />`)
347 it('Should use the original playlist URL for the canonical tag', async function () {
348 const res = await makeHTMLRequest(servers[1].url, '/videos/watch/playlist/' + playlistUUID)
349 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlistUUID}" />`)
353 after(async function () {
354 await cleanupTests(servers)