# Pruebas guardadas

> Fuente: https://astrallab.dev/es/docs/saved-tests

Un flujo que un agente ha probado se puede conservar como prueba guardada: un script más unos pocos datos (nombre, ticket, entorno, credenciales que usa, modo de grabación). Cualquier agente puede reproducirla, tú puedes verla y el CI puede ejecutarla.

## Dónde viven las pruebas

- Las **pruebas de proyecto** se guardan en `.astral/tests/<id>.astral.js` dentro de tu proyecto y se versionan con tu repositorio. El id es un slug del nombre de la prueba.
- Las **pruebas temporales** se guardan en la carpeta de datos de Astral y caducan tras un número de días (7 por defecto).

El agente guarda una con `test_save` y puede vincularla a un ticket. Una prueba guardada reproduce el script, no el modelo, así que una reproducción no gasta tokens del modelo y ejecuta los mismos pasos cada vez.

```js
return await astral.test('Login', async () => {
  await astral.step('Open the login page', () => astral.navigate({url: astral.url('/login')}));
  await astral.step('Sign in', async () => {
    await astral.fill({locator: {role: 'textbox', name: 'Email'}, credential: 'shop.demo', field: 'username'});
    await astral.fill({locator: {role: 'textbox', name: 'Password', exact: true}, credential: 'shop.demo', field: 'password'});
    await astral.click({locator: {role: 'button', name: 'Sign in'}});
    await astral.expect.url('/account');
  });
}, {record: 'actions'});
```

## .astral/config.json

El `.astral/config.json` del proyecto declara los entornos contra los que se ejecutan tus pruebas y las credenciales que pueden usar, **por nombre**. Las pruebas navegan con `astral.url('/login')`, de modo que la misma prueba se ejecuta contra local, staging o producción.

```json
{
  "project": "shop",
  "envs": {
    "local":   { "baseUrl": "http://localhost:3000" },
    "staging": { "baseUrl": "https://staging.example.com" },
    "prod":    { "baseUrl": "https://www.example.com", "protected": true }
  },
  "defaultEnv": "local",
  "collections": {
    "smoke": { "name": "Smoke", "tests": ["login", "checkout"] }
  },
  "credentials": {
    "shop.demo": {
      "username": "demo@example.com",
      "password": { "keychain": "shop.demo.password" }
    }
  }
}
```

| Clave | Qué es |
| --- | --- |
| `envs` | URLs base con nombre. `protected: true` marca un entorno como producción. Sin usuario ni contraseña en la URL. |
| `defaultEnv` | El entorno que se usa cuando no se indica ninguno. |
| `collections` | Pruebas que se ejecutan en orden como un grupo, con un resumen de éxito o fallo y un informe que enlaza el de cada prueba. |
| `credentials` | Inicios de sesión con nombre: un usuario, una contraseña, una semilla de código de un solo uso y campos adicionales. Los secretos son referencias, nunca valores. |
| `layout` | Selectores que la comprobación de layout ignora y sus umbrales. |

## Credenciales y llavero

Un secreto en `config.json` es una referencia a dónde se guarda, nunca el valor. Una contraseña en texto plano en el archivo se rechaza. Una referencia es una de estas:

```
{ "keychain": "<id>" }
{ "env": "ASTRAL_TEST_<NAME>" }
{ "local": "<key>" }
```

| Referencia | Dónde está el valor |
| --- | --- |
| `keychain` | El llavero de tu sistema. Lo defines en Astral; un agente nunca puede volver a leerlo. |
| `env` | Una variable de entorno cuyo nombre empieza por `ASTRAL_TEST_`. |
| `local` | `.astral/secrets.local.json`, que debe estar en `.gitignore`. Astral se niega a crearlo si no, y avisa si ya existe sin estar ignorado. |

