# Scenario execution When a scenario is run, the scheduler creates a `ScenarioRun` with one `ScenarioRunStep` per step. Steps are executed **in order** (by `step.order`), one per scheduler tick. **All steps in the same run share a single Playwright browser instance.** The browser is created on the first `exec` or `sign` step (using session cookies + localStorage), reused for every subsequent step, and closed when the run finishes (pass or fail). ## Step types ### `login` Authenticates in a **separate, ephemeral browser** and saves the resulting session to the database. Subsequent exec/sign steps load that session into the shared browser. `execCode` must be a JSON object: ```json { "keyId": "3137411915", "environmentName": "liquio-diia-stg" } ``` ### `exec` Runs arbitrary Playwright JS on the **shared page**. The page carries over state from the previous step (URL, form inputs, cookies, etc.). `execCode` is executed as the body of an `async` function with these variables in scope: - `page` — current Playwright `Page` - `context` — current Playwright `BrowserContext` - `helpers.dumpDom(selector?)` — returns a simplified DOM string - `helpers.getStepOutput(order)` — returns the JSON-parsed `output` of a previous step. Positive values are absolute step orders; negative values are relative to the current step (`-1` = previous step). Any value returned from `execCode` is JSON-serialised and stored as the `output` field on the `ScenarioRunStep` record. Subsequent steps can read it via `helpers.getStepOutput()`. ```js // example execCode await page.goto('https://cabinet.example.com/tasks/create/987825'); await page.locator('input[name="institution"]').fill('caltech'); await page.locator('button:has-text("Далі")').click(); await page.waitForLoadState('networkidle'); return page.url(); // stored in ScenarioRunStep.output ``` ### `sign` Performs EDS signing on the **current shared page** using a key from `KEYS_DIR`. The step clicks the sign widget, selects the file key method, uploads the key file, enters the password, and submits — all without requiring the step author to handle key material in their code. `execCode` must be a JSON object: ```json { "keyId": "3137411915" } ``` ## Validation code Any step type optionally accepts `validateCode` — Playwright JS that runs on the shared page **after** the main action and must return a result evaluated as: ```js return { success: true, description: 'Application created' }; // or return { success: false, description: 'Expected success banner not found' }; // or simply return someBoolean; ``` If `success` is false the step (and the whole run) fails with the provided `description`. ## Run statuses `pending` → `in_progress` → `pass` | `fail` Individual step runs also expose `waiting` (not yet reached) and `cancelled` (run failed before this step). ## Adding a new scenario (example workflow) ``` 1. create_environment (if not already present) 2. create_scenario → get scenarioId 3. create_scenario_step type=login, order=0 4. create_scenario_step type=exec, order=1 (navigate + fill form) 5. create_scenario_step type=sign, order=2 6. create_scenario_step type=exec, order=3 (validateCode checks success banner) 7. run_scenario → get runId 8. wait_for_scenario_run (blocks until pass/fail, returns full run with outputs) ```