You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.4 KiB
101 lines
3.4 KiB
|
1 month ago
|
import { expect, test } from '@playwright/test';
|
||
|
|
|
||
|
|
test.describe('Feed del blog', () => {
|
||
|
|
test('se sirve como RSS y lo anuncia toda la web', async ({ page, request }) => {
|
||
|
|
const respuesta = await request.get('/blog/rss.xml');
|
||
|
|
expect(respuesta.status()).toBe(200);
|
||
|
|
expect(respuesta.headers()['content-type']).toContain('application/rss+xml');
|
||
|
|
|
||
|
|
// Sin el `<link rel="alternate">` un lector no lo encuentra solo.
|
||
|
|
await page.goto('/');
|
||
|
|
await expect(page.locator('link[type="application/rss+xml"]')).toHaveAttribute(
|
||
|
|
'href',
|
||
|
|
'/blog/rss.xml'
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('lleva todas las entradas, de la más reciente primero', async ({ request }) => {
|
||
|
|
const xml = await (await request.get('/blog/rss.xml')).text();
|
||
|
|
|
||
|
|
const fechas = [...xml.matchAll(/<pubDate>(.*?)<\/pubDate>/g)].map((m) =>
|
||
|
|
new Date(m[1]).getTime()
|
||
|
|
);
|
||
|
|
expect(fechas.length).toBeGreaterThan(1);
|
||
|
|
expect(fechas).toEqual([...fechas].sort((a, b) => b - a));
|
||
|
|
});
|
||
|
|
|
||
|
|
test('las URLs son absolutas', async ({ request }) => {
|
||
|
|
// Un feed se lee fuera del sitio: una ruta relativa no lleva a ninguna
|
||
|
|
// parte.
|
||
|
|
const xml = await (await request.get('/blog/rss.xml')).text();
|
||
|
|
const enlaces = [...xml.matchAll(/<link>(.*?)<\/link>/g)].map((m) => m[1]);
|
||
|
|
|
||
|
|
expect(enlaces.length).toBeGreaterThan(0);
|
||
|
|
expect(enlaces.every((e) => e.startsWith('https://'))).toBe(true);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
test.describe('Mapa del sitio', () => {
|
||
|
|
test('se sirve como XML y lo anuncia robots.txt', async ({ request }) => {
|
||
|
|
const respuesta = await request.get('/sitemap.xml');
|
||
|
|
expect(respuesta.status()).toBe(200);
|
||
|
|
expect(respuesta.headers()['content-type']).toContain('xml');
|
||
|
|
|
||
|
|
const robots = await (await request.get('/robots.txt')).text();
|
||
|
|
expect(robots).toContain('Sitemap: https://senzapaura.com/sitemap.xml');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('incluye el catálogo entero', async ({ request }) => {
|
||
|
|
const xml = await (await request.get('/sitemap.xml')).text();
|
||
|
|
|
||
|
|
// Una muestra de cada tipo: si algo se cayera del mapa, sería por tipo.
|
||
|
|
expect(xml).toContain('/canciones/dorina');
|
||
|
|
expect(xml).toContain('/musica/baladas-romanticas');
|
||
|
|
expect(xml).toContain('/albumes/singles-baladas-romanticas');
|
||
|
|
expect(xml).toContain('/taller/bachata');
|
||
|
|
expect(xml).toContain('/blog/lo-que-no-cabe-en-una-cancion');
|
||
|
|
expect(xml).toContain('/etiquetas/desamor');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('no publica lo que depende de quién mira', async ({ request }) => {
|
||
|
|
const xml = await (await request.get('/sitemap.xml')).text();
|
||
|
|
|
||
|
|
for (const privada of [
|
||
|
|
'/cuenta',
|
||
|
|
'/carrito',
|
||
|
|
'/favoritos',
|
||
|
|
'/entrar',
|
||
|
|
'/descargas',
|
||
|
|
'/admin'
|
||
|
|
]) {
|
||
|
|
expect(xml).not.toContain(`<loc>https://senzapaura.com${privada}`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
test.describe('Imagen al compartir', () => {
|
||
|
|
test('una página sin portada propia usa la de reserva', async ({ page }) => {
|
||
|
|
await page.goto('/taller');
|
||
|
|
|
||
|
|
await expect(page.locator('meta[property="og:image"]')).toHaveAttribute(
|
||
|
|
'content',
|
||
|
|
'https://senzapaura.com/og.jpg'
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('un tema comparte su propia portada', async ({ page }) => {
|
||
|
|
await page.goto('/canciones/como-si-nada');
|
||
|
|
|
||
|
|
const contenido = await page.locator('meta[property="og:image"]').getAttribute('content');
|
||
|
|
expect(contenido).not.toContain('/og.jpg');
|
||
|
|
expect(contenido).toContain('/images/');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('la imagen de reserva existe y tiene la proporción de una tarjeta', async ({ request }) => {
|
||
|
|
const respuesta = await request.get('/og.jpg');
|
||
|
|
|
||
|
|
expect(respuesta.status()).toBe(200);
|
||
|
|
expect(respuesta.headers()['content-type']).toContain('image/jpeg');
|
||
|
|
});
|
||
|
|
});
|