saffron-ai 0.4.2 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saffron-ai",
3
- "version": "0.4.2",
3
+ "version": "0.5.1",
4
4
  "description": "Gherkin-native AI-fallback test runner: zero-token cached replay, runtime AI healing, honest reports",
5
5
  "scripts": {
6
6
  "test": "vitest run",
@@ -8,7 +8,7 @@
8
8
  "dev": "tsc --watch",
9
9
  "e2e": "node scripts/e2e.mjs",
10
10
  "prepublishOnly": "npm run build && npm test && npm run bundle",
11
- "docs": "node scripts/build-docs.mjs",
11
+ "docs": "node scripts/build-docs.mjs && node scripts/build-site-docs.mjs",
12
12
  "bundle": "esbuild src/cli/index.ts --bundle --platform=node --format=esm --packages=external --minify --legal-comments=none --outfile=dist-pkg/cli.js"
13
13
  },
14
14
  "keywords": [
@@ -56,7 +56,9 @@
56
56
  "dist-pkg",
57
57
  "skills",
58
58
  "textmate",
59
+ "templates",
59
60
  "README.md",
61
+ "CHANGELOG.md",
60
62
  "LICENSE"
61
63
  ]
62
64
  }
@@ -59,7 +59,7 @@ your-project/
59
59
  | `saffron steps [search] [--json] [--snippets]` | The step vocabulary with recorded/divergent/unrecorded badges |
60
60
  | `saffron author <prose-file>` | Draft a `.saffron` file from plain-paragraph requirements using the project vocabulary |
61
61
  | `saffron mcp` / `saffron lsp` | Vocabulary for AI assistants / language server for editors |
62
- | `saffron init` | Install this skill into the project's agent directories and scaffold config |
62
+ | `saffron init [--examples]` | Install this skill into the project's agent directories, register MCP, scaffold config; `--examples` adds the Saucedemo example suite |
63
63
  | `saffron report` | Open the latest HTML report |
64
64
 
65
65
  Exit codes: 0 green/yellow, 1 red (or yellow with `--strict`), 2 usage /
@@ -0,0 +1,5 @@
1
+ # Saucedemo's public demo credentials. Copy this file to .env (git-ignored)
2
+ # or export the variables in your shell. Saffron resolves {env:VAR} tokens
3
+ # at replay and never writes the values into caches, proposals or reports.
4
+ SAUCE_USER=standard_user
5
+ SAUCE_PASSWORD=secret_sauce
@@ -0,0 +1,37 @@
1
+ Feature: Login
2
+
3
+ # Credentials come from the environment ({env:VAR}); they never land in
4
+ # caches, proposals or reports. See .env.example.
5
+
6
+ @smoke @login
7
+ Scenario: Successful login
8
+ Given I am on the login page
9
+ When I enter "{env:SAUCE_USER}" in the username field
10
+ And I enter "{env:SAUCE_PASSWORD}" in the password field
11
+ And I click the "Login" button
12
+ Then I should see the products page
13
+
14
+ @login
15
+ Scenario Outline: Login errors
16
+ Given I am on the login page
17
+ When I enter "<username>" in the username field
18
+ And I enter "<password>" in the password field
19
+ And I click the "Login" button
20
+ Then I should see the error message "<message>"
21
+
22
+ Examples:
23
+ | username | password | message |
24
+ | locked_out_user | secret_sauce | Epic sadface: Sorry, this user has been locked out. |
25
+ | standard_user | wrong | Epic sadface: Username and password do not match |
26
+
27
+ @login @recover
28
+ Scenario: Recover from a locked-out login
29
+ # A StepSet in the middle of a scenario: the set's guard step takes the
30
+ # browser back to the login page before it logs the standard user in.
31
+ Given I am on the login page
32
+ When I enter "locked_out_user" in the username field
33
+ And I enter "secret_sauce" in the password field
34
+ And I click the "Login" button
35
+ Then I should see the error message "Epic sadface: Sorry, this user has been locked out."
36
+ StepSet Log in as the standard user
37
+ Then I should see the products page
@@ -0,0 +1,25 @@
1
+ Feature: Shared step sets for the Saucedemo example suite
2
+
3
+ # A sets-only library file: no scenarios, only StepSet definitions. Any
4
+ # .saffron file in the project invokes them with "StepSet <name>", at the
5
+ # start of a scenario or anywhere in the middle. Each set opens with a
6
+ # guard step and closes with an exit assertion, so every invocation checks
7
+ # itself.
8
+
9
+ StepSet: Log in as the standard user
10
+ Given I am on the login page
11
+ When I enter "{env:SAUCE_USER}" in the username field
12
+ And I enter "{env:SAUCE_PASSWORD}" in the password field
13
+ And I click the "Login" button
14
+ Then I should see the products page
15
+
16
+ StepSet: Proceed to checkout with the standard details
17
+ Given I am on the products page
18
+ When I open the cart
19
+ And I click the "Checkout" button
20
+ And I enter the following checkout information
21
+ | firstName | Ada |
22
+ | lastName | Lovelace |
23
+ | postalCode | 10117 |
24
+ And I click the "Continue" button
25
+ Then I should see the checkout overview
@@ -0,0 +1,20 @@
1
+ Feature: Shopping
2
+
3
+ # .saffron is Gherkin plus the StepSet keyword. The flows below are
4
+ # defined once in shared.steps.saffron; their steps are inlined at parse
5
+ # time, so they record once and replay everywhere.
6
+
7
+ @smoke @cart
8
+ Scenario: Add a product to the cart
9
+ StepSet Log in as the standard user
10
+ When I add "Sauce Labs Backpack" to the cart
11
+ Then the cart badge should show 1
12
+
13
+ @checkout
14
+ Scenario: Complete a checkout
15
+ StepSet Log in as the standard user
16
+ When I add "Sauce Labs Bike Light" to the cart
17
+ StepSet Proceed to checkout with the standard details
18
+ Then the overview should list "Sauce Labs Bike Light"
19
+ When I click the "Finish" button
20
+ Then I should see "Thank you for your order!"
@@ -0,0 +1,6 @@
1
+ {
2
+ "baseURL": "https://www.saucedemo.com",
3
+ "features": "features",
4
+ "retries": 1,
5
+ "strict": false
6
+ }
@@ -72,56 +72,78 @@
72
72
  "name": "keyword.control.stepset.saffron"
