diff options
author | Chocobozzz <me@florianbigard.com> | 2023-07-31 14:34:36 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2023-08-11 15:02:33 +0200 |
commit | 3a4992633ee62d5edfbb484d9c6bcb3cf158489d (patch) | |
tree | e4510b39bdac9c318fdb4b47018d08f15368b8f0 /packages/tests/src/client.ts | |
parent | 04d1da5621d25d59bd5fa1543b725c497bf5d9a8 (diff) | |
download | PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.gz PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.zst PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.zip |
Migrate server to ESM
Sorry for the very big commit that may lead to git log issues and merge
conflicts, but it's a major step forward:
* Server can be faster at startup because imports() are async and we can
easily lazy import big modules
* Angular doesn't seem to support ES import (with .js extension), so we
had to correctly organize peertube into a monorepo:
* Use yarn workspace feature
* Use typescript reference projects for dependencies
* Shared projects have been moved into "packages", each one is now a
node module (with a dedicated package.json/tsconfig.json)
* server/tools have been moved into apps/ and is now a dedicated app
bundled and published on NPM so users don't have to build peertube
cli tools manually
* server/tests have been moved into packages/ so we don't compile
them every time we want to run the server
* Use isolatedModule option:
* Had to move from const enum to const
(https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums)
* Had to explictely specify "type" imports when used in decorators
* Prefer tsx (that uses esbuild under the hood) instead of ts-node to
load typescript files (tests with mocha or scripts):
* To reduce test complexity as esbuild doesn't support decorator
metadata, we only test server files that do not import server
models
* We still build tests files into js files for a faster CI
* Remove unmaintained peertube CLI import script
* Removed some barrels to speed up execution (less imports)
Diffstat (limited to 'packages/tests/src/client.ts')
-rw-r--r-- | packages/tests/src/client.ts | 556 |
1 files changed, 556 insertions, 0 deletions
diff --git a/packages/tests/src/client.ts b/packages/tests/src/client.ts new file mode 100644 index 000000000..a16205494 --- /dev/null +++ b/packages/tests/src/client.ts | |||
@@ -0,0 +1,556 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { omit } from '@peertube/peertube-core-utils' | ||
5 | import { | ||
6 | Account, | ||
7 | HTMLServerConfig, | ||
8 | HttpStatusCode, | ||
9 | ServerConfig, | ||
10 | VideoPlaylistCreateResult, | ||
11 | VideoPlaylistPrivacy, | ||
12 | VideoPrivacy | ||
13 | } from '@peertube/peertube-models' | ||
14 | import { | ||
15 | cleanupTests, | ||
16 | createMultipleServers, | ||
17 | doubleFollow, | ||
18 | makeGetRequest, | ||
19 | makeHTMLRequest, | ||
20 | PeerTubeServer, | ||
21 | setAccessTokensToServers, | ||
22 | setDefaultVideoChannel, | ||
23 | waitJobs | ||
24 | } from '@peertube/peertube-server-commands' | ||
25 | |||
26 | function checkIndexTags (html: string, title: string, description: string, css: string, config: ServerConfig) { | ||
27 | expect(html).to.contain('<title>' + title + '</title>') | ||
28 | expect(html).to.contain('<meta name="description" content="' + description + '" />') | ||
29 | expect(html).to.contain('<style class="custom-css-style">' + css + '</style>') | ||
30 | |||
31 | const htmlConfig: HTMLServerConfig = omit(config, [ 'signup' ]) | ||
32 | const configObjectString = JSON.stringify(htmlConfig) | ||
33 | const configEscapedString = JSON.stringify(configObjectString) | ||
34 | |||
35 | expect(html).to.contain(`<script type="application/javascript">window.PeerTubeServerConfig = ${configEscapedString}</script>`) | ||
36 | } | ||
37 | |||
38 | describe('Test a client controllers', function () { | ||
39 | let servers: PeerTubeServer[] = [] | ||
40 | let account: Account | ||
41 | |||
42 | const videoName = 'my super name for server 1' | ||
43 | const videoDescription = 'my<br> super __description__ for *server* 1<p></p>' | ||
44 | const videoDescriptionPlainText = 'my super description for server 1' | ||
45 | |||
46 | const playlistName = 'super playlist name' | ||
47 | const playlistDescription = 'super playlist description' | ||
48 | let playlist: VideoPlaylistCreateResult | ||
49 | |||
50 | const channelDescription = 'my super channel description' | ||
51 | |||
52 | const watchVideoBasePaths = [ '/videos/watch/', '/w/' ] | ||
53 | const watchPlaylistBasePaths = [ '/videos/watch/playlist/', '/w/p/' ] | ||
54 | |||
55 | let videoIds: (string | number)[] = [] | ||
56 | let privateVideoId: string | ||
57 | let internalVideoId: string | ||
58 | let unlistedVideoId: string | ||
59 | let passwordProtectedVideoId: string | ||
60 | |||
61 | let playlistIds: (string | number)[] = [] | ||
62 | |||
63 | before(async function () { | ||
64 | this.timeout(120000) | ||
65 | |||
66 | servers = await createMultipleServers(2) | ||
67 | |||
68 | await setAccessTokensToServers(servers) | ||
69 | |||
70 | await doubleFollow(servers[0], servers[1]) | ||
71 | |||
72 | await setDefaultVideoChannel(servers) | ||
73 | |||
74 | await servers[0].channels.update({ | ||
75 | channelName: servers[0].store.channel.name, | ||
76 | attributes: { description: channelDescription } | ||
77 | }) | ||
78 | |||
79 | // Public video | ||
80 | |||
81 | { | ||
82 | const attributes = { name: videoName, description: videoDescription } | ||
83 | await servers[0].videos.upload({ attributes }) | ||
84 | |||
85 | const { data } = await servers[0].videos.list() | ||
86 | expect(data.length).to.equal(1) | ||
87 | |||
88 | const video = data[0] | ||
89 | servers[0].store.video = video | ||
90 | videoIds = [ video.id, video.uuid, video.shortUUID ] | ||
91 | } | ||
92 | |||
93 | { | ||
94 | ({ uuid: privateVideoId } = await servers[0].videos.quickUpload({ name: 'private', privacy: VideoPrivacy.PRIVATE })); | ||
95 | ({ uuid: unlistedVideoId } = await servers[0].videos.quickUpload({ name: 'unlisted', privacy: VideoPrivacy.UNLISTED })); | ||
96 | ({ uuid: internalVideoId } = await servers[0].videos.quickUpload({ name: 'internal', privacy: VideoPrivacy.INTERNAL })); | ||
97 | ({ uuid: passwordProtectedVideoId } = await servers[0].videos.quickUpload({ | ||
98 | name: 'password protected', | ||
99 | privacy: VideoPrivacy.PASSWORD_PROTECTED, | ||
100 | videoPasswords: [ 'password' ] | ||
101 | })) | ||
102 | } | ||
103 | |||
104 | // Playlist | ||
105 | |||
106 | { | ||
107 | const attributes = { | ||
108 | displayName: playlistName, | ||
109 | description: playlistDescription, | ||
110 | privacy: VideoPlaylistPrivacy.PUBLIC, | ||
111 | videoChannelId: servers[0].store.channel.id | ||
112 | } | ||
113 | |||
114 | playlist = await servers[0].playlists.create({ attributes }) | ||
115 | playlistIds = [ playlist.id, playlist.shortUUID, playlist.uuid ] | ||
116 | |||
117 | await servers[0].playlists.addElement({ playlistId: playlist.shortUUID, attributes: { videoId: servers[0].store.video.id } }) | ||
118 | } | ||
119 | |||
120 | // Account | ||
121 | |||
122 | { | ||
123 | await servers[0].users.updateMe({ description: 'my account description' }) | ||
124 | |||
125 | account = await servers[0].accounts.get({ accountName: `${servers[0].store.user.username}@${servers[0].host}` }) | ||
126 | } | ||
127 | |||
128 | await waitJobs(servers) | ||
129 | }) | ||
130 | |||
131 | describe('oEmbed', function () { | ||
132 | |||
133 | it('Should have valid oEmbed discovery tags for videos', async function () { | ||
134 | for (const basePath of watchVideoBasePaths) { | ||
135 | for (const id of videoIds) { | ||
136 | const res = await makeGetRequest({ | ||
137 | url: servers[0].url, | ||
138 | path: basePath + id, | ||
139 | accept: 'text/html', | ||
140 | expectedStatus: HttpStatusCode.OK_200 | ||
141 | }) | ||
142 | |||
143 | const expectedLink = `<link rel="alternate" type="application/json+oembed" href="${servers[0].url}/services/oembed?` + | ||
144 | `url=http%3A%2F%2F${servers[0].hostname}%3A${servers[0].port}%2Fw%2F${servers[0].store.video.shortUUID}" ` + | ||
145 | `title="${servers[0].store.video.name}" />` | ||
146 | |||
147 | expect(res.text).to.contain(expectedLink) | ||
148 | } | ||
149 | } | ||
150 | }) | ||
151 | |||
152 | it('Should have valid oEmbed discovery tags for a playlist', async function () { | ||
153 | for (const basePath of watchPlaylistBasePaths) { | ||
154 | for (const id of playlistIds) { | ||
155 | const res = await makeGetRequest({ | ||
156 | url: servers[0].url, | ||
157 | path: basePath + id, | ||
158 | accept: 'text/html', | ||
159 | expectedStatus: HttpStatusCode.OK_200 | ||
160 | }) | ||
161 | |||
162 | const expectedLink = `<link rel="alternate" type="application/json+oembed" href="${servers[0].url}/services/oembed?` + | ||
163 | `url=http%3A%2F%2F${servers[0].hostname}%3A${servers[0].port}%2Fw%2Fp%2F${playlist.shortUUID}" ` + | ||
164 | `title="${playlistName}" />` | ||
165 | |||
166 | expect(res.text).to.contain(expectedLink) | ||
167 | } | ||
168 | } | ||
169 | }) | ||
170 | }) | ||
171 | |||
172 | describe('Open Graph', function () { | ||
173 | |||
174 | async function accountPageTest (path: string) { | ||
175 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
176 | const text = res.text | ||
177 | |||
178 | expect(text).to.contain(`<meta property="og:title" content="${account.displayName}" />`) | ||
179 | expect(text).to.contain(`<meta property="og:description" content="${account.description}" />`) | ||
180 | expect(text).to.contain('<meta property="og:type" content="website" />') | ||
181 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/a/${servers[0].store.user.username}" />`) | ||
182 | } | ||
183 | |||
184 | async function channelPageTest (path: string) { | ||
185 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
186 | const text = res.text | ||
187 | |||
188 | expect(text).to.contain(`<meta property="og:title" content="${servers[0].store.channel.displayName}" />`) | ||
189 | expect(text).to.contain(`<meta property="og:description" content="${channelDescription}" />`) | ||
190 | expect(text).to.contain('<meta property="og:type" content="website" />') | ||
191 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/c/${servers[0].store.channel.name}" />`) | ||
192 | } | ||
193 | |||
194 | async function watchVideoPageTest (path: string) { | ||
195 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
196 | const text = res.text | ||
197 | |||
198 | expect(text).to.contain(`<meta property="og:title" content="${videoName}" />`) | ||
199 | expect(text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`) | ||
200 | expect(text).to.contain('<meta property="og:type" content="video" />') | ||
201 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/w/${servers[0].store.video.shortUUID}" />`) | ||
202 | } | ||
203 | |||
204 | async function watchPlaylistPageTest (path: string) { | ||
205 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
206 | const text = res.text | ||
207 | |||
208 | expect(text).to.contain(`<meta property="og:title" content="${playlistName}" />`) | ||
209 | expect(text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`) | ||
210 | expect(text).to.contain('<meta property="og:type" content="video" />') | ||
211 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/w/p/${playlist.shortUUID}" />`) | ||
212 | } | ||
213 | |||
214 | it('Should have valid Open Graph tags on the account page', async function () { | ||
215 | await accountPageTest('/accounts/' + servers[0].store.user.username) | ||
216 | await accountPageTest('/a/' + servers[0].store.user.username) | ||
217 | await accountPageTest('/@' + servers[0].store.user.username) | ||
218 | }) | ||
219 | |||
220 | it('Should have valid Open Graph tags on the channel page', async function () { | ||
221 | await channelPageTest('/video-channels/' + servers[0].store.channel.name) | ||
222 | await channelPageTest('/c/' + servers[0].store.channel.name) | ||
223 | await channelPageTest('/@' + servers[0].store.channel.name) | ||
224 | }) | ||
225 | |||
226 | it('Should have valid Open Graph tags on the watch page', async function () { | ||
227 | for (const path of watchVideoBasePaths) { | ||
228 | for (const id of videoIds) { | ||
229 | await watchVideoPageTest(path + id) | ||
230 | } | ||
231 | } | ||
232 | }) | ||
233 | |||
234 | it('Should have valid Open Graph tags on the watch page with thread id Angular param', async function () { | ||
235 | for (const path of watchVideoBasePaths) { | ||
236 | for (const id of videoIds) { | ||
237 | await watchVideoPageTest(path + id + ';threadId=1') | ||
238 | } | ||
239 | } | ||
240 | }) | ||
241 | |||
242 | it('Should have valid Open Graph tags on the watch playlist page', async function () { | ||
243 | for (const path of watchPlaylistBasePaths) { | ||
244 | for (const id of playlistIds) { | ||
245 | await watchPlaylistPageTest(path + id) | ||
246 | } | ||
247 | } | ||
248 | }) | ||
249 | }) | ||
250 | |||
251 | describe('Twitter card', async function () { | ||
252 | |||
253 | describe('Not whitelisted', function () { | ||
254 | |||
255 | async function accountPageTest (path: string) { | ||
256 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
257 | const text = res.text | ||
258 | |||
259 | expect(text).to.contain('<meta property="twitter:card" content="summary" />') | ||
260 | expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | ||
261 | expect(text).to.contain(`<meta property="twitter:title" content="${account.name}" />`) | ||
262 | expect(text).to.contain(`<meta property="twitter:description" content="${account.description}" />`) | ||
263 | } | ||
264 | |||
265 | async function channelPageTest (path: string) { | ||
266 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
267 | const text = res.text | ||
268 | |||
269 | expect(text).to.contain('<meta property="twitter:card" content="summary" />') | ||
270 | expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | ||
271 | expect(text).to.contain(`<meta property="twitter:title" content="${servers[0].store.channel.displayName}" />`) | ||
272 | expect(text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`) | ||
273 | } | ||
274 | |||
275 | async function watchVideoPageTest (path: string) { | ||
276 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
277 | const text = res.text | ||
278 | |||
279 | expect(text).to.contain('<meta property="twitter:card" content="summary_large_image" />') | ||
280 | expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | ||
281 | expect(text).to.contain(`<meta property="twitter:title" content="${videoName}" />`) | ||
282 | expect(text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`) | ||
283 | } | ||
284 | |||
285 | async function watchPlaylistPageTest (path: string) { | ||
286 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
287 | const text = res.text | ||
288 | |||
289 | expect(text).to.contain('<meta property="twitter:card" content="summary" />') | ||
290 | expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | ||
291 | expect(text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`) | ||
292 | expect(text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`) | ||
293 | } | ||
294 | |||
295 | it('Should have valid twitter card on the watch video page', async function () { | ||
296 | for (const path of watchVideoBasePaths) { | ||
297 | for (const id of videoIds) { | ||
298 | await watchVideoPageTest(path + id) | ||
299 | } | ||
300 | } | ||
301 | }) | ||
302 | |||
303 | it('Should have valid twitter card on the watch playlist page', async function () { | ||
304 | for (const path of watchPlaylistBasePaths) { | ||
305 | for (const id of playlistIds) { | ||
306 | await watchPlaylistPageTest(path + id) | ||
307 | } | ||
308 | } | ||
309 | }) | ||
310 | |||
311 | it('Should have valid twitter card on the account page', async function () { | ||
312 | await accountPageTest('/accounts/' + account.name) | ||
313 | await accountPageTest('/a/' + account.name) | ||
314 | await accountPageTest('/@' + account.name) | ||
315 | }) | ||
316 | |||
317 | it('Should have valid twitter card on the channel page', async function () { | ||
318 | await channelPageTest('/video-channels/' + servers[0].store.channel.name) | ||
319 | await channelPageTest('/c/' + servers[0].store.channel.name) | ||
320 | await channelPageTest('/@' + servers[0].store.channel.name) | ||
321 | }) | ||
322 | }) | ||
323 | |||
324 | describe('Whitelisted', function () { | ||
325 | |||
326 | before(async function () { | ||
327 | const config = await servers[0].config.getCustomConfig() | ||
328 | config.services.twitter = { | ||
329 | username: '@Kuja', | ||
330 | whitelisted: true | ||
331 | } | ||
332 | |||
333 | await servers[0].config.updateCustomConfig({ newCustomConfig: config }) | ||
334 | }) | ||
335 | |||
336 | async function accountPageTest (path: string) { | ||
337 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
338 | const text = res.text | ||
339 | |||
340 | expect(text).to.contain('<meta property="twitter:card" content="summary" />') | ||
341 | expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />') | ||
342 | } | ||
343 | |||
344 | async function channelPageTest (path: string) { | ||
345 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
346 | const text = res.text | ||
347 | |||
348 | expect(text).to.contain('<meta property="twitter:card" content="summary" />') | ||
349 | expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />') | ||
350 | } | ||
351 | |||
352 | async function watchVideoPageTest (path: string) { | ||
353 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
354 | const text = res.text | ||
355 | |||
356 | expect(text).to.contain('<meta property="twitter:card" content="player" />') | ||
357 | expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />') | ||
358 | } | ||
359 | |||
360 | async function watchPlaylistPageTest (path: string) { | ||
361 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) | ||
362 | const text = res.text | ||
363 | |||
364 | expect(text).to.contain('<meta property="twitter:card" content="player" />') | ||
365 | expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />') | ||
366 | } | ||
367 | |||
368 | it('Should have valid twitter card on the watch video page', async function () { | ||
369 | for (const path of watchVideoBasePaths) { | ||
370 | for (const id of videoIds) { | ||
371 | await watchVideoPageTest(path + id) | ||
372 | } | ||
373 | } | ||
374 | }) | ||
375 | |||
376 | it('Should have valid twitter card on the watch playlist page', async function () { | ||
377 | for (const path of watchPlaylistBasePaths) { | ||
378 | for (const id of playlistIds) { | ||
379 | await watchPlaylistPageTest(path + id) | ||
380 | } | ||
381 | } | ||
382 | }) | ||
383 | |||
384 | it('Should have valid twitter card on the account page', async function () { | ||
385 | await accountPageTest('/accounts/' + account.name) | ||
386 | await accountPageTest('/a/' + account.name) | ||
387 | await accountPageTest('/@' + account.name) | ||
388 | }) | ||
389 | |||
390 | it('Should have valid twitter card on the channel page', async function () { | ||
391 | await channelPageTest('/video-channels/' + servers[0].store.channel.name) | ||
392 | await channelPageTest('/c/' + servers[0].store.channel.name) | ||
393 | await channelPageTest('/@' + servers[0].store.channel.name) | ||
394 | }) | ||
395 | }) | ||
396 | }) | ||
397 | |||
398 | describe('Index HTML', function () { | ||
399 | |||
400 | it('Should have valid index html tags (title, description...)', async function () { | ||
401 | const config = await servers[0].config.getConfig() | ||
402 | const res = await makeHTMLRequest(servers[0].url, '/videos/trending') | ||
403 | |||
404 | const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.' | ||
405 | checkIndexTags(res.text, 'PeerTube', description, '', config) | ||
406 | }) | ||
407 | |||
408 | it('Should update the customized configuration and have the correct index html tags', async function () { | ||
409 | await servers[0].config.updateCustomSubConfig({ | ||
410 | newConfig: { | ||
411 | instance: { | ||
412 | name: 'PeerTube updated', | ||
413 | shortDescription: 'my short description', | ||
414 | description: 'my super description', | ||
415 | terms: 'my super terms', | ||
416 | defaultNSFWPolicy: 'blur', | ||
417 | defaultClientRoute: '/videos/recently-added', | ||
418 | customizations: { | ||
419 | javascript: 'alert("coucou")', | ||
420 | css: 'body { background-color: red; }' | ||
421 | } | ||
422 | } | ||
423 | } | ||
424 | }) | ||
425 | |||
426 | const config = await servers[0].config.getConfig() | ||
427 | const res = await makeHTMLRequest(servers[0].url, '/videos/trending') | ||
428 | |||
429 | checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config) | ||
430 | }) | ||
431 | |||
432 | it('Should have valid index html updated tags (title, description...)', async function () { | ||
433 | const config = await servers[0].config.getConfig() | ||
434 | const res = await makeHTMLRequest(servers[0].url, '/videos/trending') | ||
435 | |||
436 | checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config) | ||
437 | }) | ||
438 | |||
439 | it('Should use the original video URL for the canonical tag', async function () { | ||
440 | for (const basePath of watchVideoBasePaths) { | ||
441 | for (const id of videoIds) { | ||
442 | const res = await makeHTMLRequest(servers[1].url, basePath + id) | ||
443 | expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].store.video.uuid}" />`) | ||
444 | } | ||
445 | } | ||
446 | }) | ||
447 | |||
448 | it('Should use the original account URL for the canonical tag', async function () { | ||
449 | const accountURLtest = res => { | ||
450 | expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/accounts/root" />`) | ||
451 | } | ||
452 | |||
453 | accountURLtest(await makeHTMLRequest(servers[1].url, '/accounts/root@' + servers[0].host)) | ||
454 | accountURLtest(await makeHTMLRequest(servers[1].url, '/a/root@' + servers[0].host)) | ||
455 | accountURLtest(await makeHTMLRequest(servers[1].url, '/@root@' + servers[0].host)) | ||
456 | }) | ||
457 | |||
458 | it('Should use the original channel URL for the canonical tag', async function () { | ||
459 | const channelURLtests = res => { | ||
460 | expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-channels/root_channel" />`) | ||
461 | } | ||
462 | |||
463 | channelURLtests(await makeHTMLRequest(servers[1].url, '/video-channels/root_channel@' + servers[0].host)) | ||
464 | channelURLtests(await makeHTMLRequest(servers[1].url, '/c/root_channel@' + servers[0].host)) | ||
465 | channelURLtests(await makeHTMLRequest(servers[1].url, '/@root_channel@' + servers[0].host)) | ||
466 | }) | ||
467 | |||
468 | it('Should use the original playlist URL for the canonical tag', async function () { | ||
469 | for (const basePath of watchPlaylistBasePaths) { | ||
470 | for (const id of playlistIds) { | ||
471 | const res = await makeHTMLRequest(servers[1].url, basePath + id) | ||
472 | expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlist.uuid}" />`) | ||
473 | } | ||
474 | } | ||
475 | }) | ||
476 | |||
477 | it('Should add noindex meta tag for remote accounts', async function () { | ||
478 | const handle = 'root@' + servers[0].host | ||
479 | const paths = [ '/accounts/', '/a/', '/@' ] | ||
480 | |||
481 | for (const path of paths) { | ||
482 | { | ||
483 | const { text } = await makeHTMLRequest(servers[1].url, path + handle) | ||
484 | expect(text).to.contain('<meta name="robots" content="noindex" />') | ||
485 | } | ||
486 | |||
487 | { | ||
488 | const { text } = await makeHTMLRequest(servers[0].url, path + handle) | ||
489 | expect(text).to.not.contain('<meta name="robots" content="noindex" />') | ||
490 | } | ||
491 | } | ||
492 | }) | ||
493 | |||
494 | it('Should add noindex meta tag for remote channels', async function () { | ||
495 | const handle = 'root_channel@' + servers[0].host | ||
496 | const paths = [ '/video-channels/', '/c/', '/@' ] | ||
497 | |||
498 | for (const path of paths) { | ||
499 | { | ||
500 | const { text } = await makeHTMLRequest(servers[1].url, path + handle) | ||
501 | expect(text).to.contain('<meta name="robots" content="noindex" />') | ||
502 | } | ||
503 | |||
504 | { | ||
505 | const { text } = await makeHTMLRequest(servers[0].url, path + handle) | ||
506 | expect(text).to.not.contain('<meta name="robots" content="noindex" />') | ||
507 | } | ||
508 | } | ||
509 | }) | ||
510 | |||
511 | it('Should not display internal/private/password protected video', async function () { | ||
512 | for (const basePath of watchVideoBasePaths) { | ||
513 | for (const id of [ privateVideoId, internalVideoId, passwordProtectedVideoId ]) { | ||
514 | const res = await makeGetRequest({ | ||
515 | url: servers[0].url, | ||
516 | path: basePath + id, | ||
517 | accept: 'text/html', | ||
518 | expectedStatus: HttpStatusCode.NOT_FOUND_404 | ||
519 | }) | ||
520 | |||
521 | expect(res.text).to.not.contain('internal') | ||
522 | expect(res.text).to.not.contain('private') | ||
523 | expect(res.text).to.not.contain('password protected') | ||
524 | } | ||
525 | } | ||
526 | }) | ||
527 | |||
528 | it('Should add noindex meta tag for unlisted video', async function () { | ||
529 | for (const basePath of watchVideoBasePaths) { | ||
530 | const res = await makeGetRequest({ | ||
531 | url: servers[0].url, | ||
532 | path: basePath + unlistedVideoId, | ||
533 | accept: 'text/html', | ||
534 | expectedStatus: HttpStatusCode.OK_200 | ||
535 | }) | ||
536 | |||
537 | expect(res.text).to.contain('unlisted') | ||
538 | expect(res.text).to.contain('<meta name="robots" content="noindex" />') | ||
539 | } | ||
540 | }) | ||
541 | }) | ||
542 | |||
543 | describe('Embed HTML', function () { | ||
544 | |||
545 | it('Should have the correct embed html tags', async function () { | ||
546 | const config = await servers[0].config.getConfig() | ||
547 | const res = await makeHTMLRequest(servers[0].url, servers[0].store.video.embedPath) | ||
548 | |||
549 | checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config) | ||
550 | }) | ||
551 | }) | ||
552 | |||
553 | after(async function () { | ||
554 | await cleanupTests(servers) | ||
555 | }) | ||
556 | }) | ||