# Pruebas automatizadas de UI

> TestCase/TestSuite ejecutándose en el runtime gráfico, con comparación visual de screenshots (golden images).

Source: https://crossfly.dev/es/docs/best-practices/testes — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Pruebas automatizadas de UI

El framework de pruebas de CrossFly **no es JUnit**. Cada `TestCase` se ejecuta **dentro del runtime gráfico**
(paint thread, `EventsProcessor`, pipeline GL), y la aserción principal es la **comparación visual de
screenshots** contra imágenes-referencia (*golden images*). Portal al
Capítulo 31.

## Anatomía de un `TestCase`
```java
public class LoginTest extends TestCase {
   @Override protected void load() throws Exception {
      new LoginScreen().show();        // arma la pantalla bajo prueba
   }
   @Override public void runTests() throws Exception {
      waitWindow(LoginScreen.class);
      type(0, TextField.class, "usuario@app.com");   // escribe en el 1er TextField
      type(1, TextField.class, "senha123");
      click("Entrar");                 // hace clic en el botón con ese texto
      shot();                          // captura y compara con el golden
      waitWindow(HomeScreen.class);
      shot();
   }
   @Override protected void unload() { /* limpia el estado */ }
}
```
Interacción: `click(...)`, `type(...)`, `enter()`, `penDown/penUp/penDrag(...)`, `setText(...)`.
Descubrimiento: `find(index, Classe)` / `find(texto, Classe)`. Sincronización: `waitWindow(...)`,
`waitAnimation()`, `waitUIidle(...)`.

## Agrupar y ejecutar — `TestSuite`
```java
TestSuite suite = new TestSuite();
suite.startTests(new TestCase[]{ new LoginTest(), new CadastroTest() });
```
La suite ejecuta cada prueba, compara los `shot()` con los goldens y reporta (`success`/`fail`/`log`).

## ⚠️ El determinismo es un prerrequisito: `DeviceConfig.isTesting`
La comparación píxel-a-píxel solo coincide si el renderizado es **determinístico**. Activa
`DeviceConfig.isTesting = true` — eso fija el cursor, elimina timestamps y hace que `TimePicker`/reloj sean
estables. **Sin eso, el golden nunca coincide** (cursor parpadeando, hora actual, etc. cambian la imagen).

## Sin UI: `WindowlessTestCase`
Para lógica que no necesita pantalla (repository, formato), extiende `WindowlessTestCase` — se ejecuta en el
runtime, pero sin montar UI.

## Generar las imágenes de la doc
Los mismos screenshots de prueba sirven para **generar las imágenes de la documentación/tienda**:
`Main.getScreenShot(true).toPng("prefixo_")`.

## Buenas prácticas
- **Siempre** `DeviceConfig.isTesting = true` en la batería de pruebas.
- Usa `waitWindow(...)`/`waitAnimation()` antes de `shot()` — captura un frame **estable**.
- Un golden por estado visual relevante; regenéralos al cambiar la UI a propósito.

## Errores comunes
- Golden que "desaparece a veces sí, a veces no" → faltó `isTesting`/`waitAnimation` (frame inestable).
- `shot()` antes de que la ventana esté totalmente visible.
