Tema
Inventario de data-testid
Todos los elementos interactivos de web.theproject.ec tienen un atributo data-testid estable: existe solo para las pruebas y no cambia cuando se retoca el diseño o los textos.
Úsalos siempre en tus pruebas automatizadas:
ts
await page.getByTestId('boton-confirmar').click();Estructura general
| testid | Elemento | Dónde |
|---|---|---|
cabecera | Barra superior | Todas las pantallas |
titulo-app | Título "ReservaLab" | Cabecera |
usuario-actual | Email del usuario en sesión | Cabecera (autenticado) |
boton-cerrar-sesion | Botón de salir | Cabecera (autenticado) |
pie | Pie de página | Todas las pantallas |
Pantalla de inicio de sesión
| testid | Elemento | Notas |
|---|---|---|
pagina-login | Contenedor de la pantalla | Útil para comprobar en qué pantalla estás |
titulo-login | Título "Iniciar sesión" | |
formulario-login | El formulario | |
input-email | Campo de correo | |
input-password | Campo de contraseña | |
boton-entrar | Botón de envío | Se deshabilita mientras envía |
error-login | Mensaje de error | Solo aparece si falla; tiene role="alert" |
ts
await page.getByTestId('input-email').fill('student01@theproject.ec');
await page.getByTestId('input-password').fill(password);
await page.getByTestId('boton-entrar').click();
await expect(page.getByTestId('pagina-citas')).toBeVisible();Pantalla de citas
| testid | Elemento |
|---|---|
pagina-citas | Contenedor de la pantalla |
Formulario de reserva
| testid | Elemento | Notas |
|---|---|---|
seccion-nueva-cita | Bloque de la reserva | |
titulo-nueva-cita | Título "Reservar una cita" | |
formulario-nueva-cita | El formulario | |
select-servicio | Desplegable de servicios | La primera opción está vacía |
opcion-servicio-{id} | Cada opción del desplegable | {id} es el id real del servicio |
input-fecha | Campo de fecha y hora | Tipo datetime-local |
input-notas | Campo de notas | Opcional |
boton-confirmar | Botón de reservar | |
mensaje-exito | Aviso verde | role="status" |
mensaje-error | Aviso rojo | role="alert" |
El desplegable de servicios
La opción en el índice 0 es el texto guía ("Elige un servicio…") y no tiene valor. Para seleccionar el primer servicio real usa { index: 1 }, o mejor todavía, pide los servicios a la API y selecciona por su id:
ts
await page.getByTestId('select-servicio').selectOption({ index: 1 });El campo de fecha
Es datetime-local: espera el formato YYYY-MM-DDTHH:mm en hora local, sin zona y sin segundos.
ts
const fecha = new Date(Date.now() + 30 * 86400000);
fecha.setSeconds(0, 0);
await page.getByTestId('input-fecha').fill(fecha.toISOString().slice(0, 16));Listado de citas
| testid | Elemento | Notas |
|---|---|---|
seccion-mis-citas | Bloque del listado | |
titulo-mis-citas | Título "Mis citas" | |
boton-recargar | Botón de recargar | |
cargando-citas | Aviso de carga | Solo mientras carga |
sin-citas | Aviso de listado vacío | Solo si no hay citas |
tabla-citas | La tabla | Solo si hay citas |
total-citas | Resumen "Total: N" |
Filas de la tabla
Cada fila lleva el id real de la cita en su testid:
| testid | Elemento |
|---|---|
fila-cita-{id} | La fila completa |
servicio-cita-{id} | Nombre del servicio |
fecha-cita-{id} | Fecha formateada |
estado-cita-{id} | Estado: confirmada, cancelada o completada |
boton-cancelar-{id} | Botón de cancelar (solo si está confirmada) |
Para recorrer todas las filas sin conocer los ids:
ts
// Contar las citas visibles
const filas = page.locator('[data-testid^="fila-cita-"]');
await expect(filas).toHaveCount(5);
// Sacar los ids de las citas que hay ahora
const ids = await filas.evaluateAll((fs) =>
fs.map((f) => f.getAttribute('data-testid').replace('fila-cita-', '')),
);
// Cancelar la primera cita confirmada
const boton = page.locator('[data-testid^="boton-cancelar-"]').first();
await boton.click();Buenas prácticas
Espera por estado, no por tiempo. Un sleep fijo hace la prueba lenta y frágil a la vez:
ts
// ❌ mal
await page.waitForTimeout(3000);
// ✅ bien
await expect(page.getByTestId('mensaje-exito')).toBeVisible();Comprueba el efecto, no solo el mensaje. La aplicación puede decir "éxito" sin haber hecho nada:
ts
// Débil: solo mira el cartel
await expect(page.getByTestId('mensaje-exito')).toBeVisible();
// Fuerte: comprueba que el dato cambió de verdad
await expect(page.getByTestId(`estado-cita-${id}`)).toHaveText('cancelada');Deja el sistema como estaba. Si tu prueba crea una cita, cancélala al final — y espera a que la cancelación se refleje antes de terminar la prueba, o Playwright cierra la página con la petición a medias.
Si falta un testid
Si necesitas automatizar algo que no tiene data-testid, avísale al instructor: se puede añadir. Es mejor que recurrir a un selector frágil.