Web de Senza Paura: catálogo, taller, blog y tienda
Sitio del letrista y compositor, con SvelteKit 2 y Svelte 5.
El catálogo es contenido, no base de datos: estilos, álbumes, canciones y
capítulos son Markdown en `src/content/`, validados al compilar y compilados
dentro del bundle, así que recorrer la música no hace ni una consulta. La base
de datos guarda solo lo que generan las personas: cuentas, carritos, pedidos,
compras, valoraciones y favoritos.
Lo que hay:
- Música agrupada por estilos, con página propia para cada estilo, álbum y
tema, buscador y tabla ordenable.
- Reproductor persistente que sobrevive a la navegación. Suena un fragmento;
el archivo completo solo se obtiene comprando.
- Taller de letras: los principios del oficio y una ficha de creación por
estilo hispanoamericano.
- Blog con feed RSS, y etiquetas que cruzan blog y catálogo.
- Tienda con cuentas por código de correo, carrito, Stripe y descargas
protegidas.
- Panel de contenido en `/admin` que escribe los mismos Markdown.
- Tema oscuro de marca y su inversión clara, aplicado antes de pintar.
Lo que falta y no es código: las claves de Stripe y de correo, el tratamiento
del IVA, las páginas de condiciones y privacidad, y el material real. Las
canciones de ejemplo son inventadas y están para sustituirse; el audio son
marcadores salvo un tema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
import { expect, test } from '@playwright/test';
|
|
|
|
|
|
|
|
|
|
test.describe('Taller de letras', () => {
|
|
|
|
|
test('el índice separa los principios de las fichas', async ({ page }) => {
|
|
|
|
|
await page.goto('/taller');
|
|
|
|
|
|
|
|
|
|
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Taller de letras');
|
|
|
|
|
await expect(page.getByRole('heading', { level: 2, name: 'Los principios' })).toBeVisible();
|
|
|
|
|
await expect(page.getByRole('heading', { level: 2, name: 'Fichas de creación' })).toBeVisible();
|
|
|
|
|
// El índice lateral rotula sus bloques, pero no como encabezados: si no,
|
|
|
|
|
// el esquema de la página diría dos veces lo mismo.
|
|
|
|
|
await expect(page.getByRole('heading', { level: 2 })).toHaveCount(2);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('se llega a un principio y se encadena con el siguiente', async ({ page }) => {
|
|
|
|
|
await page.goto('/taller');
|
|
|
|
|
// El listado de la página, no el índice lateral, que repite los enlaces.
|
|
|
|
|
await page
|
|
|
|
|
.locator('section.bloque')
|
|
|
|
|
.getByRole('link', { name: /Lo que hace que una letra funcione/ })
|
|
|
|
|
.click();
|
|
|
|
|
|
|
|
|
|
await expect(page).toHaveURL('/taller/lo-que-hace-que-una-letra-funcione');
|
|
|
|
|
await expect(page.getByRole('heading', { level: 1 })).toHaveText(
|
|
|
|
|
'Lo que hace que una letra funcione'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Los capítulos están pensados para seguirse en orden.
|
|
|
|
|
await page.getByRole('link', { name: /Siguiente/ }).click();
|
|
|
|
|
await expect(page.getByRole('heading', { level: 1 })).toHaveText('La imagen concreta');
|
|
|
|
|
});
|
|
|
|
|
|
La ficha de género pierde la barra lateral y gana su franja de datos
Los datos del género —compás, metro, tempo, rima— pasan de una lista de
definiciones apretada en una columna estrecha a la derecha a una franja a
todo lo ancho encima del texto. El compás y la métrica de un género se
leen juntos o no se leen, y en la lateral quedaban en letra pequeña con el
texto escorado.
La estructura, la temática y los rasgos bajan debajo de la prosa como
bloques a lo ancho: la temática en rejilla —son etiquetas disfrazadas de
frase— y los rasgos en lista, que son frases de verdad. Es el sitio donde
entrarán los instrumentos, los letristas, las obras de referencia y el
linaje cuando tengan datos.
Y el volcado de medios: 55 archivos a la tabla `medio` con su huella, su
peso y su duración MEDIDA, no escrita. De ahí salen dos cosas que no se
veían: el mismo audio está copiado bajo doce nombres distintos, y las
duraciones del catálogo dicen 252 segundos donde el archivo dura 6.
La clave de un medio lleva su almacén delante, porque `singles/dorina.mp3`
existe en audio y en muestras y sin eso serían la misma fila. Es además la
ruta con la que se servirán desde m.senzapaura.es/archives.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
test('una ficha de género trae sus datos de creación', async ({ page }) => {
|
Web de Senza Paura: catálogo, taller, blog y tienda
Sitio del letrista y compositor, con SvelteKit 2 y Svelte 5.
El catálogo es contenido, no base de datos: estilos, álbumes, canciones y
capítulos son Markdown en `src/content/`, validados al compilar y compilados
dentro del bundle, así que recorrer la música no hace ni una consulta. La base
de datos guarda solo lo que generan las personas: cuentas, carritos, pedidos,
compras, valoraciones y favoritos.
Lo que hay:
- Música agrupada por estilos, con página propia para cada estilo, álbum y
tema, buscador y tabla ordenable.
- Reproductor persistente que sobrevive a la navegación. Suena un fragmento;
el archivo completo solo se obtiene comprando.
- Taller de letras: los principios del oficio y una ficha de creación por
estilo hispanoamericano.
- Blog con feed RSS, y etiquetas que cruzan blog y catálogo.
- Tienda con cuentas por código de correo, carrito, Stripe y descargas
protegidas.
- Panel de contenido en `/admin` que escribe los mismos Markdown.
- Tema oscuro de marca y su inversión clara, aplicado antes de pintar.
Lo que falta y no es código: las claves de Stripe y de correo, el tratamiento
del IVA, las páginas de condiciones y privacidad, y el material real. Las
canciones de ejemplo son inventadas y están para sustituirse; el audio son
marcadores salvo un tema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
await page.goto('/taller/bolero');
|
|
|
|
|
|
|
|
|
|
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Bolero');
|
|
|
|
|
await expect(page.getByText('Santiago de Cuba, 1883')).toBeVisible();
|
La ficha de género pierde la barra lateral y gana su franja de datos
Los datos del género —compás, metro, tempo, rima— pasan de una lista de
definiciones apretada en una columna estrecha a la derecha a una franja a
todo lo ancho encima del texto. El compás y la métrica de un género se
leen juntos o no se leen, y en la lateral quedaban en letra pequeña con el
texto escorado.
La estructura, la temática y los rasgos bajan debajo de la prosa como
bloques a lo ancho: la temática en rejilla —son etiquetas disfrazadas de
frase— y los rasgos en lista, que son frases de verdad. Es el sitio donde
entrarán los instrumentos, los letristas, las obras de referencia y el
linaje cuando tengan datos.
Y el volcado de medios: 55 archivos a la tabla `medio` con su huella, su
peso y su duración MEDIDA, no escrita. De ahí salen dos cosas que no se
veían: el mismo audio está copiado bajo doce nombres distintos, y las
duraciones del catálogo dicen 252 segundos donde el archivo dura 6.
La clave de un medio lleva su almacén delante, porque `singles/dorina.mp3`
existe en audio y en muestras y sin eso serían la misma fila. Es además la
ruta con la que se servirán desde m.senzapaura.es/archives.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Los datos comparables van en una franja a lo ancho, no en una barra
|
|
|
|
|
* lateral: el compás y la métrica de un género se leen juntos o no se leen.
|
|
|
|
|
* Antes era una lista de definiciones en una columna estrecha a la derecha,
|
|
|
|
|
* con los datos en letra pequeña y el texto escorado.
|
|
|
|
|
*/
|
|
|
|
|
const franja = page.locator('.datos .dato');
|
|
|
|
|
await expect(franja).toHaveCount(4);
|
|
|
|
|
await expect(franja.filter({ hasText: 'Compás' })).toContainText('2/4');
|
|
|
|
|
await expect(franja.filter({ hasText: 'Metro' })).toContainText('Octosílabo');
|
|
|
|
|
|
|
|
|
|
await expect(page.locator('aside.lateral')).toHaveCount(0);
|
|
|
|
|
|
Web de Senza Paura: catálogo, taller, blog y tienda
Sitio del letrista y compositor, con SvelteKit 2 y Svelte 5.
El catálogo es contenido, no base de datos: estilos, álbumes, canciones y
capítulos son Markdown en `src/content/`, validados al compilar y compilados
dentro del bundle, así que recorrer la música no hace ni una consulta. La base
de datos guarda solo lo que generan las personas: cuentas, carritos, pedidos,
compras, valoraciones y favoritos.
Lo que hay:
- Música agrupada por estilos, con página propia para cada estilo, álbum y
tema, buscador y tabla ordenable.
- Reproductor persistente que sobrevive a la navegación. Suena un fragmento;
el archivo completo solo se obtiene comprando.
- Taller de letras: los principios del oficio y una ficha de creación por
estilo hispanoamericano.
- Blog con feed RSS, y etiquetas que cruzan blog y catálogo.
- Tienda con cuentas por código de correo, carrito, Stripe y descargas
protegidas.
- Panel de contenido en `/admin` que escribe los mismos Markdown.
- Tema oscuro de marca y su inversión clara, aplicado antes de pintar.
Lo que falta y no es código: las claves de Stripe y de correo, el tratamiento
del IVA, las páginas de condiciones y privacidad, y el material real. Las
canciones de ejemplo son inventadas y están para sustituirse; el audio son
marcadores salvo un tema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
await expect(page.getByRole('heading', { level: 2, name: 'De qué se habla' })).toBeVisible();
|
|
|
|
|
await expect(
|
|
|
|
|
page.getByRole('heading', { level: 2, name: 'Rasgos de escritura' })
|
|
|
|
|
).toBeVisible();
|
La ficha de género pierde la barra lateral y gana su franja de datos
Los datos del género —compás, metro, tempo, rima— pasan de una lista de
definiciones apretada en una columna estrecha a la derecha a una franja a
todo lo ancho encima del texto. El compás y la métrica de un género se
leen juntos o no se leen, y en la lateral quedaban en letra pequeña con el
texto escorado.
La estructura, la temática y los rasgos bajan debajo de la prosa como
bloques a lo ancho: la temática en rejilla —son etiquetas disfrazadas de
frase— y los rasgos en lista, que son frases de verdad. Es el sitio donde
entrarán los instrumentos, los letristas, las obras de referencia y el
linaje cuando tengan datos.
Y el volcado de medios: 55 archivos a la tabla `medio` con su huella, su
peso y su duración MEDIDA, no escrita. De ahí salen dos cosas que no se
veían: el mismo audio está copiado bajo doce nombres distintos, y las
duraciones del catálogo dicen 252 segundos donde el archivo dura 6.
La clave de un medio lleva su almacén delante, porque `singles/dorina.mp3`
existe en audio y en muestras y sin eso serían la misma fila. Es además la
ruta con la que se servirán desde m.senzapaura.es/archives.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
await expect(
|
|
|
|
|
page.getByRole('heading', { level: 2, name: 'Estructura de las canciones' })
|
|
|
|
|
).toBeVisible();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('la franja de datos ocupa el ancho, y el texto su medida de lectura', async ({ page }) => {
|
|
|
|
|
// Es la diferencia con la barra lateral de antes, y lo que hace que los
|
|
|
|
|
// datos se puedan comparar de un vistazo.
|
|
|
|
|
await page.setViewportSize({ width: 1280, height: 900 });
|
|
|
|
|
await page.goto('/taller/bolero');
|
|
|
|
|
|
|
|
|
|
const datos = (await page.locator('.datos').boundingBox())!;
|
|
|
|
|
const texto = (await page.locator('.texto').boundingBox())!;
|
|
|
|
|
|
|
|
|
|
expect(datos.width).toBeGreaterThan(texto.width * 1.4);
|
|
|
|
|
expect(Math.abs(datos.x - texto.x)).toBeLessThan(2);
|
Web de Senza Paura: catálogo, taller, blog y tienda
Sitio del letrista y compositor, con SvelteKit 2 y Svelte 5.
El catálogo es contenido, no base de datos: estilos, álbumes, canciones y
capítulos son Markdown en `src/content/`, validados al compilar y compilados
dentro del bundle, así que recorrer la música no hace ni una consulta. La base
de datos guarda solo lo que generan las personas: cuentas, carritos, pedidos,
compras, valoraciones y favoritos.
Lo que hay:
- Música agrupada por estilos, con página propia para cada estilo, álbum y
tema, buscador y tabla ordenable.
- Reproductor persistente que sobrevive a la navegación. Suena un fragmento;
el archivo completo solo se obtiene comprando.
- Taller de letras: los principios del oficio y una ficha de creación por
estilo hispanoamericano.
- Blog con feed RSS, y etiquetas que cruzan blog y catálogo.
- Tienda con cuentas por código de correo, carrito, Stripe y descargas
protegidas.
- Panel de contenido en `/admin` que escribe los mismos Markdown.
- Tema oscuro de marca y su inversión clara, aplicado antes de pintar.
Lo que falta y no es código: las claves de Stripe y de correo, el tratamiento
del IVA, las páginas de condiciones y privacidad, y el material real. Las
canciones de ejemplo son inventadas y están para sustituirse; el audio son
marcadores salvo un tema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('la portada del taller también lleva el índice al lado', async ({ page }) => {
|
|
|
|
|
// El índice está en el layout de la sección, así que acompaña a todas sus
|
|
|
|
|
// páginas, no solo a los capítulos.
|
|
|
|
|
await page.goto('/taller');
|
|
|
|
|
|
|
|
|
|
const indice = page.getByRole('navigation', { name: 'Contenido del taller' });
|
|
|
|
|
await expect(indice).toBeVisible();
|
|
|
|
|
await expect(indice.getByRole('link', { name: 'Bolero' })).toBeVisible();
|
|
|
|
|
// En la portada no hay capítulo abierto que marcar.
|
|
|
|
|
await expect(indice.locator('a[aria-current="page"]')).toHaveCount(0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('cada capítulo lleva el índice del taller al lado', async ({ page }) => {
|
|
|
|
|
await page.goto('/taller/bolero');
|
|
|
|
|
|
|
|
|
|
const indice = page.getByRole('navigation', { name: 'Contenido del taller' });
|
|
|
|
|
await expect(indice).toBeVisible();
|
|
|
|
|
// Marca dónde estás dentro de la estructura.
|
|
|
|
|
await expect(indice.getByRole('link', { name: 'Bolero' })).toHaveAttribute(
|
|
|
|
|
'aria-current',
|
|
|
|
|
'page'
|
|
|
|
|
);
|
|
|
|
|
// Y enseña los dos bloques enteros, no solo el actual.
|
|
|
|
|
await expect(indice.getByRole('link', { name: 'El estribillo' })).toBeVisible();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('un principio no enseña ficha de creación', async ({ page }) => {
|
|
|
|
|
// La ficha es de los estilos; en un principio sería un panel vacío.
|
|
|
|
|
await page.goto('/taller/el-estribillo');
|
|
|
|
|
|
|
|
|
|
await expect(page.getByRole('heading', { level: 2, name: 'De un vistazo' })).toHaveCount(0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('el taller está en la navegación principal', async ({ page }) => {
|
|
|
|
|
await page.goto('/');
|
|
|
|
|
await page
|
|
|
|
|
.getByRole('navigation', { name: 'Principal' })
|
|
|
|
|
.getByRole('link', { name: 'Taller' })
|
|
|
|
|
.click();
|
|
|
|
|
|
|
|
|
|
await expect(page).toHaveURL('/taller');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test.describe('Tema claro y oscuro', () => {
|
|
|
|
|
test('sin elegir nada no hay atributo, y manda el marino', async ({ browser }) => {
|
|
|
|
|
// Aunque el sistema pida el claro. El color es de la marca y no lo decide
|
|
|
|
|
// una preferencia que se configuró pensando en otra cosa.
|
Web de Senza Paura: catálogo, taller, blog y tienda
Sitio del letrista y compositor, con SvelteKit 2 y Svelte 5.
El catálogo es contenido, no base de datos: estilos, álbumes, canciones y
capítulos son Markdown en `src/content/`, validados al compilar y compilados
dentro del bundle, así que recorrer la música no hace ni una consulta. La base
de datos guarda solo lo que generan las personas: cuentas, carritos, pedidos,
compras, valoraciones y favoritos.
Lo que hay:
- Música agrupada por estilos, con página propia para cada estilo, álbum y
tema, buscador y tabla ordenable.
- Reproductor persistente que sobrevive a la navegación. Suena un fragmento;
el archivo completo solo se obtiene comprando.
- Taller de letras: los principios del oficio y una ficha de creación por
estilo hispanoamericano.
- Blog con feed RSS, y etiquetas que cruzan blog y catálogo.
- Tienda con cuentas por código de correo, carrito, Stripe y descargas
protegidas.
- Panel de contenido en `/admin` que escribe los mismos Markdown.
- Tema oscuro de marca y su inversión clara, aplicado antes de pintar.
Lo que falta y no es código: las claves de Stripe y de correo, el tratamiento
del IVA, las páginas de condiciones y privacidad, y el material real. Las
canciones de ejemplo son inventadas y están para sustituirse; el audio son
marcadores salvo un tema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
const claro = await browser.newContext({ colorScheme: 'light' });
|
|
|
|
|
const pagina = await claro.newPage();
|
|
|
|
|
await pagina.goto('/taller');
|
|
|
|
|
|
|
|
|
|
await expect(pagina.locator('html')).not.toHaveAttribute('data-tema', /.+/);
|
|
|
|
|
await expect(pagina.getByRole('button', { name: 'Cambiar al tema claro' })).toBeVisible();
|
Web de Senza Paura: catálogo, taller, blog y tienda
Sitio del letrista y compositor, con SvelteKit 2 y Svelte 5.
El catálogo es contenido, no base de datos: estilos, álbumes, canciones y
capítulos son Markdown en `src/content/`, validados al compilar y compilados
dentro del bundle, así que recorrer la música no hace ni una consulta. La base
de datos guarda solo lo que generan las personas: cuentas, carritos, pedidos,
compras, valoraciones y favoritos.
Lo que hay:
- Música agrupada por estilos, con página propia para cada estilo, álbum y
tema, buscador y tabla ordenable.
- Reproductor persistente que sobrevive a la navegación. Suena un fragmento;
el archivo completo solo se obtiene comprando.
- Taller de letras: los principios del oficio y una ficha de creación por
estilo hispanoamericano.
- Blog con feed RSS, y etiquetas que cruzan blog y catálogo.
- Tienda con cuentas por código de correo, carrito, Stripe y descargas
protegidas.
- Panel de contenido en `/admin` que escribe los mismos Markdown.
- Tema oscuro de marca y su inversión clara, aplicado antes de pintar.
Lo que falta y no es código: las claves de Stripe y de correo, el tratamiento
del IVA, las páginas de condiciones y privacidad, y el material real. Las
canciones de ejemplo son inventadas y están para sustituirse; el audio son
marcadores salvo un tema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
|
|
|
|
|
await claro.close();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('la elección manual manda y se recuerda', async ({ browser }) => {
|
|
|
|
|
const claro = await browser.newContext({ colorScheme: 'light' });
|
|
|
|
|
const pagina = await claro.newPage();
|
|
|
|
|
await pagina.goto('/taller');
|
|
|
|
|
|
|
|
|
|
await pagina.getByRole('button', { name: 'Cambiar al tema claro' }).click();
|
|
|
|
|
await expect(pagina.locator('html')).toHaveAttribute('data-tema', 'claro');
|
Web de Senza Paura: catálogo, taller, blog y tienda
Sitio del letrista y compositor, con SvelteKit 2 y Svelte 5.
El catálogo es contenido, no base de datos: estilos, álbumes, canciones y
capítulos son Markdown en `src/content/`, validados al compilar y compilados
dentro del bundle, así que recorrer la música no hace ni una consulta. La base
de datos guarda solo lo que generan las personas: cuentas, carritos, pedidos,
compras, valoraciones y favoritos.
Lo que hay:
- Música agrupada por estilos, con página propia para cada estilo, álbum y
tema, buscador y tabla ordenable.
- Reproductor persistente que sobrevive a la navegación. Suena un fragmento;
el archivo completo solo se obtiene comprando.
- Taller de letras: los principios del oficio y una ficha de creación por
estilo hispanoamericano.
- Blog con feed RSS, y etiquetas que cruzan blog y catálogo.
- Tienda con cuentas por código de correo, carrito, Stripe y descargas
protegidas.
- Panel de contenido en `/admin` que escribe los mismos Markdown.
- Tema oscuro de marca y su inversión clara, aplicado antes de pintar.
Lo que falta y no es código: las claves de Stripe y de correo, el tratamiento
del IVA, las páginas de condiciones y privacidad, y el material real. Las
canciones de ejemplo son inventadas y están para sustituirse; el audio son
marcadores salvo un tema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
|
|
|
|
|
// Sobrevive a la recarga y, sobre todo, se aplica antes de pintar: lo hace
|
|
|
|
|
// un script en línea, no la hidratación.
|
|
|
|
|
await pagina.reload();
|
|
|
|
|
await expect(pagina.locator('html')).toHaveAttribute('data-tema', 'claro');
|
|
|
|
|
|
|
|
|
|
// Y se puede volver.
|
|
|
|
|
await pagina.getByRole('button', { name: 'Cambiar al tema oscuro' }).click();
|
Web de Senza Paura: catálogo, taller, blog y tienda
Sitio del letrista y compositor, con SvelteKit 2 y Svelte 5.
El catálogo es contenido, no base de datos: estilos, álbumes, canciones y
capítulos son Markdown en `src/content/`, validados al compilar y compilados
dentro del bundle, así que recorrer la música no hace ni una consulta. La base
de datos guarda solo lo que generan las personas: cuentas, carritos, pedidos,
compras, valoraciones y favoritos.
Lo que hay:
- Música agrupada por estilos, con página propia para cada estilo, álbum y
tema, buscador y tabla ordenable.
- Reproductor persistente que sobrevive a la navegación. Suena un fragmento;
el archivo completo solo se obtiene comprando.
- Taller de letras: los principios del oficio y una ficha de creación por
estilo hispanoamericano.
- Blog con feed RSS, y etiquetas que cruzan blog y catálogo.
- Tienda con cuentas por código de correo, carrito, Stripe y descargas
protegidas.
- Panel de contenido en `/admin` que escribe los mismos Markdown.
- Tema oscuro de marca y su inversión clara, aplicado antes de pintar.
Lo que falta y no es código: las claves de Stripe y de correo, el tratamiento
del IVA, las páginas de condiciones y privacidad, y el material real. Las
canciones de ejemplo son inventadas y están para sustituirse; el audio son
marcadores salvo un tema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 month ago
|
|
|
await expect(pagina.locator('html')).toHaveAttribute('data-tema', 'oscuro');
|
|
|
|
|
|
|
|
|
|
await claro.close();
|
|
|
|
|
});
|
|
|
|
|
});
|