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'
16 setDefaultVideoChannel,
18 updateCustomSubConfig,
23 flushAndRunMultipleServers,
24 setAccessTokensToServers
25 } from '../../shared/extra-utils'
26 import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
28 const expect = chai.expect
30 function checkIndexTags (html: string, title: string, description: string, css: string) {
31 expect(html).to.contain('<title>' + title + '</title>')
32 expect(html).to.contain('<meta name="description" content="' + description + '" />')
33 expect(html).to.contain('<style class="custom-css-style">' + css + '</style>')
36 describe('Test a client controllers', function () {
37 let servers: ServerInfo[] = []
38 let server: ServerInfo
41 let videoOriginalUrl: string
43 const videoName = 'my super name for server 1'
44 const videoDescription = 'my super description for server 1'
46 const playlistName = 'super playlist name'
47 const playlistDescription = 'super playlist description'
48 let playlistUUID: string
50 const channelDescription = 'my super channel description'
52 before(async function () {
55 servers = await flushAndRunMultipleServers(2)
56 const server = servers[0]
58 await setAccessTokensToServers(servers)
61 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' })
62 videoUUID = res.body.video.uuid
63 videoOriginalUrl = res.body.video.url
66 await doubleFollow(servers[0], servers[1])
68 await setDefaultVideoChannel([ server ])
70 await updateVideoChannel(server.url, server.accessToken, server.videoChannel.name, { description: channelDescription })
74 const videoAttributes = { name: videoName, description: videoDescription }
75 await uploadVideo(server.url, server.accessToken, videoAttributes)
77 const resVideosRequest = await getVideosList(server.url)
78 const videos = resVideosRequest.body.data
79 expect(videos.length).to.equal(1)
81 server.video = videos[0]
85 const playlistAttrs = {
86 displayName: playlistName,
87 description: playlistDescription,
88 privacy: VideoPlaylistPrivacy.PUBLIC,
89 videoChannelId: server.videoChannel.id
92 const resVideoPlaylistRequest = await createVideoPlaylist({ url: server.url, token: server.accessToken, playlistAttrs })
94 const playlist = resVideoPlaylistRequest.body.videoPlaylist
95 const playlistId = playlist.id
96 playlistUUID = playlist.uuid
98 await addVideoInPlaylist({
100 token: server.accessToken,
102 elementAttrs: { videoId: server.video.id }
107 await updateMyUser({ url: server.url, accessToken: server.accessToken, description: 'my account description' })
109 const resAccountRequest = await getAccount(server.url, `${server.user.username}@${server.host}`)
110 account = resAccountRequest.body
113 describe('oEmbed', function () {
114 it('Should have valid oEmbed discovery tags for videos', async function () {
115 const path = '/videos/watch/' + server.video.uuid
116 const res = await request(server.url)
118 .set('Accept', 'text/html')
119 .expect(HttpStatusCode.OK_200)
121 const port = server.port
123 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
124 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2F${server.video.uuid}" ` +
125 `title="${server.video.name}" />`
127 expect(res.text).to.contain(expectedLink)
130 it('Should have valid oEmbed discovery tags for a playlist', async function () {
131 const res = await request(server.url)
132 .get('/videos/watch/playlist/' + playlistUUID)
133 .set('Accept', 'text/html')
134 .expect(HttpStatusCode.OK_200)
136 const port = server.port
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}" />`
142 expect(res.text).to.contain(expectedLink)
146 describe('Open Graph', function () {
148 it('Should have valid Open Graph tags on the account page', async function () {
149 const res = await request(server.url)
150 .get('/accounts/' + server.user.username)
151 .set('Accept', 'text/html')
152 .expect(HttpStatusCode.OK_200)
154 expect(res.text).to.contain(`<meta property="og:title" content="${account.displayName}" />`)
155 expect(res.text).to.contain(`<meta property="og:description" content="${account.description}" />`)
156 expect(res.text).to.contain('<meta property="og:type" content="website" />')
157 expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/accounts/${server.user.username}" />`)
160 it('Should have valid Open Graph tags on the channel page', async function () {
161 const res = await request(server.url)
162 .get('/video-channels/' + server.videoChannel.name)
163 .set('Accept', 'text/html')
164 .expect(HttpStatusCode.OK_200)
166 expect(res.text).to.contain(`<meta property="og:title" content="${server.videoChannel.displayName}" />`)
167 expect(res.text).to.contain(`<meta property="og:description" content="${channelDescription}" />`)
168 expect(res.text).to.contain('<meta property="og:type" content="website" />')
169 expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/video-channels/${server.videoChannel.name}" />`)
172 it('Should have valid Open Graph tags on the watch page with video id', async function () {
173 const res = await request(server.url)
174 .get('/videos/watch/' + server.video.id)
175 .set('Accept', 'text/html')
176 .expect(HttpStatusCode.OK_200)
178 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
179 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescription}" />`)
180 expect(res.text).to.contain('<meta property="og:type" content="video" />')
181 expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/videos/watch/${server.video.uuid}" />`)
184 it('Should have valid Open Graph tags on the watch page with video uuid', async function () {
185 const res = await request(server.url)
186 .get('/videos/watch/' + server.video.uuid)
187 .set('Accept', 'text/html')
188 .expect(HttpStatusCode.OK_200)
190 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
191 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescription}" />`)
192 expect(res.text).to.contain('<meta property="og:type" content="video" />')
193 expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/videos/watch/${server.video.uuid}" />`)
196 it('Should have valid Open Graph tags on the watch playlist page', async function () {
197 const res = await request(server.url)
198 .get('/videos/watch/playlist/' + playlistUUID)
199 .set('Accept', 'text/html')
200 .expect(HttpStatusCode.OK_200)
202 expect(res.text).to.contain(`<meta property="og:title" content="${playlistName}" />`)
203 expect(res.text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`)
204 expect(res.text).to.contain('<meta property="og:type" content="video" />')
205 expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/videos/watch/playlist/${playlistUUID}" />`)
209 describe('Twitter card', async function () {
211 it('Should have valid twitter card on the watch video page', async function () {
212 const res = await request(server.url)
213 .get('/videos/watch/' + server.video.uuid)
214 .set('Accept', 'text/html')
215 .expect(HttpStatusCode.OK_200)
217 expect(res.text).to.contain('<meta property="twitter:card" content="summary_large_image" />')
218 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
219 expect(res.text).to.contain(`<meta property="twitter:title" content="${videoName}" />`)
220 expect(res.text).to.contain(`<meta property="twitter:description" content="${videoDescription}" />`)
223 it('Should have valid twitter card on the watch playlist page', async function () {
224 const res = await request(server.url)
225 .get('/videos/watch/playlist/' + playlistUUID)
226 .set('Accept', 'text/html')
227 .expect(HttpStatusCode.OK_200)
229 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
230 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
231 expect(res.text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`)
232 expect(res.text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`)
235 it('Should have valid twitter card on the account page', async function () {
236 const res = await request(server.url)
237 .get('/accounts/' + account.name)
238 .set('Accept', 'text/html')
239 .expect(HttpStatusCode.OK_200)
241 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
242 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
243 expect(res.text).to.contain(`<meta property="twitter:title" content="${account.name}" />`)
244 expect(res.text).to.contain(`<meta property="twitter:description" content="${account.description}" />`)
247 it('Should have valid twitter card on the channel page', async function () {
248 const res = await request(server.url)
249 .get('/video-channels/' + server.videoChannel.name)
250 .set('Accept', 'text/html')
251 .expect(HttpStatusCode.OK_200)
253 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
254 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
255 expect(res.text).to.contain(`<meta property="twitter:title" content="${server.videoChannel.displayName}" />`)
256 expect(res.text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`)
259 it('Should have valid twitter card if Twitter is whitelisted', async function () {
260 const res1 = await getCustomConfig(server.url, server.accessToken)
261 const config = res1.body
262 config.services.twitter = {
266 await updateCustomConfig(server.url, server.accessToken, config)
268 const resVideoRequest = await request(server.url)
269 .get('/videos/watch/' + server.video.uuid)
270 .set('Accept', 'text/html')
271 .expect(HttpStatusCode.OK_200)
273 expect(resVideoRequest.text).to.contain('<meta property="twitter:card" content="player" />')
274 expect(resVideoRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
276 const resVideoPlaylistRequest = await request(server.url)
277 .get('/videos/watch/playlist/' + playlistUUID)
278 .set('Accept', 'text/html')
279 .expect(HttpStatusCode.OK_200)
281 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:card" content="player" />')
282 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
284 const resAccountRequest = await request(server.url)
285 .get('/accounts/' + account.name)
286 .set('Accept', 'text/html')
287 .expect(HttpStatusCode.OK_200)
289 expect(resAccountRequest.text).to.contain('<meta property="twitter:card" content="summary" />')
290 expect(resAccountRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
292 const resChannelRequest = await request(server.url)
293 .get('/video-channels/' + server.videoChannel.name)
294 .set('Accept', 'text/html')
295 .expect(HttpStatusCode.OK_200)
297 expect(resChannelRequest.text).to.contain('<meta property="twitter:card" content="summary" />')
298 expect(resChannelRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
302 describe('Index HTML', function () {
304 it('Should have valid index html tags (title, description...)', async function () {
305 const res = await makeHTMLRequest(server.url, '/videos/trending')
307 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.'
308 checkIndexTags(res.text, 'PeerTube', description, '')
311 it('Should update the customized configuration and have the correct index html tags', async function () {
312 await updateCustomSubConfig(server.url, server.accessToken, {
314 name: 'PeerTube updated',
315 shortDescription: 'my short description',
316 description: 'my super description',
317 terms: 'my super terms',
318 defaultClientRoute: '/videos/recently-added',
319 defaultNSFWPolicy: 'blur',
321 javascript: 'alert("coucou")',
322 css: 'body { background-color: red; }'
327 const res = await makeHTMLRequest(server.url, '/videos/trending')
329 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }')
332 it('Should have valid index html updated tags (title, description...)', async function () {
333 const res = await makeHTMLRequest(server.url, '/videos/trending')
335 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }')
338 it('Should use the original video URL for the canonical tag', async function () {
339 const res = await makeHTMLRequest(servers[1].url, '/videos/watch/' + videoUUID)
340 expect(res.text).to.contain(`<link rel="canonical" href="${videoOriginalUrl}" />`)
344 after(async function () {
345 await cleanupTests([ server ])