- El agente solo ve el nombre de la credencial y el nombre de usuario. `astral.fill` resuelve el valor por sí mismo y lo escribe con pulsaciones reales; el agente solo sabe que se escribió y se enmascaró.
- Un secreto solo se escribe en un campo sensible (contraseña, código de un solo uso, tarjeta) del propio origen del entorno, de modo que no puede leerse ni enviarse a otro sitio. Los informes muestran •••••• en su lugar.
- Un secreto del llavero se guarda junto con los orígenes de los entornos en ese momento y solo se escribe en ellos, aunque `config.json` se edite después. Para inicios de sesión sensibles, prefiere el llavero.

## Entornos protegidos

En un entorno marcado como `protected` (producción, por ejemplo) solo se ejecutan las pruebas declaradas `readOnly`, y solo después de que una persona apruebe en Astral esa versión exacta de la prueba. Un agente puede pedir `readOnly: true`, pero eso es una petición, no una aprobación: la apruebas tú con **Aprobar como solo lectura** en el panel Pruebas, la aprobación se guarda fuera del proyecto y se pierde si la prueba se edita. En una colección, las pruebas no aprobadas se omiten indicando el motivo.

## Viewports

Una prueba o una colección puede ejecutarse en uno o varios viewports, y Astral ejecuta cada prueba en cada uno.

| Preajuste | Tamaño (px CSS) | Densidad de píxeles | Táctil |
| --- | --- | --- | --- |
| `mobile` | 390 × 844 | 3   | sí  |
| `tablet` | 820 × 1180 | 2   | sí  |
| `desktop` | 1440 × 900 | 1   | no  |

Un viewport personalizado tiene un ancho y un alto de 200 a 4096 px, y opcionalmente una densidad de píxeles, modo táctil, un user agent y un nombre. Dentro de Astral, el panel de la pestaña se redimensiona al viewport durante la ejecución y después recupera su tamaño; la densidad de píxeles, el modo táctil y el user agent no se emulan allí, y la ejecución lo indica. El runner headless con Chrome los emula todos.

## La comprobación de layout

La comprobación de layout examina la página tal como se renderiza e informa de hallazgos, cada uno con una regla, una gravedad, un selector, un rectángulo, un mensaje y una corrección CSS sugerida.

| Regla | Qué detecta |
| --- | --- |
| `horizontal-overflow` | La página es más ancha que el viewport; indica el elemento que se sale. |
| `overlap` | Texto o controles visibles superpuestos. |
| `text-clipped` | Texto cortado por desbordamiento, o una palabra larga que se sale de su caja. |
| `offscreen` | Un control fuera del viewport horizontal. |
| `tap-target` | Un objetivo táctil de menos de 24 × 24 px es un error; de menos de 44 × 44, una advertencia. Solo en viewports táctiles. |
| `small-text` | Texto de menos de 12 px en pantallas de hasta 600 px de ancho. |

Tres formas de usarla:

- La herramienta [`layout_check`](https://astrallab.dev/es/docs/tools.md#tool-layout_check): el agente encuentra un problema, corrige el CSS y vuelve a comprobar.
- `astral.expect.layout()` como un paso de una prueba.
- `layoutCheck: true` en una prueba o colección, para añadir una comprobación al final de cada ejecución por viewport.

```json
{
  "collections": {
    "rwd": { "name": "Responsive", "tests": ["home", "checkout"], "viewports": ["mobile", "tablet", "desktop"], "layoutCheck": true }
  },
  "layout": { "ignore": [".chat-widget", "#cookie-banner"] }
}
```

Con una captura, la página se captura con cada hallazgo resaltado. En un motor que no maqueta las páginas, la comprobación se informa como omitida, nunca como superada.

## Reproducir con Reproducir

El agente llama a `test_open_in_astral` y Astral abre su panel Pruebas con la prueba cargada y en pausa. Pulsas **Reproducir** para verla ejecutarse: cámara lenta, pausa, paso a paso y detener. Por defecto, el agente no puede iniciarla: Reproducir es también un control de seguridad. Para demos y revisiones que le has pedido dirigir, el agente puede iniciarla con `play: true`; eso requiere el mismo permiso que `test_run`, funciona solo con pruebas guardadas en un proyecto que has permitido, y tú conservas Pausa, Paso y Detener.
