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 +129 -0
- package/README.md +2 -1
- package/dist-pkg/cli.js +132 -122
- package/package.json +1 -1
- package/skills/saffron/SKILL.md +2 -0
- package/skills/saffron/references/config.md +4 -1
- package/skills/saffron/references/syntax.md +54 -0
- package/templates/saucedemo/data/catalog.json +11 -0
- package/templates/saucedemo/features/shopping.saffron +9 -0
- package/textmate/saffron/syntaxes/saffron.tmLanguage.json +7 -2
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,
|