@anselmdk/feature-spec-md 0.6.2 → 0.7.0-rc.2
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 +63 -16
- package/SPEC_FORMAT.md +117 -0
- package/dist/githubActionDiffReport.js +16 -26
- package/dist/githubActionDiffReport.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mockReports.js +7 -4
- package/dist/mockReports.js.map +1 -1
- package/dist/playwright.d.ts +3 -3
- package/dist/playwright.d.ts.map +1 -1
- package/dist/playwright.js +62 -15
- package/dist/playwright.js.map +1 -1
- package/dist/reportTemplate.d.ts.map +1 -1
- package/dist/reportTemplate.js +222 -98
- package/dist/reportTemplate.js.map +1 -1
- package/dist/screenshots.d.ts +1 -3
- package/dist/screenshots.d.ts.map +1 -1
- package/dist/screenshots.js +20 -23
- package/dist/screenshots.js.map +1 -1
- package/dist/types.d.ts +24 -23
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/mocks/current/screenshots/screenshots.json +19 -1
- package/src/mocks/current/specs/support-desk.model.md +22 -1
- package/src/mocks/previous/screenshots/screenshots.json +10 -1
package/dist/screenshots.js
CHANGED
|
@@ -1,42 +1,36 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Screenshot evidence manifest loading and normalization for generated spec
|
|
3
|
-
* implementation reports.
|
|
4
|
-
*/
|
|
5
1
|
import { readFile } from "node:fs/promises";
|
|
6
2
|
import { expandArtifactPatterns } from "./filePatterns.js";
|
|
7
|
-
/** Load screenshot evidence manifests and normalize entries for report rendering. */
|
|
8
3
|
export async function collectSpecScreenshots(patterns) {
|
|
9
|
-
const
|
|
4
|
+
const evidence = [];
|
|
10
5
|
for (const file of await expandArtifactPatterns(patterns)) {
|
|
11
6
|
const parsed = JSON.parse(await readFile(file, "utf8"));
|
|
12
|
-
const entries = Array.isArray(parsed)
|
|
13
|
-
? parsed
|
|
7
|
+
const entries = isRecord(parsed) && Array.isArray(parsed.evidence)
|
|
8
|
+
? parsed.evidence
|
|
14
9
|
: isRecord(parsed) && Array.isArray(parsed.screenshots)
|
|
15
10
|
? parsed.screenshots
|
|
16
11
|
: [];
|
|
17
12
|
for (const entry of entries) {
|
|
18
|
-
const
|
|
19
|
-
if (
|
|
20
|
-
|
|
13
|
+
const normalized = normalizeEvidence(entry);
|
|
14
|
+
if (normalized)
|
|
15
|
+
evidence.push(normalized);
|
|
21
16
|
}
|
|
22
17
|
}
|
|
23
|
-
return
|
|
18
|
+
return evidence;
|
|
24
19
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const screenshotKeys = new Set(screenshots.map((screenshot) => screenshotKey(screenshot.specPath, screenshot.line)));
|
|
20
|
+
export function validateScenarioScreenshots(specs, evidence) {
|
|
21
|
+
const evidenceKeys = new Set(evidence.map((entry) => screenshotKey(entry.specPath, entry.line)));
|
|
28
22
|
const issues = [];
|
|
29
23
|
for (const spec of specs) {
|
|
30
24
|
for (const scenario of spec.scenarios) {
|
|
31
25
|
if (scenario.evidence.screenshots === "required") {
|
|
32
26
|
for (const step of scenario.steps) {
|
|
33
|
-
if (!
|
|
27
|
+
if (!evidenceKeys.has(screenshotKey(spec.filePath, step.line))) {
|
|
34
28
|
issues.push({
|
|
35
29
|
code: "missing-screenshot-evidence",
|
|
36
30
|
severity: "error",
|
|
37
31
|
filePath: spec.filePath,
|
|
38
32
|
line: step.line,
|
|
39
|
-
message: `
|
|
33
|
+
message: `Visual evidence is required for ${scenario.id} ${step.keyword} ${step.text}`,
|
|
40
34
|
});
|
|
41
35
|
}
|
|
42
36
|
}
|
|
@@ -51,23 +45,26 @@ export function screenshotKey(filePath, line) {
|
|
|
51
45
|
export function normalizeFilePath(filePath) {
|
|
52
46
|
return filePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
53
47
|
}
|
|
54
|
-
function
|
|
48
|
+
function normalizeEvidence(value) {
|
|
55
49
|
if (!isRecord(value))
|
|
56
50
|
return null;
|
|
57
51
|
const specPath = value.specPath;
|
|
58
52
|
const line = value.line;
|
|
53
|
+
const changed = value.changed;
|
|
59
54
|
const imagePath = value.path ?? value.imagePath;
|
|
60
|
-
if (typeof specPath !== "string" ||
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
if (typeof specPath !== "string" || typeof line !== "number")
|
|
56
|
+
return null;
|
|
57
|
+
const changedValue = typeof changed === "boolean" ? changed : true;
|
|
58
|
+
if (changedValue && typeof imagePath !== "string")
|
|
63
59
|
return null;
|
|
64
|
-
}
|
|
65
60
|
return {
|
|
66
61
|
specPath: normalizeFilePath(specPath),
|
|
67
62
|
line,
|
|
68
|
-
|
|
63
|
+
changed: changedValue,
|
|
64
|
+
path: typeof imagePath === "string" ? imagePath : undefined,
|
|
69
65
|
title: typeof value.title === "string" ? value.title : undefined,
|
|
70
66
|
testPath: typeof value.testPath === "string" ? value.testPath : undefined,
|
|
67
|
+
comparedWithLine: typeof value.comparedWithLine === "number" ? value.comparedWithLine : undefined,
|
|
71
68
|
};
|
|
72
69
|
}
|
|
73
70
|
function isRecord(value) {
|
package/dist/screenshots.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshots.js","sourceRoot":"","sources":["../src/screenshots.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"screenshots.js","sourceRoot":"","sources":["../src/screenshots.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,33 +1,45 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared TypeScript types for parsed spec documents, validation issues,
|
|
3
|
-
* coverage summaries, test references, and screenshot evidence.
|
|
4
|
-
*/
|
|
5
|
-
/** Shared frontmatter fields supported by all spec documents. */
|
|
6
1
|
export type SpecFrontmatter = {
|
|
7
2
|
id: string;
|
|
8
3
|
title: string;
|
|
9
4
|
status?: "draft" | "active" | "deprecated";
|
|
10
5
|
owner?: string;
|
|
11
6
|
};
|
|
12
|
-
/** Frontmatter fields supported by documents that may reference models. */
|
|
13
7
|
export type ModelReferenceFrontmatter = SpecFrontmatter & {
|
|
14
8
|
model?: string;
|
|
15
9
|
models?: string[] | string;
|
|
16
10
|
};
|
|
11
|
+
export type SpecExtensionSection = {
|
|
12
|
+
title: string;
|
|
13
|
+
body: string;
|
|
14
|
+
line: number;
|
|
15
|
+
};
|
|
16
|
+
export type SpecExtensionSections = {
|
|
17
|
+
/** Mermaid overview diagrams that visualize model relationships. */
|
|
18
|
+
modelDiagram?: SpecExtensionSection;
|
|
19
|
+
/** Known unknowns, unresolved choices, or decisions that need a product answer. */
|
|
20
|
+
openQuestions?: SpecExtensionSection;
|
|
21
|
+
/** Assumptions the spec currently relies on until they are confirmed or replaced. */
|
|
22
|
+
assumptions?: SpecExtensionSection;
|
|
23
|
+
/** API endpoints, request/response contracts, auth requirements, and OpenAPI links. */
|
|
24
|
+
apiContract?: SpecExtensionSection;
|
|
25
|
+
/** Role/group capability matrix, permission rules, and access-control notes. */
|
|
26
|
+
permissions?: SpecExtensionSection;
|
|
27
|
+
/** Entity state machines, state transition rules, and lifecycle examples. */
|
|
28
|
+
lifecycle?: SpecExtensionSection;
|
|
29
|
+
/** Mock adapters, seeded data, fixed-time setup, and CI/e2e environment contracts. */
|
|
30
|
+
testEnvironment?: SpecExtensionSection;
|
|
31
|
+
};
|
|
17
32
|
export type ScenarioTestType = "unit" | "integration" | "playwright" | "manual" | "skip";
|
|
18
33
|
export type ScreenshotPolicy = "required" | "optional" | "skip";
|
|
19
34
|
export type ScenarioEvidencePolicy = {
|
|
20
35
|
test: ScenarioTestType;
|
|
21
36
|
screenshots: ScreenshotPolicy;
|
|
22
37
|
};
|
|
23
|
-
/** Frontmatter fields supported by `*.feature.md` files. */
|
|
24
38
|
export type FeatureFrontmatter = ModelReferenceFrontmatter & {
|
|
25
39
|
test?: ScenarioTestType;
|
|
26
40
|
screenshots?: ScreenshotPolicy;
|
|
27
41
|
};
|
|
28
|
-
/** Frontmatter fields supported by `*.design.md` files. */
|
|
29
42
|
export type DesignFrontmatter = ModelReferenceFrontmatter;
|
|
30
|
-
/** Parsed contents of one `*.model.md` file. */
|
|
31
43
|
export type ModelSpec = {
|
|
32
44
|
kind: "model";
|
|
33
45
|
filePath: string;
|
|
@@ -38,7 +50,6 @@ export type ModelSpec = {
|
|
|
38
50
|
rules: FeatureRule[];
|
|
39
51
|
source: string;
|
|
40
52
|
};
|
|
41
|
-
/** Parsed contents of one `*.feature.md` file. */
|
|
42
53
|
export type FeatureSpec = {
|
|
43
54
|
kind?: "feature";
|
|
44
55
|
filePath: string;
|
|
@@ -49,7 +60,6 @@ export type FeatureSpec = {
|
|
|
49
60
|
scenarios: FeatureScenario[];
|
|
50
61
|
source: string;
|
|
51
62
|
};
|
|
52
|
-
/** Parsed contents of one `*.stack.md` file. */
|
|
53
63
|
export type StackSpec = {
|
|
54
64
|
kind: "stack";
|
|
55
65
|
filePath: string;
|
|
@@ -63,7 +73,6 @@ export type StackSpec = {
|
|
|
63
73
|
rules: FeatureRule[];
|
|
64
74
|
source: string;
|
|
65
75
|
};
|
|
66
|
-
/** Parsed contents of one `*.design.md` file. */
|
|
67
76
|
export type DesignSpec = {
|
|
68
77
|
kind: "design";
|
|
69
78
|
filePath: string;
|
|
@@ -78,16 +87,13 @@ export type DesignSpec = {
|
|
|
78
87
|
rules: FeatureRule[];
|
|
79
88
|
source: string;
|
|
80
89
|
};
|
|
81
|
-
/** Any parsed spec document. */
|
|
82
90
|
export type SpecDocument = ModelSpec | FeatureSpec | StackSpec | DesignSpec;
|
|
83
|
-
/** A model concept declared in the `## Model` section. */
|
|
84
91
|
export type ModelItem = {
|
|
85
92
|
id: string;
|
|
86
93
|
title: string;
|
|
87
94
|
body: string;
|
|
88
95
|
line: number;
|
|
89
96
|
};
|
|
90
|
-
/** A rule declared in the `## Rules` section. */
|
|
91
97
|
export type FeatureRule = {
|
|
92
98
|
id: string;
|
|
93
99
|
text: string;
|
|
@@ -95,7 +101,6 @@ export type FeatureRule = {
|
|
|
95
101
|
strength: "required" | "recommended" | "optional" | "unspecified";
|
|
96
102
|
line: number;
|
|
97
103
|
};
|
|
98
|
-
/** A concrete example declared in the `## Scenarios` section. */
|
|
99
104
|
export type FeatureScenario = {
|
|
100
105
|
id: string;
|
|
101
106
|
title: string;
|
|
@@ -103,7 +108,6 @@ export type FeatureScenario = {
|
|
|
103
108
|
evidence: ScenarioEvidencePolicy;
|
|
104
109
|
steps: FeatureStep[];
|
|
105
110
|
};
|
|
106
|
-
/** A single Given / When / Then style step inside a scenario. */
|
|
107
111
|
export type FeatureStep = {
|
|
108
112
|
keyword: StepKeyword;
|
|
109
113
|
text: string;
|
|
@@ -111,7 +115,6 @@ export type FeatureStep = {
|
|
|
111
115
|
};
|
|
112
116
|
export type RuleKeyword = "MUST" | "MUST NOT" | "SHOULD" | "SHOULD NOT" | "MAY" | "OPTIONAL";
|
|
113
117
|
export type StepKeyword = "Given" | "When" | "Then" | "And" | "But";
|
|
114
|
-
/** Validation problem found in a spec, test reference, or report input. */
|
|
115
118
|
export type ValidationIssue = {
|
|
116
119
|
code: string;
|
|
117
120
|
severity: "error" | "warning";
|
|
@@ -119,7 +122,6 @@ export type ValidationIssue = {
|
|
|
119
122
|
filePath?: string;
|
|
120
123
|
line?: number;
|
|
121
124
|
};
|
|
122
|
-
/** A model item, rule, or scenario ID found in executable tests. */
|
|
123
125
|
export type TestReference = {
|
|
124
126
|
id: string;
|
|
125
127
|
filePath: string;
|
|
@@ -127,7 +129,6 @@ export type TestReference = {
|
|
|
127
129
|
kind: "model" | "rule" | "scenario";
|
|
128
130
|
source: "title" | "tag" | "covers" | "annotation" | "free-text";
|
|
129
131
|
};
|
|
130
|
-
/** Coverage state for one expected model item, rule, or scenario. */
|
|
131
132
|
export type CoverageItem = {
|
|
132
133
|
id: string;
|
|
133
134
|
title?: string;
|
|
@@ -136,7 +137,6 @@ export type CoverageItem = {
|
|
|
136
137
|
covered: boolean;
|
|
137
138
|
references: TestReference[];
|
|
138
139
|
};
|
|
139
|
-
/** Complete test coverage mapping for a set of spec documents. */
|
|
140
140
|
export type CoverageSummary = {
|
|
141
141
|
modelCoverage?: CoverageItem[];
|
|
142
142
|
ruleCoverage: CoverageItem[];
|
|
@@ -145,12 +145,13 @@ export type CoverageSummary = {
|
|
|
145
145
|
orphanRuleReferences: TestReference[];
|
|
146
146
|
orphanScenarioReferences: TestReference[];
|
|
147
147
|
};
|
|
148
|
-
/** Screenshot evidence associated with an exact spec line. */
|
|
149
148
|
export type SpecScreenshot = {
|
|
150
149
|
specPath: string;
|
|
151
150
|
line: number;
|
|
152
|
-
|
|
151
|
+
changed?: boolean;
|
|
152
|
+
path?: string;
|
|
153
153
|
title?: string;
|
|
154
154
|
testPath?: string;
|
|
155
|
+
comparedWithLine?: number;
|
|
155
156
|
};
|
|
156
157
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"evidence": [
|
|
3
3
|
{
|
|
4
4
|
"specPath": "src/mocks/current/specs/ticket-inbox.feature.md",
|
|
5
5
|
"line": 27,
|
|
6
|
+
"changed": true,
|
|
6
7
|
"path": "screenshots/SUPPORT-INBOX-S001-line-27-current.svg",
|
|
7
8
|
"title": "Inbox with priority badges",
|
|
8
9
|
"testPath": "src/mocks/current/tests/supportDesk.spec.ts"
|
|
9
10
|
},
|
|
11
|
+
{
|
|
12
|
+
"specPath": "src/mocks/current/specs/ticket-inbox.feature.md",
|
|
13
|
+
"line": 28,
|
|
14
|
+
"changed": false,
|
|
15
|
+
"title": "Inbox remains visually unchanged after selecting the first ticket",
|
|
16
|
+
"testPath": "src/mocks/current/tests/supportDesk.spec.ts",
|
|
17
|
+
"comparedWithLine": 27
|
|
18
|
+
},
|
|
10
19
|
{
|
|
11
20
|
"specPath": "src/mocks/current/specs/ticket-reply.feature.md",
|
|
12
21
|
"line": 27,
|
|
22
|
+
"changed": true,
|
|
13
23
|
"path": "screenshots/SUPPORT-REPLY-S001-line-27-current.svg",
|
|
14
24
|
"title": "Reply composer with suggested answer",
|
|
15
25
|
"testPath": "src/mocks/current/tests/supportDesk.spec.ts"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"specPath": "src/mocks/current/specs/ticket-reply.feature.md",
|
|
29
|
+
"line": 28,
|
|
30
|
+
"changed": false,
|
|
31
|
+
"title": "Reply composer stays visually unchanged while text is reviewed",
|
|
32
|
+
"testPath": "src/mocks/current/tests/supportDesk.spec.ts",
|
|
33
|
+
"comparedWithLine": 27
|
|
16
34
|
}
|
|
17
35
|
]
|
|
18
36
|
}
|
|
@@ -26,4 +26,25 @@ A visible urgency label used to sort the queue.
|
|
|
26
26
|
|
|
27
27
|
## Rules
|
|
28
28
|
|
|
29
|
-
- SUPPORT-M-R001: Tickets
|
|
29
|
+
- SUPPORT-M-R001: Tickets keep a stable public reference.
|
|
30
|
+
|
|
31
|
+
## Model Diagram
|
|
32
|
+
|
|
33
|
+
```mermaid
|
|
34
|
+
erDiagram
|
|
35
|
+
AGENT ||--o{ TICKET : handles
|
|
36
|
+
TICKET }o--|| PRIORITY : has
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Open Questions
|
|
40
|
+
|
|
41
|
+
- SUPPORT-Q001: Should permission tables have optional coverage checks later?
|
|
42
|
+
|
|
43
|
+
## Assumptions
|
|
44
|
+
|
|
45
|
+
- SUPPORT-A001: Review notes are shown in reports as informational context.
|
|
46
|
+
|
|
47
|
+
## Permissions
|
|
48
|
+
|
|
49
|
+
- Agents can view assigned tickets.
|
|
50
|
+
- Leads can reassign tickets.
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"evidence": [
|
|
3
3
|
{
|
|
4
4
|
"specPath": "src/mocks/previous/specs/ticket-inbox.feature.md",
|
|
5
5
|
"line": 27,
|
|
6
|
+
"changed": true,
|
|
6
7
|
"path": "screenshots/SUPPORT-INBOX-S001-line-27-previous.svg",
|
|
7
8
|
"title": "Inbox before priority badges",
|
|
8
9
|
"testPath": "src/mocks/previous/tests/supportDesk.spec.ts"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"specPath": "src/mocks/previous/specs/ticket-inbox.feature.md",
|
|
13
|
+
"line": 28,
|
|
14
|
+
"changed": false,
|
|
15
|
+
"title": "Inbox remains visually unchanged after selecting the first ticket",
|
|
16
|
+
"testPath": "src/mocks/previous/tests/supportDesk.spec.ts",
|
|
17
|
+
"comparedWithLine": 27
|
|
9
18
|
}
|
|
10
19
|
]
|
|
11
20
|
}
|