73
73
  },
74
74
  "2": {
75
- "name": "entity.name.function.stepset.saffron"
76
- }
77
- }
78
- },
79
- "step": {
80
- "match": "^\\s*(Given|When|Then|And|But|\\*)\\s(.*)$",
81
- "captures": {
82
- "1": {
83
- "name": "keyword.other.step.saffron"
84
- },
85
- "2": {
86
- "name": "string.unquoted.step-text.saffron",
75
+ "name": "entity.name.function.stepset.saffron",
87
76
  "patterns": [
88
77
  {
89
- "match": "\"[^\"]*\"",
90
- "name": "string.quoted.double.saffron"
78
+ "include": "#argument"
79
+ },
80
+ {
81
+ "include": "#placeholder"
91
82
  },
92
83
  {
93
- "match": "<[^<>]+>",
94
- "name": "variable.parameter.saffron"
84
+ "include": "#token"
95
85
  }
96
86
  ]
97
87
  }
98
88
  }
99
89
  },
90
+ "step": {
91
+ "begin": "^\\s*(Given|When|Then|And|But|\\*)\\b",
92
+ "beginCaptures": {
93
+ "1": {
94
+ "name": "keyword.other.step.saffron"
95
+ }
96
+ },
97
+ "end": "$",
98
+ "name": "meta.step.saffron",
99
+ "patterns": [
100
+ {
101
+ "include": "#argument"
102
+ },
103
+ {
104
+ "include": "#placeholder"
105
+ },
106
+ {
107
+ "include": "#token"
108
+ }
109
+ ]
110
+ },
100
111
  "docstring": {
101
112
  "begin": "^\\s*\"\"\"",
102
113
  "end": "^\\s*\"\"\"",
103
114
  "name": "string.quoted.docstring.saffron"
104
115
  },
105
116
  "table": {
106
- "match": "^\\s*\\|.*\\|\\s*$",
117
+ "begin": "^\\s*(?=\\|)",
118
+ "end": "$",
107
119
  "name": "meta.table.saffron",
108
- "captures": {
109
- "0": {
110
- "patterns": [
111
- {
112
- "match": "\\|",
113
- "name": "punctuation.separator.table.saffron"
114
- },
115
- {
116
- "match": "<[^<>]+>",
117
- "name": "variable.parameter.saffron"
118
- }
119
- ]
120
+ "patterns": [
121
+ {
122
+ "match": "\\|",
123
+ "name": "punctuation.separator.table.saffron"
124
+ },
125
+ {
126
+ "include": "#placeholder"
127
+ },
128
+ {
129
+ "include": "#token"
120
130
  }
121
- }
131
+ ]
132
+ },
133
+ "argument": {
134
+ "match": "\"[^\"]*\"",
135
+ "name": "string.quoted.double.argument.saffron"
136
+ },
137
+ "placeholder": {
138
+ "match": "<[^<>\\s]+>",
139
+ "name": "variable.parameter.placeholder.saffron"
140
+ },
141
+ "token": {
142
+ "match": "\\{(env:[A-Za-z_][A-Za-z0-9_]*|date(?:[+-]\\d+)?(?::[^}]+)?)\\}",
143
+ "name": "constant.other.token.saffron"
122
144
  }
123
145
  },
124
146
  "fileTypes": [
125
147
  "saffron"
126
148
  ]
127
- }
149
+ }