saffron-ai 0.7.2 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,135 @@ All notable changes to Saffron, in one place: the `saffron-ai` runner (npm),
4
4
  the VS Code extension (`ChathurangaJayasinghe.saffron-vscode`) and the
5
5
  JetBrains plugin (`ai.saffron.jetbrains`). Dates are publish dates.
6
6
 
7
+ ## 0.8.1
8
+
9
+ Released 2026-09-21.
10
+
11
+ Runner
12
+
13
+ - **Google Chrome and Microsoft Edge: `--browser chrome` and
14
+ `--browser msedge`.** Run on the branded browser your users actually
15
+ have, not only the open-source Chromium build. Both speak CDP, so
16
+ everything works there: replay, recording and healing. Recordings are the
17
+ same files, so a scenario recorded on `chromium` replays on `chrome` and
18
+ `msedge` and the other way round. Saffron uses the copy installed on the
19
+ machine; when it is missing the run stops before the first scenario, exit
20
+ code 2, and names the browser (`npx playwright install chrome` adds it on
21
+ a CI image). Also accepted as `browser` in the config.
22
+ - **Setup and teardown: `"setup"` and `"teardown"` in the config.** Shell
23
+ commands, one or a list, that Saffron runs once around a run, in the
24
+ project root: seed the data your scenarios read before any browser
25
+ opens, and clean up after the last scenario. A failed setup stops the
26
+ run with exit code 2 and no scenario runs. Teardown always runs: after
27
+ failures, after a failed setup, after Ctrl-C (which first stops a running
28
+ setup and waits for it, so nothing writes behind the cleanup). A failed teardown leaves
29
+ the verdicts alone and turns an otherwise green exit into 2, because what
30
+ it left behind is the next run's false red. The commands receive
31
+ `SAFFRON_BASE_URL` and `SAFFRON_ENV`. `--no-hooks` skips them,
32
+ `hookTimeoutMs` (default five minutes) bounds each one, and the report
33
+ lists every command with how it ended. With `{unique:name}` from 0.8.0
34
+ this makes a suite re-runnable and parallel-safe.
35
+
36
+ Fixes
37
+
38
+ - **Step reuse could bring back a stale data value.** When a `{data:...}`
39
+ value changed, the scenario's recording correctly went stale, but a new
40
+ recording could be seeded from that same recording's steps, putting the
41
+ old literal back under a fresh data snapshot, verified, at zero AI calls.
42
+ A step whose source recording still spells out a value that has since
43
+ changed is no longer reused.
44
+ - **`every {data:list}` counted hidden content as shown.** A value sitting
45
+ in a `hidden` or `display: none` element satisfied the check. The target
46
+ must now be visible, and only text the page actually shows counts. A
47
+ native `<select>` keeps its exception, since its options are never
48
+ visible while it is closed, but only when the select itself is visible.
49
+ Text is still compared as written, so CSS `text-transform` does not
50
+ change the result.
51
+ - **`{unique:name}` inside an Examples cell, a table cell or a doc string
52
+ reached the browser as the literal token.** Unique values were resolved
53
+ before parameters were substituted. They are now resolved in parameter
54
+ values too, with the same per-run seed, for values and locators alike.
55
+ - **`saffron prune` could list the screenshots of a live scenario as
56
+ orphaned** when its feature file is outside the configured directory and
57
+ the scenario has only ever failed, so no cache or proposal named the
58
+ file. Each screenshot folder now records which feature and scenario it
59
+ belongs to, prune reads it before judging, and the listing names what
60
+ the pictures were of.
61
+
62
+ Editors (VS Code extension 0.2.8)
63
+
64
+ - **VS Code ignored environment-specific CSV files.** With environment
65
+ `staging` and `roles.staging.csv`, `Examples: {data:roles}` was reported
66
+ as not resolving, or described from the base `roles.csv`. Diagnostics,
67
+ hover and go-to-definition now follow the runner: the environment's CSV
68
+ replaces the base one, and the hover names the file it read.
69
+
70
+ ## 0.8.0
71
+
72
+ Released 2026-09-21.
73
+
74
+ Test data moves out of the feature file: a `data/` folder, `{data:...}`
75
+ references, list checks, `Examples` from a file, values unique per run, and
76
+ data per environment.
77
+
78
+ Runner
79
+
80
+ - **Test data outside the feature file: `{data:file.key}`.** Put values in
81
+ JSON files under `data/` and reference them from a step, a table cell or
82
+ a doc string: `When I sign in as {data:users.admin.email}`. Same family
83
+ as `{env:VAR}`: the recording stores the token and replay reads the file,
84
+ so changing a value changes the next replay at zero tokens. A recording
85
+ that still spells out the old value goes stale instead of replaying
86
+ yesterday's data, and a missing file or key stops the run by name before
87
+ a browser opens. New config key `dataDir` (default `data`). Not for
88
+ secrets: data files are committed.
89
+ - **Check a whole list in one step.** `Then the status filter should list
90
+ every {data:enums.OrderStatus}` records ONE assertion (`expectEach`) that
91
+ names the list and its container. Replay reads the list from the file, so
92
+ a value added to the data is checked on the next run at zero tokens, and
93
+ a missing one fails by name with how many were found. Values match as
94
+ whole text ("Paid" is not "Unpaid"), extra entries such as "All" are
95
+ allowed, and a closed dropdown works.
96
+ - **`Examples` from a file**, in `.saffron` files: `Examples: {data:roles}`
97
+ reads `data/roles.csv` (header row = placeholders) or a JSON list of
98
+ records. One recording, one zero-token replay per row; a row added to the
99
+ file records nothing. A placeholder without a column, a missing file and a
100
+ `.feature` file using it are each parse errors that say what to do.
101
+ - **`{unique:name}`**: a value that is new on every run and the same within
102
+ one, for scenarios that create things. The agent types the generated
103
+ value while recording and Saffron turns it back into the token; a run that
104
+ is not green lists what each token stood for. `{unique:name:digits}` for
105
+ numeric fields.
106
+ - **Data per environment**: `--env staging` (or `SAFFRON_ENV`, or `env` in
107
+ the config) lays `data/users.staging.json` over `data/users.json`, key by
108
+ key. The reference in the step stays the same on every target.
109
+ - `saffron status --json` gains `data`: the folder, the environment, the
110
+ files, and references that do not resolve. `saffron lsp` completes
111
+ `{data:` paths, shows values on hover, jumps to the key and flags
112
+ unresolved references. The bundled grammar highlights `{data:...}` and
113
+ `{unique:...}`. `saffron init --examples` installs `data/catalog.json` and
114
+ a scenario that uses it, and the agent skill, its syntax reference and the
115
+ AGENTS.md block teach the new syntax.
116
+
117
+ - **`saffron prune` covers failure screenshots.** A deleted scenario also
118
+ leaves its screenshot folder behind under `.saffron/artifacts/`. Prune
119
+ lists those folders with the caches and proposals and removes them with
120
+ `--yes`; a live scenario's folder is kept, per Examples row. `saffron
121
+ status --json` reports them as orphans of kind `artifact`, and both IDE
122
+ panels (VS Code 0.2.7, JetBrains 0.2.4) show them.
123
+
124
+ Editors (VS Code extension 0.2.7, JetBrains plugin 0.2.4)
125
+
126
+ - **`{data:...}` in the editor.** VS Code completes data files and keys with
127
+ their values, shows the current value (or a list's values, or an Examples
128
+ file's columns) on hover, jumps to the key, and underlines a reference
129
+ that does not resolve, reading the same files and environment overlay the
130
+ runner does. JetBrains gets the same through `saffron lsp`. Both highlight
131
+ `{data:...}` and `{unique:...}` like `{env:VAR}`, including on an
132
+ `Examples:` line.
133
+ - Both Orphans lists show the screenshot folders of scenarios that no longer
134
+ exist, so "Remove All" never deletes something it did not show.
135
+
7
136
  ## 0.7.2
8
137
 
9
138
  Released 2026-09-21.
package/README.md CHANGED
@@ -72,7 +72,7 @@ node dist/cli/index.js -p examples accept --all
72
72
 
73
73
  | Command | What it does |
74
74
  |---|---|
75
- | `saffron run [paths] [--headed] [--filter @tags] [--rerecord] [--no-agent] [--strict] [--browser b] [--workers n] [--heal-model m] [--no-verify] [--no-reuse] [--model m] [--storage-state f]` | Run features. Cached replays are deterministic; misses/failures escalate to the agent (unless `--no-agent`). Replay cross-browser with `--browser firefox\|webkit`, parallelize with `--workers N`, heal on a cheaper model with `--heal-model`. Exit 1 on red (and on yellow with `--strict`). |
75
+ | `saffron run [paths] [--headed] [--filter @tags] [--rerecord] [--no-agent] [--strict] [--browser b] [--no-hooks] [--workers n] [--heal-model m] [--no-verify] [--no-reuse] [--model m] [--storage-state f]` | Run features. Cached replays are deterministic; misses/failures escalate to the agent (unless `--no-agent`). Replay cross-browser with `--browser firefox\|webkit`, parallelize with `--workers N`, heal on a cheaper model with `--heal-model`. Exit 1 on red (and on yellow with `--strict`). |
76
76
  | `saffron accept [files... \| --all] [--include-unverified] [--with-feature-edit] [--propagate]` | Promote cache proposals to committed caches (`--all` skips UNVERIFIED ones unless `--include-unverified`); `--with-feature-edit` also rewrites the adapted steps in the `.feature` file (and keeps the cache in sync); `--propagate` applies the heal's locator fixes to every other cache using the same locator. One heal repairs N scenarios before they ever fail. No args: list pending proposals. |
77
77
  | `saffron reject [files... \| --all]` | Discard proposals; the agent will try again next run. |
78
78
  | `saffron status [--json]` | Project overview for people, IDE panels and dashboards: feature files and scenarios with cache state, tags, pending proposals, last run, history, vocabulary health (divergent steps, duplicate wordings proven by identical recordings), effective config. |
@@ -89,6 +89,7 @@ Configuration lives in `saffron.config.json` at your project root:
89
89
  {
90
90
  "baseURL": "http://localhost:4173",
91
91
  "features": "features",
92
+ "dataDir": "data",
92
93
  "actionTimeoutMs": 5000,
93
94
  "pollIntervalMs": 100,
94
95
  "retries": 1,