@overshift/sfs 1.1.0
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/README.md +215 -0
- package/dist/cli/coverage-output.d.ts +3 -0
- package/dist/cli/coverage-output.d.ts.map +1 -0
- package/dist/cli/coverage-output.js +74 -0
- package/dist/cli/coverage-output.js.map +1 -0
- package/dist/cli/coverage-types.d.ts +24 -0
- package/dist/cli/coverage-types.d.ts.map +1 -0
- package/dist/cli/coverage-types.js +2 -0
- package/dist/cli/coverage-types.js.map +1 -0
- package/dist/cli/coverage.d.ts +3 -0
- package/dist/cli/coverage.d.ts.map +1 -0
- package/dist/cli/coverage.js +69 -0
- package/dist/cli/coverage.js.map +1 -0
- package/dist/cli/init-templates.d.ts +5 -0
- package/dist/cli/init-templates.d.ts.map +1 -0
- package/dist/cli/init-templates.js +108 -0
- package/dist/cli/init-templates.js.map +1 -0
- package/dist/cli/init.d.ts +7 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +170 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/run.d.ts +3 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +58 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/story-extractor.d.ts +7 -0
- package/dist/cli/story-extractor.d.ts.map +1 -0
- package/dist/cli/story-extractor.js +130 -0
- package/dist/cli/story-extractor.js.map +1 -0
- package/dist/cli/validate.d.ts +2 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +39 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/executor/assertion-executor.d.ts +7 -0
- package/dist/executor/assertion-executor.d.ts.map +1 -0
- package/dist/executor/assertion-executor.js +206 -0
- package/dist/executor/assertion-executor.js.map +1 -0
- package/dist/executor/config-loader.d.ts +5 -0
- package/dist/executor/config-loader.d.ts.map +1 -0
- package/dist/executor/config-loader.js +48 -0
- package/dist/executor/config-loader.js.map +1 -0
- package/dist/executor/executor-types.d.ts +64 -0
- package/dist/executor/executor-types.d.ts.map +1 -0
- package/dist/executor/executor-types.js +6 -0
- package/dist/executor/executor-types.js.map +1 -0
- package/dist/executor/retry-handler.d.ts +7 -0
- package/dist/executor/retry-handler.d.ts.map +1 -0
- package/dist/executor/retry-handler.js +32 -0
- package/dist/executor/retry-handler.js.map +1 -0
- package/dist/executor/run-context.d.ts +27 -0
- package/dist/executor/run-context.d.ts.map +1 -0
- package/dist/executor/run-context.js +52 -0
- package/dist/executor/run-context.js.map +1 -0
- package/dist/executor/run-engine.d.ts +9 -0
- package/dist/executor/run-engine.d.ts.map +1 -0
- package/dist/executor/run-engine.js +140 -0
- package/dist/executor/run-engine.js.map +1 -0
- package/dist/executor/session-manager.d.ts +16 -0
- package/dist/executor/session-manager.d.ts.map +1 -0
- package/dist/executor/session-manager.js +103 -0
- package/dist/executor/session-manager.js.map +1 -0
- package/dist/executor/shell-executor.d.ts +12 -0
- package/dist/executor/shell-executor.d.ts.map +1 -0
- package/dist/executor/shell-executor.js +66 -0
- package/dist/executor/shell-executor.js.map +1 -0
- package/dist/executor/step-executor.d.ts +6 -0
- package/dist/executor/step-executor.d.ts.map +1 -0
- package/dist/executor/step-executor.js +73 -0
- package/dist/executor/step-executor.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/assertion-parser.d.ts +3 -0
- package/dist/parser/assertion-parser.d.ts.map +1 -0
- package/dist/parser/assertion-parser.js +92 -0
- package/dist/parser/assertion-parser.js.map +1 -0
- package/dist/parser/command-parser.d.ts +3 -0
- package/dist/parser/command-parser.d.ts.map +1 -0
- package/dist/parser/command-parser.js +252 -0
- package/dist/parser/command-parser.js.map +1 -0
- package/dist/parser/config-parser.d.ts +16 -0
- package/dist/parser/config-parser.d.ts.map +1 -0
- package/dist/parser/config-parser.js +217 -0
- package/dist/parser/config-parser.js.map +1 -0
- package/dist/parser/sfs-parser.d.ts +3 -0
- package/dist/parser/sfs-parser.d.ts.map +1 -0
- package/dist/parser/sfs-parser.js +184 -0
- package/dist/parser/sfs-parser.js.map +1 -0
- package/dist/parser/step-parser.d.ts +3 -0
- package/dist/parser/step-parser.d.ts.map +1 -0
- package/dist/parser/step-parser.js +72 -0
- package/dist/parser/step-parser.js.map +1 -0
- package/dist/parser/types.d.ts +115 -0
- package/dist/parser/types.d.ts.map +1 -0
- package/dist/parser/types.js +3 -0
- package/dist/parser/types.js.map +1 -0
- package/dist/utils/mcp-detector.d.ts +9 -0
- package/dist/utils/mcp-detector.d.ts.map +1 -0
- package/dist/utils/mcp-detector.js +62 -0
- package/dist/utils/mcp-detector.js.map +1 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# SFS (StoryFlowSteps)
|
|
2
|
+
|
|
3
|
+
An agent-oriented browser automation protocol for validating user story flows. SFS provides a high-level, natural language syntax for describing browser automation tests, designed to be executed by an AI agent using Playwright MCP.
|
|
4
|
+
|
|
5
|
+
## Key Features
|
|
6
|
+
|
|
7
|
+
- **Agent-Oriented Design** - Built for AI agents to understand context and make intelligent decisions
|
|
8
|
+
- **Flexible Selectors** - Supports explicit selectors with fuzzy fallback matching
|
|
9
|
+
- **User Story Traceability** - Each SFS file maps to a user story (US-XXX-001) for coverage tracking
|
|
10
|
+
- **Natural Language Syntax** - Commands read like human actions
|
|
11
|
+
- **Multi-Environment Config** - Environment layering for CI/staging/local
|
|
12
|
+
- **Persona Management** - Define user roles with environment-specific credentials
|
|
13
|
+
- **Lifecycle Hooks** - Complete session orchestration (before/after session, before/after each)
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @sfs/cli
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Requires Node.js >= 18.0.0
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
Initialize SFS in your project:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx sfs init
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This creates:
|
|
32
|
+
- `sfs.config.md` - Base configuration
|
|
33
|
+
- `example.sfs` - Example login flow
|
|
34
|
+
|
|
35
|
+
## CLI Commands
|
|
36
|
+
|
|
37
|
+
### Run SFS Flows
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx sfs run # Run all .sfs files
|
|
41
|
+
npx sfs run stories/US-SHOP-01a.sfs # Run specific file
|
|
42
|
+
npx sfs run "stories/**/*.sfs" # Run with glob pattern
|
|
43
|
+
npx sfs run --env ci # Use CI-specific config
|
|
44
|
+
npx sfs run --headed # Show browser GUI
|
|
45
|
+
npx sfs run --verbose # Verbose output
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Validate Syntax
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx sfs validate stories/US-SHOP-01a.sfs
|
|
52
|
+
npx sfs validate "stories/**/*.sfs"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Coverage Report
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx sfs coverage # Table format
|
|
59
|
+
npx sfs coverage --format json # JSON output
|
|
60
|
+
npx sfs coverage --format summary # Summary only
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## SFS File Syntax
|
|
64
|
+
|
|
65
|
+
```sfs
|
|
66
|
+
STORY US-LOGIN-01a
|
|
67
|
+
ENTRYPOINT http://localhost:3000
|
|
68
|
+
LOCALE en-US
|
|
69
|
+
|
|
70
|
+
HINT Standard login form with email and password fields
|
|
71
|
+
ON FAILURE capture screenshot and describe visible state
|
|
72
|
+
|
|
73
|
+
BEFORE THIS
|
|
74
|
+
ASSERT port 3000 is open
|
|
75
|
+
|
|
76
|
+
--- page-load ---
|
|
77
|
+
OBSERVE login form is visible
|
|
78
|
+
|
|
79
|
+
--- enter-credentials ---
|
|
80
|
+
TYPE "testuser@example.com" INTO email field >> selector:testid:email-input
|
|
81
|
+
TYPE "password123" INTO password field >> selector:testid:password-input
|
|
82
|
+
CAPTURE before-submit
|
|
83
|
+
|
|
84
|
+
--- submit-login ---
|
|
85
|
+
CLICK login button >> selector:testid:login-btn
|
|
86
|
+
WAIT FOR url contains /dashboard
|
|
87
|
+
|
|
88
|
+
--- verify-dashboard ---
|
|
89
|
+
OBSERVE dashboard content is visible
|
|
90
|
+
OBSERVE logout button is visible
|
|
91
|
+
|
|
92
|
+
DONE WHEN user is logged in and dashboard is visible
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Command Reference
|
|
96
|
+
|
|
97
|
+
| Category | Commands |
|
|
98
|
+
|----------|----------|
|
|
99
|
+
| **Interactions** | `CLICK`, `TYPE`, `SELECT`, `DOUBLE CLICK`, `HOVER`, `SCROLL TO`, `UPLOAD`, `PRESS`, `CLEAR` |
|
|
100
|
+
| **Navigation** | `NAVIGATE TO`, `WAIT FOR` |
|
|
101
|
+
| **Observations** | `OBSERVE`, `CAPTURE`, `READ ... INTO $var` |
|
|
102
|
+
| **Tabs** | `TAB EXPECT NEW`, `TAB SWITCH TO`, `TAB CLOSE`, `TAB COUNT IS` |
|
|
103
|
+
| **Dialogs** | `ACCEPT DIALOG`, `DISMISS DIALOG` |
|
|
104
|
+
| **Assertions** | `ASSERT port`, `ASSERT env`, `ASSERT file` |
|
|
105
|
+
|
|
106
|
+
### Selectors
|
|
107
|
+
|
|
108
|
+
Commands support explicit selectors with fuzzy fallback:
|
|
109
|
+
|
|
110
|
+
```sfs
|
|
111
|
+
CLICK login button # Fuzzy (agent resolves)
|
|
112
|
+
CLICK login button >> selector:testid:login-btn # Explicit with fallback
|
|
113
|
+
CLICK login button >> selector:css:.btn-login # CSS selector
|
|
114
|
+
CLICK login button >> selector:xpath://button[1] # XPath selector
|
|
115
|
+
CLICK login button >> selector:text:Log In # Text selector
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Configuration
|
|
119
|
+
|
|
120
|
+
### sfs.config.md
|
|
121
|
+
|
|
122
|
+
```markdown
|
|
123
|
+
# SFS Configuration
|
|
124
|
+
|
|
125
|
+
## Settings
|
|
126
|
+
|
|
127
|
+
| Setting | Value |
|
|
128
|
+
|---------|-------|
|
|
129
|
+
| ENTRYPOINT | http://localhost:3000 |
|
|
130
|
+
| LOCALE | en-US |
|
|
131
|
+
| TIMEOUT | 30s |
|
|
132
|
+
| ON FAILURE | capture screenshot |
|
|
133
|
+
| PRESERVE STATE ON FAILURE | true |
|
|
134
|
+
|
|
135
|
+
## Personas
|
|
136
|
+
|
|
137
|
+
| Persona | Username | Password | Description |
|
|
138
|
+
|---------|----------|----------|-------------|
|
|
139
|
+
| user | testuser@example.com | {{TEST_USER_PASSWORD}} | Standard user |
|
|
140
|
+
| admin | admin@example.com | {{ADMIN_PASSWORD}} | Administrator |
|
|
141
|
+
| guest | | | Unauthenticated |
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Environment Layering
|
|
145
|
+
|
|
146
|
+
Configuration files are merged in order:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
sfs.config.md → Base configuration
|
|
150
|
+
sfs.config.{env}.md → Environment-specific (ci, staging)
|
|
151
|
+
sfs.config.local.md → Local overrides (gitignored)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Project Structure
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
/stories/
|
|
158
|
+
sfs.config.md # Base config
|
|
159
|
+
sfs.config.ci.md # CI overrides
|
|
160
|
+
sfs.config.local.md # Local overrides (gitignored)
|
|
161
|
+
|
|
162
|
+
US-SHOP-01/
|
|
163
|
+
US-SHOP-01a.sfs # Primary flow
|
|
164
|
+
US-SHOP-01a.edge.sfs # Edge cases
|
|
165
|
+
|
|
166
|
+
/runs/ # Test output (gitignored)
|
|
167
|
+
2024-02-04T14-30-00/
|
|
168
|
+
run.report.md
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Development
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
npm install # Install dependencies
|
|
175
|
+
npm run dev # Run in development
|
|
176
|
+
npm run build # Build
|
|
177
|
+
npm test # Run tests
|
|
178
|
+
npm run lint # Lint
|
|
179
|
+
npm run format # Format
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Pre-commit Checks
|
|
183
|
+
|
|
184
|
+
This project uses a Definition of Done (DoD) quality gate that runs before each commit. The checks include:
|
|
185
|
+
|
|
186
|
+
**Critical (must pass):** build, test, lint, format
|
|
187
|
+
**Warnings (informational):** longfiles, knip, seccheck, audit
|
|
188
|
+
|
|
189
|
+
Run checks manually with npm scripts:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npm run dod # Run all checks (default)
|
|
193
|
+
npm run dod:all # Run all checks (explicit)
|
|
194
|
+
npm run dod:core # Run only critical checks (faster)
|
|
195
|
+
npm run dod:skip # Skip all checks
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Commit with check level control:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
npm run commit:check -- -m "message" # All checks (default)
|
|
202
|
+
npm run commit:check:all -- -m "message" # All checks (explicit)
|
|
203
|
+
npm run commit:check:core -- -m "message" # Core checks only
|
|
204
|
+
npm run commit:check:skip -- -m "message" # Skip DoD checks
|
|
205
|
+
git commit --no-verify -m "message" # Skip all hooks
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Documentation
|
|
209
|
+
|
|
210
|
+
- [SFS Language Specification](SFS-SPEC.md)
|
|
211
|
+
- [Configuration Specification](SFS-CONFIG-SPEC.md)
|
|
212
|
+
|
|
213
|
+
## License
|
|
214
|
+
|
|
215
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-output.d.ts","sourceRoot":"","sources":["../../src/cli/coverage-output.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAe1E"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
export function outputResults(result, format) {
|
|
3
|
+
switch (format) {
|
|
4
|
+
case "json":
|
|
5
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6
|
+
break;
|
|
7
|
+
case "summary":
|
|
8
|
+
outputSummary(result);
|
|
9
|
+
break;
|
|
10
|
+
case "table":
|
|
11
|
+
default:
|
|
12
|
+
outputTable(result);
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function outputSummary(result) {
|
|
17
|
+
const { stories, flows, covered, uncovered, coverage } = result;
|
|
18
|
+
console.log(`User Stories: ${stories.length}`);
|
|
19
|
+
console.log(`SFS Flows: ${flows.length}`);
|
|
20
|
+
console.log(`Covered: ${covered.length}`);
|
|
21
|
+
console.log(`Uncovered: ${uncovered.length}`);
|
|
22
|
+
console.log();
|
|
23
|
+
const coverageColor = coverage >= 80 ? chalk.green : coverage >= 50 ? chalk.yellow : chalk.red;
|
|
24
|
+
console.log(`Coverage: ${coverageColor(`${coverage.toFixed(1)}%`)}`);
|
|
25
|
+
}
|
|
26
|
+
function outputTable(result) {
|
|
27
|
+
const { stories, flows, covered, uncovered, coverage } = result;
|
|
28
|
+
console.log(chalk.bold("Summary"));
|
|
29
|
+
console.log(` User Stories: ${stories.length}`);
|
|
30
|
+
console.log(` SFS Flows: ${flows.length}`);
|
|
31
|
+
console.log();
|
|
32
|
+
if (stories.length > 0) {
|
|
33
|
+
console.log(chalk.bold("Coverage by Story"));
|
|
34
|
+
console.log();
|
|
35
|
+
console.log("| Story ID | Title | Source | Status | Flows |");
|
|
36
|
+
console.log("|----------|-------|--------|--------|-------|");
|
|
37
|
+
for (const story of stories) {
|
|
38
|
+
const storyFlows = flows.filter((f) => f.storyId === story.id);
|
|
39
|
+
const status = storyFlows.length > 0
|
|
40
|
+
? chalk.green("✓ Covered")
|
|
41
|
+
: chalk.red("✗ Missing");
|
|
42
|
+
const flowCount = storyFlows.length > 0 ? storyFlows.length.toString() : "0";
|
|
43
|
+
const title = story.title ? truncate(story.title, 30) : "-";
|
|
44
|
+
const source = story.source === "single" ? "file" : "multi";
|
|
45
|
+
console.log(`| ${story.id} | ${title} | ${source} | ${status} | ${flowCount} |`);
|
|
46
|
+
}
|
|
47
|
+
console.log();
|
|
48
|
+
}
|
|
49
|
+
if (uncovered.length > 0) {
|
|
50
|
+
console.log(chalk.bold.red("Uncovered Stories"));
|
|
51
|
+
for (const id of uncovered) {
|
|
52
|
+
const story = stories.find((s) => s.id === id);
|
|
53
|
+
console.log(chalk.red(` ✗ ${id}${story?.title ? ` - ${story.title}` : ""}`));
|
|
54
|
+
}
|
|
55
|
+
console.log();
|
|
56
|
+
}
|
|
57
|
+
const orphanFlows = flows.filter((f) => !stories.some((s) => s.id === f.storyId));
|
|
58
|
+
if (orphanFlows.length > 0) {
|
|
59
|
+
console.log(chalk.bold.yellow("Flows without matching user stories"));
|
|
60
|
+
for (const flow of orphanFlows) {
|
|
61
|
+
console.log(chalk.yellow(` ⚠ ${flow.path} (STORY ${flow.storyId})`));
|
|
62
|
+
}
|
|
63
|
+
console.log();
|
|
64
|
+
}
|
|
65
|
+
const coverageColor = coverage >= 80 ? chalk.green : coverage >= 50 ? chalk.yellow : chalk.red;
|
|
66
|
+
console.log(chalk.bold("Overall Coverage"));
|
|
67
|
+
console.log(` ${coverageColor(`${coverage.toFixed(1)}%`)} (${covered.length}/${stories.length} stories)`);
|
|
68
|
+
}
|
|
69
|
+
function truncate(str, maxLen) {
|
|
70
|
+
if (str.length <= maxLen)
|
|
71
|
+
return str;
|
|
72
|
+
return str.slice(0, maxLen - 3) + "...";
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=coverage-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-output.js","sourceRoot":"","sources":["../../src/cli/coverage-output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface CoverageOptions {
|
|
2
|
+
stories?: string;
|
|
3
|
+
sfs?: string;
|
|
4
|
+
format?: "table" | "json" | "summary";
|
|
5
|
+
}
|
|
6
|
+
export interface UserStory {
|
|
7
|
+
id: string;
|
|
8
|
+
title?: string;
|
|
9
|
+
path: string;
|
|
10
|
+
source: "single" | "multi";
|
|
11
|
+
}
|
|
12
|
+
export interface SfsFlow {
|
|
13
|
+
storyId: string;
|
|
14
|
+
path: string;
|
|
15
|
+
name: string;
|
|
16
|
+
}
|
|
17
|
+
export interface CoverageResult {
|
|
18
|
+
stories: UserStory[];
|
|
19
|
+
flows: SfsFlow[];
|
|
20
|
+
covered: string[];
|
|
21
|
+
uncovered: string[];
|
|
22
|
+
coverage: number;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=coverage-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-types.d.ts","sourceRoot":"","sources":["../../src/cli/coverage-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-types.js","sourceRoot":"","sources":["../../src/cli/coverage-types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/cli/coverage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,qBAAqB,CAAC;AAU7B,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB7E"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { basename } from "path";
|
|
2
|
+
import { glob } from "glob";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { extractStoryIdFromFilename, extractStoryTitle, extractStoriesFromMultiFile, deduplicateStories, extractSfsStoryId, } from "./story-extractor.js";
|
|
5
|
+
import { outputResults } from "./coverage-output.js";
|
|
6
|
+
export async function coverageCommand(options) {
|
|
7
|
+
const storiesDir = options.stories ?? "stories";
|
|
8
|
+
const sfsPattern = options.sfs ?? "**/*.sfs";
|
|
9
|
+
const format = options.format ?? "table";
|
|
10
|
+
// Only show header for non-JSON formats
|
|
11
|
+
if (format !== "json") {
|
|
12
|
+
console.log(chalk.blue("SFS - User Story Coverage Report"));
|
|
13
|
+
console.log();
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const result = await calculateCoverage(storiesDir, sfsPattern);
|
|
17
|
+
outputResults(result, format);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.log(chalk.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function calculateCoverage(storiesDir, sfsPattern) {
|
|
25
|
+
const singleStoryFiles = await glob(`${storiesDir}/**/US-*.md`, {
|
|
26
|
+
ignore: ["**/node_modules/**", "**/*.sfs.md"],
|
|
27
|
+
});
|
|
28
|
+
const multiStoryFiles = await glob([
|
|
29
|
+
`${storiesDir}/**/*user-stories*.md`,
|
|
30
|
+
`${storiesDir}/**/*user.stories*.md`,
|
|
31
|
+
`${storiesDir}/**/*user_stories*.md`,
|
|
32
|
+
], {
|
|
33
|
+
ignore: ["**/node_modules/**"],
|
|
34
|
+
});
|
|
35
|
+
const sfsFiles = await glob(sfsPattern, {
|
|
36
|
+
ignore: ["**/node_modules/**"],
|
|
37
|
+
});
|
|
38
|
+
const stories = [];
|
|
39
|
+
for (const file of singleStoryFiles) {
|
|
40
|
+
const id = extractStoryIdFromFilename(file);
|
|
41
|
+
if (id) {
|
|
42
|
+
const title = await extractStoryTitle(file);
|
|
43
|
+
stories.push({ id, title, path: file, source: "single" });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (const file of multiStoryFiles) {
|
|
47
|
+
const multiStories = await extractStoriesFromMultiFile(file);
|
|
48
|
+
stories.push(...multiStories);
|
|
49
|
+
}
|
|
50
|
+
const uniqueStories = deduplicateStories(stories);
|
|
51
|
+
const flows = [];
|
|
52
|
+
for (const file of sfsFiles) {
|
|
53
|
+
const storyId = await extractSfsStoryId(file);
|
|
54
|
+
if (storyId) {
|
|
55
|
+
flows.push({
|
|
56
|
+
storyId,
|
|
57
|
+
path: file,
|
|
58
|
+
name: basename(file, ".sfs"),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const storyIds = new Set(uniqueStories.map((s) => s.id));
|
|
63
|
+
const coveredIds = new Set(flows.map((f) => f.storyId));
|
|
64
|
+
const covered = [...storyIds].filter((id) => coveredIds.has(id));
|
|
65
|
+
const uncovered = [...storyIds].filter((id) => !coveredIds.has(id));
|
|
66
|
+
const coverage = storyIds.size > 0 ? (covered.length / storyIds.size) * 100 : 100;
|
|
67
|
+
return { stories: uniqueStories, flows, covered, uncovered, coverage };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/cli/coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const CONFIG_TEMPLATE = "# SFS Configuration\n\n## Settings\n\n| Setting | Value |\n|---------|-------|\n| ENTRYPOINT | http://localhost:3000 |\n| LOCALE | en-US |\n| TIMEOUT | 30000 |\n| ON FAILURE | capture screenshot |\n| PRESERVE STATE ON FAILURE | true |\n\n## Hints\n\n- Add context about your application here\n- Describe the UI layout, navigation patterns\n- Note any authentication requirements\n- Mention relevant test data or fixtures\n\n## Personas\n\n| Persona | Username | Password | Description |\n|---------|----------|----------|-------------|\n| user | testuser@example.com | {{TEST_USER_PASSWORD}} | Standard user account |\n| admin | admin@example.com | {{ADMIN_PASSWORD}} | Administrator with full access |\n| guest | | | Unauthenticated visitor |\n\n## Before Session\n\n```sfs\n# Validate environment\nASSERT file .env exists\nASSERT env-check\n\n# Start services (uncomment as needed)\n# SHELL docker compose up -d\n# WAIT FOR http://localhost:3000 to respond\n```\n\n## After Session\n\n```sfs\n# Collect logs\nSHELL mkdir -p {{RUN_DIR}}\n# SHELL docker compose logs > {{RUN_DIR}}/docker.log\n```\n\n## Before Each\n\n```sfs\n# Reset browser state\nCLEAR cookies\nCLEAR local storage\n```\n\n## After Each\n\n```sfs\n# Log completion\nSHELL echo \"$(date): Completed {{SFS_NAME}}\" >> {{RUN_DIR}}/execution.log\n```\n";
|
|
2
|
+
export declare const EXAMPLE_SFS = "# example.sfs\n# Example: Basic page load verification\n\nSTORY EXAMPLE-001\nENTRYPOINT http://localhost:3000\nLOCALE en-US\n\nHINT Replace with your application context\nHINT Describe the page layout and key elements\n\nON FAILURE capture screenshot and describe visible state\n\nBEFORE THIS\n ASSERT port 3000 is open\n\n--- page-load ---\nAS user\nOBSERVE page has loaded\nOBSERVE main content is visible\n\n--- verify-elements ---\n# Add your verification steps here\nOBSERVE expected elements are present\n\nDONE WHEN page loaded successfully with expected content\n";
|
|
3
|
+
export declare const GITIGNORE_ADDITIONS = "\n# SFS local config (may contain sensitive paths/settings)\nsfs.config.local.md\n\n# SFS run outputs\n/runs/\n/stories/runs/\n*.report.md\n\n# Failure screenshots\n/failures/\n";
|
|
4
|
+
export declare const SFS_SKILLS: string[];
|
|
5
|
+
//# sourceMappingURL=init-templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-templates.d.ts","sourceRoot":"","sources":["../../src/cli/init-templates.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,0yCA6D3B,CAAC;AAEF,eAAO,MAAM,WAAW,4lBAyBvB,CAAC;AAEF,eAAO,MAAM,mBAAmB,sLAW/B,CAAC;AAEF,eAAO,MAAM,UAAU,UAMtB,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export const CONFIG_TEMPLATE = `# SFS Configuration
|
|
2
|
+
|
|
3
|
+
## Settings
|
|
4
|
+
|
|
5
|
+
| Setting | Value |
|
|
6
|
+
|---------|-------|
|
|
7
|
+
| ENTRYPOINT | http://localhost:3000 |
|
|
8
|
+
| LOCALE | en-US |
|
|
9
|
+
| TIMEOUT | 30000 |
|
|
10
|
+
| ON FAILURE | capture screenshot |
|
|
11
|
+
| PRESERVE STATE ON FAILURE | true |
|
|
12
|
+
|
|
13
|
+
## Hints
|
|
14
|
+
|
|
15
|
+
- Add context about your application here
|
|
16
|
+
- Describe the UI layout, navigation patterns
|
|
17
|
+
- Note any authentication requirements
|
|
18
|
+
- Mention relevant test data or fixtures
|
|
19
|
+
|
|
20
|
+
## Personas
|
|
21
|
+
|
|
22
|
+
| Persona | Username | Password | Description |
|
|
23
|
+
|---------|----------|----------|-------------|
|
|
24
|
+
| user | testuser@example.com | {{TEST_USER_PASSWORD}} | Standard user account |
|
|
25
|
+
| admin | admin@example.com | {{ADMIN_PASSWORD}} | Administrator with full access |
|
|
26
|
+
| guest | | | Unauthenticated visitor |
|
|
27
|
+
|
|
28
|
+
## Before Session
|
|
29
|
+
|
|
30
|
+
\`\`\`sfs
|
|
31
|
+
# Validate environment
|
|
32
|
+
ASSERT file .env exists
|
|
33
|
+
ASSERT env-check
|
|
34
|
+
|
|
35
|
+
# Start services (uncomment as needed)
|
|
36
|
+
# SHELL docker compose up -d
|
|
37
|
+
# WAIT FOR http://localhost:3000 to respond
|
|
38
|
+
\`\`\`
|
|
39
|
+
|
|
40
|
+
## After Session
|
|
41
|
+
|
|
42
|
+
\`\`\`sfs
|
|
43
|
+
# Collect logs
|
|
44
|
+
SHELL mkdir -p {{RUN_DIR}}
|
|
45
|
+
# SHELL docker compose logs > {{RUN_DIR}}/docker.log
|
|
46
|
+
\`\`\`
|
|
47
|
+
|
|
48
|
+
## Before Each
|
|
49
|
+
|
|
50
|
+
\`\`\`sfs
|
|
51
|
+
# Reset browser state
|
|
52
|
+
CLEAR cookies
|
|
53
|
+
CLEAR local storage
|
|
54
|
+
\`\`\`
|
|
55
|
+
|
|
56
|
+
## After Each
|
|
57
|
+
|
|
58
|
+
\`\`\`sfs
|
|
59
|
+
# Log completion
|
|
60
|
+
SHELL echo "$(date): Completed {{SFS_NAME}}" >> {{RUN_DIR}}/execution.log
|
|
61
|
+
\`\`\`
|
|
62
|
+
`;
|
|
63
|
+
export const EXAMPLE_SFS = `# example.sfs
|
|
64
|
+
# Example: Basic page load verification
|
|
65
|
+
|
|
66
|
+
STORY EXAMPLE-001
|
|
67
|
+
ENTRYPOINT http://localhost:3000
|
|
68
|
+
LOCALE en-US
|
|
69
|
+
|
|
70
|
+
HINT Replace with your application context
|
|
71
|
+
HINT Describe the page layout and key elements
|
|
72
|
+
|
|
73
|
+
ON FAILURE capture screenshot and describe visible state
|
|
74
|
+
|
|
75
|
+
BEFORE THIS
|
|
76
|
+
ASSERT port 3000 is open
|
|
77
|
+
|
|
78
|
+
--- page-load ---
|
|
79
|
+
AS user
|
|
80
|
+
OBSERVE page has loaded
|
|
81
|
+
OBSERVE main content is visible
|
|
82
|
+
|
|
83
|
+
--- verify-elements ---
|
|
84
|
+
# Add your verification steps here
|
|
85
|
+
OBSERVE expected elements are present
|
|
86
|
+
|
|
87
|
+
DONE WHEN page loaded successfully with expected content
|
|
88
|
+
`;
|
|
89
|
+
export const GITIGNORE_ADDITIONS = `
|
|
90
|
+
# SFS local config (may contain sensitive paths/settings)
|
|
91
|
+
sfs.config.local.md
|
|
92
|
+
|
|
93
|
+
# SFS run outputs
|
|
94
|
+
/runs/
|
|
95
|
+
/stories/runs/
|
|
96
|
+
*.report.md
|
|
97
|
+
|
|
98
|
+
# Failure screenshots
|
|
99
|
+
/failures/
|
|
100
|
+
`;
|
|
101
|
+
export const SFS_SKILLS = [
|
|
102
|
+
"from-user-story-to-sfs.md",
|
|
103
|
+
"write-sfs-session-reports.md",
|
|
104
|
+
"read-sfs-session-reports.md",
|
|
105
|
+
"validate-sfs-syntax.md",
|
|
106
|
+
"run-sfs-session.md",
|
|
107
|
+
];
|
|
108
|
+
//# sourceMappingURL=init-templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-templates.js","sourceRoot":"","sources":["../../src/cli/init-templates.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6D9B,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;CAyB1B,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;CAWlC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,2BAA2B;IAC3B,8BAA8B;IAC9B,6BAA6B;IAC7B,wBAAwB;IACxB,oBAAoB;CACrB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAkBA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqErE"}
|