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.
senzapaura_es/e2e/sindicacion.e2e.ts

157 lines
5.3 KiB

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');
});
});
test.describe('Legal', () => {
test('las cinco páginas están y se enlazan desde el pie', async ({ page }) => {
await page.goto('/');
const pie = page.getByRole('navigation', { name: 'Legal' });
for (const titulo of [
'Información legal',
'Condiciones de uso',
'Política de privacidad',
'Política de cookies',
'Condiciones de venta'
]) {
await expect(pie.getByRole('link', { name: titulo })).toBeVisible();
}
});
test('cada texto legal dice cuándo se revisó', async ({ page }) => {
// Un aviso legal sin fecha no sirve: quien lo lee necesita saber a qué
// versión se está acogiendo.
await page.goto('/legal/privacidad');
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Política de privacidad');
await expect(page.getByText(/Última revisión/)).toBeVisible();
});
test('desde un texto legal se llega a los demás', async ({ page }) => {
await page.goto('/legal/cookies');
const lateral = page.getByRole('navigation', { name: 'Textos legales' });
await expect(lateral.getByRole('link', { name: 'Política de cookies' })).toHaveAttribute(
'aria-current',
'page'
);
await lateral.getByRole('link', { name: 'Condiciones de venta' }).click();
await expect(page).toHaveURL('/legal/condiciones-de-venta');
});
});
test.describe('Sin terceros', () => {
test('cargar la web no contacta con ningún dominio ajeno', async ({ page }) => {
// Las tipografías se sirven desde aquí. Cargarlas de Google mandaba la IP
// de cada visitante a un tercero en cada página, sin pedirlo.
const ajenos = new Set<string>();
page.on('request', (r) => {
const host = new URL(r.url()).host;
if (!host.startsWith('localhost') && !host.startsWith('127.0.0.1')) ajenos.add(host);
});
for (const ruta of ['/', '/musica', '/canciones/dorina', '/entrar']) {
await page.goto(ruta);
}
expect([...ajenos]).toEqual([]);
});
});

Powered by TurnKey Linux.