Keep player state stable during hot reload

codex/redisenio-dominio-musical
dev 4 weeks ago
parent 29e8789312
commit 38fc78aa9a

@ -1,12 +1,14 @@
import { expect, test } from '@playwright/test';
test.describe('Reproductor', () => {
const album = '/albumes/cupido-sin-flechas';
/** El título del tema dentro de la barra, por su enlace exacto. */
const temaEnBarra = (page: import('@playwright/test').Page, slug: string) =>
page.getByRole('group', { name: 'Sonando ahora' }).locator(`a[href="/canciones/${slug}"]`);
test('la barra aparece al reproducir un álbum y anuncia el tema', async ({ page }) => {
await page.goto('/albumes/como-si-nada');
await page.goto(album);
const barra = page.getByRole('region', { name: 'Reproductor' });
await expect(barra).toBeHidden();
@ -14,7 +16,7 @@ test.describe('Reproductor', () => {
await page.getByRole('button', { name: 'Reproducir', exact: true }).first().click();
await expect(barra).toBeVisible();
await expect(temaEnBarra(page, 'como-si-nada')).toBeVisible();
await expect(temaEnBarra(page, 'amame-esta-noche-nada-mas')).toBeVisible();
// Y sigue sonando de verdad, no solo pintada: la posición avanza. Sin esto
// el test pasaría igual con una barra congelada.
@ -24,24 +26,36 @@ test.describe('Reproductor', () => {
expect(Number(await posicion.inputValue())).toBeGreaterThan(antes);
});
test('la barra aparece al reproducir una canción desde la tabla', async ({ page }) => {
await page.goto(album);
const fila = page.getByRole('row').filter({ hasText: 'Ton silence me libère' });
await fila.getByRole('button', { name: 'Reproducir Ton silence me libère' }).click();
const barra = page.getByRole('region', { name: 'Reproductor' });
await expect(barra).toBeVisible();
await expect(temaEnBarra(page, 'ton-silence-me-libere')).toBeVisible();
await expect(fila.getByRole('button', { name: 'Pausar' })).toBeVisible();
});
test('el paso al tema siguiente carga el orden del disco', async ({ page }) => {
await page.goto('/albumes/como-si-nada');
await page.goto(album);
await page.getByRole('button', { name: 'Reproducir', exact: true }).first().click();
const barra = page.getByRole('region', { name: 'Reproductor' });
await barra.getByRole('button', { name: 'Tema siguiente' }).click();
await expect(temaEnBarra(page, 'media-verdad')).toBeVisible();
await expect(temaEnBarra(page, 'cuando-tus-manos-me-tocan')).toBeVisible();
});
test('la reproducción sobrevive al cambiar de página', async ({ page }) => {
// Es la razón de que la barra viva en el layout raíz: navegar por la web
// no puede cortar lo que se está escuchando.
await page.goto('/albumes/como-si-nada');
await page.goto(album);
await page.getByRole('button', { name: 'Reproducir', exact: true }).first().click();
const barra = page.getByRole('region', { name: 'Reproductor' });
await expect(temaEnBarra(page, 'como-si-nada')).toBeVisible();
await expect(temaEnBarra(page, 'amame-esta-noche-nada-mas')).toBeVisible();
await page
.getByRole('navigation', { name: 'Principal' })
@ -50,11 +64,11 @@ test.describe('Reproductor', () => {
await expect(page).toHaveURL('/bio');
await expect(barra).toBeVisible();
await expect(temaEnBarra(page, 'como-si-nada')).toBeVisible();
await expect(temaEnBarra(page, 'amame-esta-noche-nada-mas')).toBeVisible();
});
test('la cola muestra los temas pendientes', async ({ page }) => {
await page.goto('/albumes/como-si-nada');
await page.goto(album);
await page.getByRole('button', { name: 'Reproducir', exact: true }).first().click();
const barra = page.getByRole('region', { name: 'Reproductor' });
@ -62,10 +76,10 @@ test.describe('Reproductor', () => {
const cola = page.getByRole('complementary', { name: 'Cola de reproducción' });
await expect(cola).toBeVisible();
await expect(cola.getByRole('button', { name: /El último tren/ })).toBeVisible();
await expect(cola.getByRole('button', { name: /Pagué por una noche de amor/ })).toBeVisible();
// Saltar desde la cola cambia lo que suena.
await cola.getByRole('button', { name: /El último tren/ }).click();
await expect(temaEnBarra(page, 'el-ultimo-tren')).toBeVisible();
await cola.getByRole('button', { name: /Pagué por una noche de amor/ }).click();
await expect(temaEnBarra(page, 'pague-por-una-noche-de-amor')).toBeVisible();
});
});

@ -463,5 +463,22 @@ class Reproductor {
}
}
/** Instancia unica del reproductor para toda la aplicacion. */
export const reproductor = new Reproductor();
/**
* Instancia unica del reproductor para toda la aplicacion.
*
* Vite puede volver a evaluar este modulo durante una recarga en caliente sin
* reconstruir a la vez todos los componentes que lo importan. Si cada
* evaluacion crease su propio `Reproductor`, una fila podria manejar una
* instancia y la barra inferior observar otra: la fila quedaria en «Pausar»
* pero la barra no aparecería. Conservamos la instancia en los datos HMR para
* que todos los importadores sigan compartiendo exactamente el mismo objeto.
*/
const reproductorAnterior = browser
? (import.meta.hot?.data.reproductor as Reproductor | undefined)
: undefined;
export const reproductor = reproductorAnterior ?? new Reproductor();
if (browser && import.meta.hot) {
import.meta.hot.data.reproductor = reproductor;
}

Loading…
Cancel
Save

Powered by TurnKey Linux.