mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-06 03:50:26 +02:00
Fix SEO and refactor HTML pages generation
* Split methods in multiple classes * Add JSONLD tags in embed too * Index embeds but use a canonical URL tag (targeting the watch page) * Remote objects don't include a canonical URL tag anymore. Instead we forbid indexation * Canonical URLs now use the official short URL (/w/, /w/p, /a, /c etc.)
This commit is contained in:
parent
e731f4b724
commit
f90db24233
23 changed files with 1876 additions and 1213 deletions
258
packages/tests/src/client/index-html.ts
Normal file
258
packages/tests/src/client/index-html.ts
Normal file
|
@ -0,0 +1,258 @@
|
|||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { expect } from 'chai'
|
||||
import { HttpStatusCode, VideoPlaylistCreateResult } from '@peertube/peertube-models'
|
||||
import { cleanupTests, makeGetRequest, makeHTMLRequest, PeerTubeServer } from '@peertube/peertube-server-commands'
|
||||
import { checkIndexTags, getWatchPlaylistBasePaths, getWatchVideoBasePaths, prepareClientTests } from '@tests/shared/client.js'
|
||||
|
||||
describe('Test index HTML generation', function () {
|
||||
let servers: PeerTubeServer[]
|
||||
|
||||
let videoIds: (string | number)[] = []
|
||||
let privateVideoId: string
|
||||
let internalVideoId: string
|
||||
let unlistedVideoId: string
|
||||
let passwordProtectedVideoId: string
|
||||
|
||||
let playlist: VideoPlaylistCreateResult
|
||||
|
||||
let playlistIds: (string | number)[] = []
|
||||
let privatePlaylistId: string
|
||||
let unlistedPlaylistId: string
|
||||
|
||||
let instanceDescription: string
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000);
|
||||
|
||||
({
|
||||
servers,
|
||||
playlistIds,
|
||||
videoIds,
|
||||
playlist,
|
||||
privateVideoId,
|
||||
internalVideoId,
|
||||
passwordProtectedVideoId,
|
||||
unlistedVideoId,
|
||||
privatePlaylistId,
|
||||
unlistedPlaylistId,
|
||||
instanceDescription
|
||||
} = await prepareClientTests())
|
||||
})
|
||||
|
||||
describe('Instance tags', function () {
|
||||
|
||||
it('Should have valid index html tags (title, description...)', async function () {
|
||||
const config = await servers[0].config.getConfig()
|
||||
const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
|
||||
|
||||
checkIndexTags(res.text, 'PeerTube', instanceDescription, '', config)
|
||||
})
|
||||
|
||||
it('Should update the customized configuration and have the correct index html tags', async function () {
|
||||
await servers[0].config.updateCustomSubConfig({
|
||||
newConfig: {
|
||||
instance: {
|
||||
name: 'PeerTube updated',
|
||||
shortDescription: 'my short description',
|
||||
description: 'my super description',
|
||||
terms: 'my super terms',
|
||||
defaultNSFWPolicy: 'blur',
|
||||
defaultClientRoute: '/videos/recently-added',
|
||||
customizations: {
|
||||
javascript: 'alert("coucou")',
|
||||
css: 'body { background-color: red; }'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const config = await servers[0].config.getConfig()
|
||||
const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
|
||||
|
||||
checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config)
|
||||
})
|
||||
|
||||
it('Should have valid index html updated tags (title, description...)', async function () {
|
||||
const config = await servers[0].config.getConfig()
|
||||
const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
|
||||
|
||||
checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Canonical tags', function () {
|
||||
|
||||
it('Should use the original video URL for the canonical tag', async function () {
|
||||
for (const basePath of getWatchVideoBasePaths()) {
|
||||
for (const id of videoIds) {
|
||||
const res = await makeHTMLRequest(servers[0].url, basePath + id)
|
||||
expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/w/${servers[0].store.video.shortUUID}" />`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Should use the original playlist URL for the canonical tag', async function () {
|
||||
for (const basePath of getWatchPlaylistBasePaths()) {
|
||||
for (const id of playlistIds) {
|
||||
const res = await makeHTMLRequest(servers[0].url, basePath + id)
|
||||
expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/w/p/${playlist.shortUUID}" />`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Should use the original account URL for the canonical tag', async function () {
|
||||
const accountURLtest = res => {
|
||||
expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/a/root" />`)
|
||||
}
|
||||
|
||||
accountURLtest(await makeHTMLRequest(servers[0].url, '/accounts/root@' + servers[0].host))
|
||||
accountURLtest(await makeHTMLRequest(servers[0].url, '/a/root@' + servers[0].host))
|
||||
accountURLtest(await makeHTMLRequest(servers[0].url, '/@root@' + servers[0].host))
|
||||
})
|
||||
|
||||
it('Should use the original channel URL for the canonical tag', async function () {
|
||||
const channelURLtests = res => {
|
||||
expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/c/root_channel" />`)
|
||||
}
|
||||
|
||||
channelURLtests(await makeHTMLRequest(servers[0].url, '/video-channels/root_channel@' + servers[0].host))
|
||||
channelURLtests(await makeHTMLRequest(servers[0].url, '/c/root_channel@' + servers[0].host))
|
||||
channelURLtests(await makeHTMLRequest(servers[0].url, '/@root_channel@' + servers[0].host))
|
||||
})
|
||||
})
|
||||
|
||||
describe('Indexation tags', function () {
|
||||
|
||||
it('Should not index remote videos', async function () {
|
||||
for (const basePath of getWatchVideoBasePaths()) {
|
||||
for (const id of videoIds) {
|
||||
{
|
||||
const res = await makeHTMLRequest(servers[1].url, basePath + id)
|
||||
expect(res.text).to.contain('<meta name="robots" content="noindex" />')
|
||||
}
|
||||
|
||||
{
|
||||
const res = await makeHTMLRequest(servers[0].url, basePath + id)
|
||||
expect(res.text).to.not.contain('<meta name="robots" content="noindex" />')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Should not index remote playlists', async function () {
|
||||
for (const basePath of getWatchPlaylistBasePaths()) {
|
||||
for (const id of playlistIds) {
|
||||
{
|
||||
const res = await makeHTMLRequest(servers[1].url, basePath + id)
|
||||
expect(res.text).to.contain('<meta name="robots" content="noindex" />')
|
||||
}
|
||||
|
||||
{
|
||||
const res = await makeHTMLRequest(servers[0].url, basePath + id)
|
||||
expect(res.text).to.not.contain('<meta name="robots" content="noindex" />')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Should add noindex meta tag for remote accounts', async function () {
|
||||
const handle = 'root@' + servers[0].host
|
||||
const paths = [ '/accounts/', '/a/', '/@' ]
|
||||
|
||||
for (const path of paths) {
|
||||
{
|
||||
const { text } = await makeHTMLRequest(servers[1].url, path + handle)
|
||||
expect(text).to.contain('<meta name="robots" content="noindex" />')
|
||||
}
|
||||
|
||||
{
|
||||
const { text } = await makeHTMLRequest(servers[0].url, path + handle)
|
||||
expect(text).to.not.contain('<meta name="robots" content="noindex" />')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Should add noindex meta tag for remote channels', async function () {
|
||||
const handle = 'root_channel@' + servers[0].host
|
||||
const paths = [ '/video-channels/', '/c/', '/@' ]
|
||||
|
||||
for (const path of paths) {
|
||||
{
|
||||
const { text } = await makeHTMLRequest(servers[1].url, path + handle)
|
||||
expect(text).to.contain('<meta name="robots" content="noindex" />')
|
||||
}
|
||||
|
||||
{
|
||||
const { text } = await makeHTMLRequest(servers[0].url, path + handle)
|
||||
expect(text).to.not.contain('<meta name="robots" content="noindex" />')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Should add noindex meta tag for unlisted video', async function () {
|
||||
for (const basePath of getWatchVideoBasePaths()) {
|
||||
const res = await makeGetRequest({
|
||||
url: servers[0].url,
|
||||
path: basePath + unlistedVideoId,
|
||||
accept: 'text/html',
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
|
||||
expect(res.text).to.contain('unlisted')
|
||||
expect(res.text).to.contain('<meta name="robots" content="noindex" />')
|
||||
}
|
||||
})
|
||||
|
||||
it('Should add noindex meta tag for unlisted video playlist', async function () {
|
||||
for (const basePath of getWatchPlaylistBasePaths()) {
|
||||
const res = await makeGetRequest({
|
||||
url: servers[0].url,
|
||||
path: basePath + unlistedPlaylistId,
|
||||
accept: 'text/html',
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
|
||||
expect(res.text).to.contain('unlisted')
|
||||
expect(res.text).to.contain('<meta name="robots" content="noindex" />')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Check no leaks for private objects', function () {
|
||||
|
||||
it('Should not display internal/private/password protected video', async function () {
|
||||
for (const basePath of getWatchVideoBasePaths()) {
|
||||
for (const id of [ privateVideoId, internalVideoId, passwordProtectedVideoId ]) {
|
||||
const res = await makeGetRequest({
|
||||
url: servers[0].url,
|
||||
path: basePath + id,
|
||||
accept: 'text/html',
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
|
||||
expect(res.text).to.not.contain('internal')
|
||||
expect(res.text).to.not.contain('private')
|
||||
expect(res.text).to.not.contain('password protected')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Should not display private video playlist', async function () {
|
||||
for (const basePath of getWatchPlaylistBasePaths()) {
|
||||
const res = await makeGetRequest({
|
||||
url: servers[0].url,
|
||||
path: basePath + privatePlaylistId,
|
||||
accept: 'text/html',
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
|
||||
expect(res.text).to.not.contain('private')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests(servers)
|
||||
})
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue