Docs: Saved tests

View as Markdown

Saved tests

A flow an agent has tested can be kept as a saved test: a script plus a few details (name, ticket, environment, credentials it uses, record mode). Any agent can replay it, you can watch it, and CI can run it.

Where tests live

  • Project tests are saved in .astral/tests/<id>.astral.js inside your project and versioned with your repository. The id is a slug of the test's name.
  • Temporary tests are kept in Astral's data folder and expire after a number of days (7 by default).

The agent saves one with test_save and can link it to a ticket. A saved test replays the script, not the model, so a replay spends no model tokens and runs the same steps every time.

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

The project's .astral/config.json declares the environments your tests run against and the credentials they may use, by name. Tests navigate with astral.url('/login'), so the same test runs against local, staging or production.

{
  "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": "[email protected]",
      "password": { "keychain": "shop.demo.password" }
    }
  }
}
KeyWhat it is
envsNamed base URLs. protected: true marks an environment such as production. No user name or password in the URL.
defaultEnvThe environment used when none is given.
collectionsTests run in order as one group, with a pass or fail summary and a report linking each test's.
credentialsNamed logins: a username, a password, a one-time-code seed and extra fields. Secrets are references, never values.
layoutSelectors the layout check ignores and its thresholds.

Credentials and the keychain

A secret in config.json is a reference to where it lives, never the value. A plain-text password in the file is rejected. A reference is one of:

{ "keychain": "<id>" }
{ "env": "ASTRAL_TEST_<NAME>" }
{ "local": "<key>" }
ReferenceWhere the value is
keychainYour system keychain. You set it in Astral; an agent can never read it back.
envAn environment variable whose name starts with ASTRAL_TEST_.
local.astral/secrets.local.json, which must be in .gitignore. Astral refuses to create it otherwise and warns if it already exists unignored.
  • The agent only ever sees the credential's name and username. astral.fill resolves the value itself and types it with real key strokes; the agent only learns that it was typed and masked.
  • A secret is typed only into a sensitive field (password, one-time code, card) on the environment's own origin, so it cannot be read back or sent to another site. Reports show •••••• in its place.
  • A keychain secret is stored together with the environments' origins at that moment and only typed into those, even if config.json is edited later. For sensitive logins, prefer the keychain.

Protected environments

On an environment marked protected (production, say), only tests declared readOnly run, and only after a person approves that exact version of the test in Astral. An agent can ask for readOnly: true, but that is a request, not an approval: you approve it with Approve as read-only in the Tests panel, the approval is kept outside the project, and it is lost if the test is edited. In a collection, tests that are not approved are skipped with the reason.

Viewports

A test or a collection can run at one or several viewports, and Astral runs every test at each one.

PresetSize (CSS px)Pixel ratioTouch
mobile390 × 8443yes
tablet820 × 11802yes
desktop1440 × 9001no

A custom viewport has a width and a height from 200 to 4096 px, and optionally a pixel ratio, touch, a user agent and a name. Inside Astral the tab's panel is resized to the viewport for the run and given back its own size afterwards; pixel ratio, touch and user agent are not emulated there, and the run says so. The headless runner with Chrome emulates all of them.

The layout check

The layout check looks at the page as it is rendered and reports findings, each with a rule, a severity, a selector, a rectangle, a message and a suggested CSS fix.

RuleWhat it finds
horizontal-overflowThe page is wider than the viewport; it names the element that escapes.
overlapVisible text or controls on top of each other.
text-clippedText cut by overflow, or a long word spilling out of its box.
offscreenA control outside the horizontal viewport.
tap-targetA touch target under 24 × 24 px is an error; under 44 × 44, a warning. Touch viewports only.
small-textText under 12 px on screens up to 600 px wide.

Three ways to use it:

  • The layout_check tool: the agent finds a problem, fixes the CSS and checks again.
  • astral.expect.layout() as a step of a test.
  • layoutCheck: true on a test or collection, to add a check at the end of each viewport run.
{
  "collections": {
    "rwd": { "name": "Responsive", "tests": ["home", "checkout"], "viewports": ["mobile", "tablet", "desktop"], "layoutCheck": true }
  },
  "layout": { "ignore": [".chat-widget", "#cookie-banner"] }
}

With a screenshot, the page is captured with every finding outlined. On an engine that does not lay pages out the check is reported as skipped, never as passed.

Replay with Play

The agent calls test_open_in_astral and Astral opens its Tests panel with the test loaded and paused. You press Play to watch it run: slow motion, pause, step by step and stop. By default the agent cannot start it: Play is also a safety control. For demos and reviews you asked it to drive, the agent can start it with play: true; that needs the same permission as test_run, works only for tests saved in a project you have allowed, and you keep Pause, Step and Stop.