@anselmdk/feature-spec-md 0.1.0 → 0.1.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/README.md CHANGED
@@ -31,6 +31,24 @@ See `SPEC_FORMAT.md` and `examples/account-access.feature.md`.
31
31
  npm install
32
32
  npm run dev -- check --specs "examples/**/*.feature.md" --tests "tests/**/*.test.ts" --require-scenario-coverage=false
33
33
  npm run dev -- report --specs "examples/**/*.feature.md" --tests "tests/**/*.test.ts"
34
+ npm run dev -- report --specs "examples/**/*.feature.md" --tests "tests/**/*.test.ts" --screenshots "test-results/spec-report/screenshots-*.json"
35
+ ```
36
+
37
+ Playwright screenshot evidence can be shown in the report by passing one or
38
+ more screenshot manifest JSON files. Each screenshot should point at the spec
39
+ file and line it proves:
40
+
41
+ ```json
42
+ {
43
+ "screenshots": [
44
+ {
45
+ "specPath": "specs/account-access.feature.md",
46
+ "line": 24,
47
+ "path": "screenshots/account-s001-line-24.png",
48
+ "title": "ACCOUNT-S001:24 Given a registered person is on the sign-in page"
49
+ }
50
+ ]
51
+ }
34
52
  ```
35
53
 
36
54
  ## Library API
@@ -52,3 +70,19 @@ npm test
52
70
  npm run typecheck
53
71
  npm run build
54
72
  ```
73
+
74
+ ## Releases
75
+
76
+ Stable releases are published to npm by the `Publish to npm` GitHub Actions workflow when a `v*` tag is pushed, or when the workflow is run manually.
77
+
78
+ Release candidates are published manually from GitHub Actions:
79
+
80
+ 1. Open the `Publish RC to npm` workflow.
81
+ 2. Run the workflow from `main`.
82
+ 3. The workflow verifies the package, creates a prerelease version using the current package version and GitHub run number, and publishes it with the npm `rc` dist-tag.
83
+
84
+ Install the latest release candidate with:
85
+
86
+ ```bash
87
+ npm install @anselmdk/feature-spec-md@rc
88
+ ```
package/SPEC_FORMAT.md CHANGED
@@ -103,3 +103,8 @@ Generated tooling can then answer:
103
103
  - Which rules have executable coverage?
104
104
  - Which tests reference deleted or unknown spec IDs?
105
105
  - Which visible flows have screenshots, traces, or other evidence?
106
+
107
+ For Playwright tests, capture one screenshot for each scenario step line in the
108
+ spec. Report manifests associate each screenshot with the exact spec file and
109
+ line number, so the HTML report can display the evidence beside the
110
+ Given / When / Then / And line it proves.
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { mkdir, writeFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { checkFeatureSpecs, renderHtmlReport, writeTextFile } from "./index.js";
4
+ import { checkFeatureSpecs, collectSpecScreenshots, renderHtmlReport, writeTextFile, } from "./index.js";
5
5
  const defaultSpecPattern = "specs/**/*.feature.md";
6
6
  const defaultTestPattern = "tests/**/*.spec.ts";
7
7
  main().catch((error) => {
@@ -42,8 +42,12 @@ async function runReport(options) {
42
42
  requireScenarioCoverage: false,
43
43
  });
44
44
  const out = options.out ?? "test-results/feature-spec-report/index.html";
45
+ const screenshots = options.screenshots
46
+ ? await collectSpecScreenshots(optionList(options.screenshots, ""))
47
+ : [];
45
48
  await writeTextFile(out, renderHtmlReport(result.specs, {
46
49
  coverage: result.coverage,
50
+ screenshots,
47
51
  validationIssues: [...result.validationIssues, ...result.coverageIssues],
48
52
  }));
49
53
  console.log(`Feature spec report written to ${out}`);
@@ -77,11 +81,16 @@ function parseArgs(args) {
77
81
  return options;
78
82
  }
79
83
  function optionList(value, fallback) {
80
- return (value ?? fallback).split(",").map((item) => item.trim()).filter(Boolean);
84
+ return (value ?? fallback)
85
+ .split(",")
86
+ .map((item) => item.trim())
87
+ .filter(Boolean);
81
88
  }
82
89
  function printIssues(issues) {
83
90
  for (const issue of issues) {
84
- const location = issue.filePath ? `${issue.filePath}${issue.line ? `:${issue.line}` : ""}` : "";
91
+ const location = issue.filePath
92
+ ? `${issue.filePath}${issue.line ? `:${issue.line}` : ""}`
93
+ : "";
85
94
  console.error(`${issue.severity.toUpperCase()} ${issue.code}${location ? ` ${location}` : ""}: ${issue.message}`);
86
95
  }
87
96
  }
@@ -91,11 +100,12 @@ function printHelp() {
91
100
  Usage:
92
101
  feature-spec-md init [--dir specs]
93
102
  feature-spec-md check [--specs "specs/**/*.feature.md"] [--tests "tests/**/*.spec.ts"]
94
- feature-spec-md report [--specs "specs/**/*.feature.md"] [--tests "tests/**/*.spec.ts"] [--out test-results/feature-spec-report/index.html]
103
+ feature-spec-md report [--specs "specs/**/*.feature.md"] [--tests "tests/**/*.spec.ts"] [--screenshots "test-results/spec-report/screenshots.json"] [--out test-results/feature-spec-report/index.html]
95
104
 
96
105
  Options:
97
106
  --require-rule-coverage Fail when rules have no matching test references.
98
107
  --require-scenario-coverage Defaults to true for check. Use --require-scenario-coverage=false to disable.
108
+ --screenshots Screenshot manifest JSON glob for report evidence.
99
109
  --tests "" Disable test coverage lookup.
100
110
  `);
101
111
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Expand user-provided source globs while ignoring generated directories. */
2
+ export declare function expandFilePatterns(patterns: string[]): Promise<string[]>;
3
+ /** Expand report artifact globs, including files under `test-results`. */
4
+ export declare function expandArtifactPatterns(patterns: string[]): Promise<string[]>;
5
+ //# sourceMappingURL=filePatterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filePatterns.d.ts","sourceRoot":"","sources":["../src/filePatterns.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,qBAO1D;AAED,0EAA0E;AAC1E,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,qBAE9D"}
@@ -0,0 +1,24 @@
1
+ import { glob } from "node:fs/promises";
2
+ /** Expand user-provided source globs while ignoring generated directories. */
3
+ export async function expandFilePatterns(patterns) {
4
+ return expandPatterns(patterns, [
5
+ "node_modules/**",
6
+ ".git/**",
7
+ "dist/**",
8
+ "test-results/**",
9
+ ]);
10
+ }
11
+ /** Expand report artifact globs, including files under `test-results`. */
12
+ export async function expandArtifactPatterns(patterns) {
13
+ return expandPatterns(patterns, ["node_modules/**", ".git/**", "dist/**"]);
14
+ }
15
+ async function expandPatterns(patterns, exclude) {
16
+ const files = new Set();
17
+ for (const pattern of patterns) {
18
+ for await (const file of glob(pattern, { exclude })) {
19
+ files.add(file);
20
+ }
21
+ }
22
+ return Array.from(files).sort();
23
+ }
24
+ //# sourceMappingURL=filePatterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filePatterns.js","sourceRoot":"","sources":["../src/filePatterns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAkB;IACzD,OAAO,cAAc,CAAC,QAAQ,EAAE;QAC9B,iBAAiB;QACjB,SAAS;QACT,SAAS;QACT,iBAAiB;KAClB,CAAC,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,QAAkB;IAC7D,OAAO,cAAc,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,QAAkB,EAAE,OAAiB;IACjE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACpD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC"}
package/dist/html.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function html(value: string): string;
2
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AAAA,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,UAOjC"}
package/dist/html.js ADDED
@@ -0,0 +1,9 @@
1
+ export function html(value) {
2
+ return value
3
+ .replace(/&/g, "&amp;")
4
+ .replace(/</g, "&lt;")
5
+ .replace(/>/g, "&gt;")
6
+ .replace(/\"/g, "&quot;")
7
+ .replace(/'/g, "&#039;");
8
+ }
9
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,IAAI,CAAC,KAAa;IAChC,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC;SACxB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,77 +1,28 @@
1
- export type FeatureSpec = {
2
- filePath: string;
3
- frontmatter: FeatureFrontmatter;
4
- title: string;
5
- purpose: string;
6
- rules: FeatureRule[];
7
- scenarios: FeatureScenario[];
8
- source: string;
9
- };
10
- export type FeatureFrontmatter = {
11
- id: string;
12
- title: string;
13
- status?: "draft" | "active" | "deprecated";
14
- owner?: string;
15
- };
16
- export type FeatureRule = {
17
- id: string;
18
- text: string;
19
- keyword?: RuleKeyword;
20
- strength: "required" | "recommended" | "optional" | "unspecified";
21
- line: number;
22
- };
23
- export type FeatureScenario = {
24
- id: string;
25
- title: string;
26
- line: number;
27
- steps: Array<{
28
- keyword: StepKeyword;
29
- text: string;
30
- line: number;
31
- }>;
32
- };
33
- export type RuleKeyword = "MUST" | "MUST NOT" | "SHOULD" | "SHOULD NOT" | "MAY" | "OPTIONAL";
34
- export type StepKeyword = "Given" | "When" | "Then" | "And" | "But";
35
- export type ValidationIssue = {
36
- code: string;
37
- severity: "error" | "warning";
38
- message: string;
39
- filePath?: string;
40
- line?: number;
41
- };
42
- export type TestReference = {
43
- id: string;
44
- filePath: string;
45
- line: number;
46
- kind: "scenario" | "rule";
47
- source: "title" | "tag" | "covers" | "annotation" | "free-text";
48
- };
49
- export type CoverageItem = {
50
- id: string;
51
- title?: string;
52
- filePath?: string;
53
- line?: number;
54
- covered: boolean;
55
- references: TestReference[];
56
- };
57
- export type CoverageSummary = {
58
- scenarioCoverage: CoverageItem[];
59
- ruleCoverage: CoverageItem[];
60
- orphanScenarioReferences: TestReference[];
61
- orphanRuleReferences: TestReference[];
62
- };
1
+ export { expandFilePatterns } from "./filePatterns.js";
2
+ export { renderHtmlReport } from "./reportTemplate.js";
3
+ export { collectSpecScreenshots } from "./screenshots.js";
4
+ export type { CoverageItem, CoverageSummary, FeatureFrontmatter, FeatureRule, FeatureScenario, FeatureSpec, FeatureStep, RuleKeyword, SpecScreenshot, StepKeyword, TestReference, ValidationIssue, } from "./types.js";
5
+ import type { CoverageSummary, FeatureSpec, TestReference, ValidationIssue } from "./types.js";
6
+ /** Parse one feature spec Markdown document into structured metadata, rules, and scenarios. */
63
7
  export declare function parseFeatureSpec(source: string, options?: {
64
8
  filePath?: string;
65
9
  }): FeatureSpec;
10
+ /** Validate spec structure, ID prefixes, duplicate IDs, and required sections. */
66
11
  export declare function validateFeatureSpec(spec: FeatureSpec): ValidationIssue[];
12
+ /** Find rule and scenario IDs referenced by one test source file. */
67
13
  export declare function parseTestReferences(source: string, filePath?: string): TestReference[];
14
+ /** Expand test file globs and collect all rule and scenario references from them. */
68
15
  export declare function collectTestReferences(patterns: string[]): Promise<TestReference[]>;
16
+ /** Build rule and scenario coverage from parsed specs and collected test references. */
69
17
  export declare function buildCoverageSummary(specs: FeatureSpec[], references: TestReference[]): CoverageSummary;
18
+ /** Validate coverage expectations and orphaned references. */
70
19
  export declare function validateCoverage(coverage: CoverageSummary, options?: {
71
20
  requireRuleCoverage?: boolean;
72
21
  requireScenarioCoverage?: boolean;
73
22
  }): ValidationIssue[];
23
+ /** Load and parse all feature specs matching the provided globs. */
74
24
  export declare function loadFeatureSpecs(patterns: string[]): Promise<FeatureSpec[]>;
25
+ /** Run spec validation and optional test coverage validation in one call. */
75
26
  export declare function checkFeatureSpecs(options: {
76
27
  specs: string[];
77
28
  tests?: string[];
@@ -84,12 +35,6 @@ export declare function checkFeatureSpecs(options: {
84
35
  coverageIssues: ValidationIssue[];
85
36
  ok: boolean;
86
37
  }>;
87
- export declare function renderHtmlReport(specs: FeatureSpec[], options?: {
88
- coverage?: CoverageSummary;
89
- validationIssues?: ValidationIssue[];
90
- title?: string;
91
- generatedAt?: string;
92
- }): string;
38
+ /** Write text content to a path, creating the parent directory when needed. */
93
39
  export declare function writeTextFile(filePath: string, content: string): Promise<void>;
94
- export declare function expandFilePatterns(patterns: string[]): Promise<string[]>;
95
40
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EACV,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,WAAW,EACX,WAAW,EACX,WAAW,EACX,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAEV,eAAe,EAIf,WAAW,EAGX,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAC;AAapB,+FAA+F;AAC/F,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,WAAW,CAuCb;AAED,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,EAAE,CA2GxE;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,SAAa,GACpB,aAAa,EAAE,CAyBjB;AAED,qFAAqF;AACrF,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,4BAM7D;AAED,wFAAwF;AACxF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,EAAE,EACpB,UAAU,EAAE,aAAa,EAAE,GAC1B,eAAe,CAkCjB;AAED,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,eAAe,EACzB,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAC9B,qBAmDP;AAED,oEAAoE;AACpE,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,0BAQxD;AAED,6EAA6E;AAC7E,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;;;;;;GAsBA;AAED,+EAA+E;AAC/E,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,iBAGpE"}
package/dist/index.js CHANGED
@@ -1,8 +1,20 @@
1
- import { glob, mkdir, readFile, writeFile } from "node:fs/promises";
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
+ import { expandFilePatterns } from "./filePatterns.js";
4
+ export { expandFilePatterns } from "./filePatterns.js";
5
+ export { renderHtmlReport } from "./reportTemplate.js";
6
+ export { collectSpecScreenshots } from "./screenshots.js";
3
7
  const scenarioIdPattern = /\b[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-S\d{3}\b/g;
4
8
  const ruleIdPattern = /\b[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-R\d{3}\b/g;
5
- const ruleKeywords = ["MUST NOT", "SHOULD NOT", "MUST", "SHOULD", "MAY", "OPTIONAL"];
9
+ const ruleKeywords = [
10
+ "MUST NOT",
11
+ "SHOULD NOT",
12
+ "MUST",
13
+ "SHOULD",
14
+ "MAY",
15
+ "OPTIONAL",
16
+ ];
17
+ /** Parse one feature spec Markdown document into structured metadata, rules, and scenarios. */
6
18
  export function parseFeatureSpec(source, options = {}) {
7
19
  const filePath = options.filePath ?? "<inline>";
8
20
  const normalized = source.replace(/\r\n/g, "\n");
@@ -23,13 +35,17 @@ export function parseFeatureSpec(source, options = {}) {
23
35
  return {
24
36
  filePath,
25
37
  frontmatter: frontmatter,
26
- title: lines.find((line) => line.startsWith("# "))?.replace(/^#\s+/, "").trim() ?? frontmatter.title,
38
+ title: lines
39
+ .find((line) => line.startsWith("# "))
40
+ ?.replace(/^#\s+/, "")
41
+ .trim() ?? frontmatter.title,
27
42
  purpose: sectionText(lines, "Purpose").trim(),
28
43
  rules: parseRules(lines, bodyStartLine),
29
44
  scenarios: parseScenarios(lines, bodyStartLine),
30
45
  source,
31
46
  };
32
47
  }
48
+ /** Validate spec structure, ID prefixes, duplicate IDs, and required sections. */
33
49
  export function validateFeatureSpec(spec) {
34
50
  const issues = [];
35
51
  const seen = new Map();
@@ -67,6 +83,7 @@ export function validateFeatureSpec(spec) {
67
83
  }
68
84
  return issues;
69
85
  }
86
+ /** Find rule and scenario IDs referenced by one test source file. */
70
87
  export function parseTestReferences(source, filePath = "<inline>") {
71
88
  const lines = source.split(/\r?\n/);
72
89
  const refs = [];
@@ -90,6 +107,7 @@ export function parseTestReferences(source, filePath = "<inline>") {
90
107
  }
91
108
  return dedupe(refs);
92
109
  }
110
+ /** Expand test file globs and collect all rule and scenario references from them. */
93
111
  export async function collectTestReferences(patterns) {
94
112
  const refs = [];
95
113
  for (const file of await expandFilePatterns(patterns)) {
@@ -97,6 +115,7 @@ export async function collectTestReferences(patterns) {
97
115
  }
98
116
  return refs;
99
117
  }
118
+ /** Build rule and scenario coverage from parsed specs and collected test references. */
100
119
  export function buildCoverageSummary(specs, references) {
101
120
  const scenarios = new Map(specs.flatMap((spec) => spec.scenarios.map((scenario) => [scenario.id, { spec, scenario }])));
102
121
  const rules = new Map(specs.flatMap((spec) => spec.rules.map((rule) => [rule.id, { spec, rule }])));
@@ -109,26 +128,52 @@ export function buildCoverageSummary(specs, references) {
109
128
  orphanRuleReferences: ruleRefs.filter((ref) => !rules.has(ref.id)),
110
129
  };
111
130
  }
131
+ /** Validate coverage expectations and orphaned references. */
112
132
  export function validateCoverage(coverage, options = {}) {
113
133
  const issues = [];
114
134
  if (options.requireScenarioCoverage ?? true) {
115
135
  for (const item of coverage.scenarioCoverage.filter((item) => !item.covered)) {
116
- issues.push({ code: "missing-scenario-coverage", severity: "error", message: `Scenario "${item.id}" has no matching test reference.`, filePath: item.filePath, line: item.line });
136
+ issues.push({
137
+ code: "missing-scenario-coverage",
138
+ severity: "error",
139
+ message: `Scenario "${item.id}" has no matching test reference.`,
140
+ filePath: item.filePath,
141
+ line: item.line,
142
+ });
117
143
  }
118
144
  }
119
145
  if (options.requireRuleCoverage ?? false) {
120
146
  for (const item of coverage.ruleCoverage.filter((item) => !item.covered)) {
121
- issues.push({ code: "missing-rule-coverage", severity: "error", message: `Rule "${item.id}" has no matching test reference.`, filePath: item.filePath, line: item.line });
147
+ issues.push({
148
+ code: "missing-rule-coverage",
149
+ severity: "error",
150
+ message: `Rule "${item.id}" has no matching test reference.`,
151
+ filePath: item.filePath,
152
+ line: item.line,
153
+ });
122
154
  }
123
155
  }
124
156
  for (const ref of coverage.orphanScenarioReferences) {
125
- issues.push({ code: "orphan-scenario-reference", severity: "error", message: `Test references unknown scenario "${ref.id}".`, filePath: ref.filePath, line: ref.line });
157
+ issues.push({
158
+ code: "orphan-scenario-reference",
159
+ severity: "error",
160
+ message: `Test references unknown scenario "${ref.id}".`,
161
+ filePath: ref.filePath,
162
+ line: ref.line,
163
+ });
126
164
  }
127
165
  for (const ref of coverage.orphanRuleReferences) {
128
- issues.push({ code: "orphan-rule-reference", severity: "error", message: `Test references unknown rule "${ref.id}".`, filePath: ref.filePath, line: ref.line });
166
+ issues.push({
167
+ code: "orphan-rule-reference",
168
+ severity: "error",
169
+ message: `Test references unknown rule "${ref.id}".`,
170
+ filePath: ref.filePath,
171
+ line: ref.line,
172
+ });
129
173
  }
130
174
  return issues;
131
175
  }
176
+ /** Load and parse all feature specs matching the provided globs. */
132
177
  export async function loadFeatureSpecs(patterns) {
133
178
  const specs = [];
134
179
  for (const file of await expandFilePatterns(patterns)) {
@@ -136,11 +181,19 @@ export async function loadFeatureSpecs(patterns) {
136
181
  }
137
182
  return specs;
138
183
  }
184
+ /** Run spec validation and optional test coverage validation in one call. */
139
185
  export async function checkFeatureSpecs(options) {
140
186
  const specs = await loadFeatureSpecs(options.specs);
141
187
  const validationIssues = specs.flatMap(validateFeatureSpec);
142
- const coverage = options.tests?.length ? buildCoverageSummary(specs, await collectTestReferences(options.tests)) : undefined;
143
- const coverageIssues = coverage ? validateCoverage(coverage, { requireRuleCoverage: options.requireRuleCoverage, requireScenarioCoverage: options.requireScenarioCoverage }) : [];
188
+ const coverage = options.tests?.length
189
+ ? buildCoverageSummary(specs, await collectTestReferences(options.tests))
190
+ : undefined;
191
+ const coverageIssues = coverage
192
+ ? validateCoverage(coverage, {
193
+ requireRuleCoverage: options.requireRuleCoverage,
194
+ requireScenarioCoverage: options.requireScenarioCoverage,
195
+ })
196
+ : [];
144
197
  return {
145
198
  specs,
146
199
  validationIssues,
@@ -149,30 +202,20 @@ export async function checkFeatureSpecs(options) {
149
202
  ok: ![...validationIssues, ...coverageIssues].some((i) => i.severity === "error"),
150
203
  };
151
204
  }
152
- export function renderHtmlReport(specs, options = {}) {
153
- const title = options.title ?? "Feature Spec Report";
154
- const issues = options.validationIssues ?? [];
155
- return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${html(title)}</title><style>body{font-family:system-ui,sans-serif;max-width:1100px;margin:0 auto;padding:40px 24px}.panel{border:1px solid #ddd;border-radius:16px;padding:20px;margin:18px 0}.ok{color:#1a7f37}.missing,.error{color:#cf222e}.warning{color:#9a6700}.badge{border:1px solid #ddd;border-radius:999px;padding:2px 8px;font-size:12px}</style></head><body><h1>${html(title)}</h1><p>Generated ${html(options.generatedAt ?? new Date().toISOString())}.</p>${renderIssues(issues)}${specs.map((spec) => renderSpec(spec, options.coverage)).join("")}</body></html>`;
156
- }
205
+ /** Write text content to a path, creating the parent directory when needed. */
157
206
  export async function writeTextFile(filePath, content) {
158
207
  await mkdir(path.dirname(filePath), { recursive: true });
159
208
  await writeFile(filePath, content, "utf8");
160
209
  }
161
- export async function expandFilePatterns(patterns) {
162
- const files = new Set();
163
- for (const pattern of patterns) {
164
- for await (const file of glob(pattern, { exclude: ["node_modules/**", ".git/**", "dist/**", "test-results/**"] })) {
165
- files.add(file);
166
- }
167
- }
168
- return Array.from(files).sort();
169
- }
170
210
  function parseFrontmatter(source) {
171
211
  const data = {};
172
212
  for (const line of source.split("\n")) {
173
213
  const match = line.match(/^([A-Za-z][A-Za-z0-9_-]*):\s*(.*)$/);
174
214
  if (match)
175
- data[match[1]] = match[2].replace(/^[']|[']$/g, "").replace(/^["]|["]$/g, "").trim();
215
+ data[match[1]] = match[2]
216
+ .replace(/^[']|[']$/g, "")
217
+ .replace(/^["]|["]$/g, "")
218
+ .trim();
176
219
  }
177
220
  return data;
178
221
  }
@@ -203,7 +246,13 @@ function parseRules(lines, bodyStartLine) {
203
246
  if (!match)
204
247
  continue;
205
248
  const keyword = ruleKeywords.find((kw) => match[2].toUpperCase().includes(kw));
206
- rules.push({ id: match[1], text: match[2].trim(), keyword, strength: strength(keyword), line: bodyStartLine + i });
249
+ rules.push({
250
+ id: match[1],
251
+ text: match[2].trim(),
252
+ keyword,
253
+ strength: strength(keyword),
254
+ line: bodyStartLine + i,
255
+ });
207
256
  }
208
257
  return rules;
209
258
  }
@@ -219,9 +268,18 @@ function parseScenarios(lines, bodyStartLine) {
219
268
  break;
220
269
  const step = lines[j].trim().match(/^(Given|When|Then|And|But)\s+(.+)$/);
221
270
  if (step)
222
- steps.push({ keyword: step[1], text: step[2].trim(), line: bodyStartLine + j });
271
+ steps.push({
272
+ keyword: step[1],
273
+ text: step[2].trim(),
274
+ line: bodyStartLine + j,
275
+ });
223
276
  }
224
- scenarios.push({ id: match[1], title: match[2].trim(), line: bodyStartLine + i, steps });
277
+ scenarios.push({
278
+ id: match[1],
279
+ title: match[2].trim(),
280
+ line: bodyStartLine + i,
281
+ steps,
282
+ });
225
283
  }
226
284
  return scenarios;
227
285
  }
@@ -245,7 +303,14 @@ function registerId(spec, issues, seen, id, line) {
245
303
  }
246
304
  function item(id, title, filePath, line, refs) {
247
305
  const references = refs.filter((ref) => ref.id === id);
248
- return { id, title, filePath, line, references, covered: references.length > 0 };
306
+ return {
307
+ id,
308
+ title,
309
+ filePath,
310
+ line,
311
+ references,
312
+ covered: references.length > 0,
313
+ };
249
314
  }
250
315
  function lineForOffset(lines, offset) {
251
316
  let consumed = 0;
@@ -261,7 +326,8 @@ function sourceForMatch(source, offset) {
261
326
  const context = source.slice(Math.max(0, offset - 80), offset + 80);
262
327
  if (/covers\s*:\s*\[[^\]]*$/.test(before))
263
328
  return "covers";
264
- if (/tag\s*:\s*\[[^\]]*$/.test(before) || /@/.test(source.slice(Math.max(0, offset - 2), offset + 2)))
329
+ if (/tag\s*:\s*\[[^\]]*$/.test(before) ||
330
+ /@/.test(source.slice(Math.max(0, offset - 2), offset + 2)))
265
331
  return "tag";
266
332
  if (/annotation/.test(context))
267
333
  return "annotation";
@@ -279,18 +345,4 @@ function dedupe(refs) {
279
345
  return true;
280
346
  });
281
347
  }
282
- function renderIssues(issues) {
283
- if (!issues.length)
284
- return `<section class="panel"><h2>Validation</h2><p class="ok">No validation issues found.</p></section>`;
285
- return `<section class="panel"><h2>Validation</h2><ul>${issues.map((i) => `<li class="${i.severity}"><code>${html(`${i.filePath ?? ""}${i.line ? `:${i.line}` : ""}`)}</code> ${html(i.message)}</li>`).join("")}</ul></section>`;
286
- }
287
- function renderSpec(spec, coverage) {
288
- return `<section class="panel"><p><span class="badge">${html(spec.frontmatter.status ?? "draft")}</span></p><h2>${html(spec.frontmatter.id)} ${html(spec.title)}</h2><p>${html(spec.purpose)}</p><h3>Rules</h3><ul>${spec.rules.map((r) => `<li><code>${html(r.id)}</code>: ${html(r.text)} ${coverageBadge(coverage?.ruleCoverage.find((i) => i.id === r.id)?.covered)}</li>`).join("")}</ul><h3>Scenarios</h3>${spec.scenarios.map((s) => `<article class="panel"><h4><code>${html(s.id)}</code>: ${html(s.title)} ${coverageBadge(coverage?.scenarioCoverage.find((i) => i.id === s.id)?.covered)}</h4>${s.steps.map((step) => `<p><strong>${html(step.keyword)}</strong> ${html(step.text)}</p>`).join("")}</article>`).join("")}</section>`;
289
- }
290
- function coverageBadge(covered) {
291
- return covered === undefined ? "" : covered ? `<span class="badge ok">covered</span>` : `<span class="badge missing">missing coverage</span>`;
292
- }
293
- function html(value) {
294
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#039;");
295
- }
296
348
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { StepKeyword } from "./types.js";
2
+ export type SpecEvidenceStep = {
3
+ scenarioId: string;
4
+ specPath: string;
5
+ line: number;
6
+ keyword: StepKeyword;
7
+ text: string;
8
+ };
9
+ export type SpecEvidenceScreenshot = {
10
+ specPath: string;
11
+ line: number;
12
+ path: string;
13
+ title: string;
14
+ testPath: string;
15
+ };
16
+ export type PlaywrightSpecEvidenceOptions = {
17
+ specs: string[];
18
+ reportDir?: string;
19
+ screenshotsDirName?: string;
20
+ cwd?: string;
21
+ };
22
+ export type PlaywrightPageLike = {
23
+ screenshot(options: {
24
+ fullPage?: boolean;
25
+ path: string;
26
+ }): Promise<unknown>;
27
+ };
28
+ export type PlaywrightTestInfoLike = {
29
+ attach(name: string, options: {
30
+ contentType: string;
31
+ path: string;
32
+ }): Promise<unknown>;
33
+ file: string;
34
+ workerIndex: number;
35
+ };
36
+ export type PlaywrightTestLike = {
37
+ step<T>(title: string, body: () => Promise<T>): Promise<T>;
38
+ };
39
+ /** Create a Playwright helper that captures screenshot evidence for spec step lines. */
40
+ export declare function createPlaywrightSpecEvidence(test: PlaywrightTestLike, options: PlaywrightSpecEvidenceOptions): {
41
+ specStep(page: PlaywrightPageLike, testInfo: PlaywrightTestInfoLike, scenarioId: string, stepText: string, body: () => Promise<void>): Promise<void>;
42
+ };
43
+ /** Parse spec files and return all scenario step lines addressable by Playwright tests. */
44
+ export declare function loadSpecSteps(patterns: string[], cwd?: string): Promise<SpecEvidenceStep[]>;
45
+ //# sourceMappingURL=playwright.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../src/playwright.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7E,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,CACJ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC5D,CAAC;AAEF,wFAAwF;AACxF,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,6BAA6B;mBAc5B,kBAAkB,YACd,sBAAsB,cACpB,MAAM,YACR,MAAM,QACV,MAAM,OAAO,CAAC,IAAI,CAAC;EAiB9B;AAED,2FAA2F;AAC3F,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,GAAG,SAAgB,+BAuC1E"}
@@ -0,0 +1,109 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { expandFilePatterns } from "./filePatterns.js";
4
+ /** Create a Playwright helper that captures screenshot evidence for spec step lines. */
5
+ export function createPlaywrightSpecEvidence(test, options) {
6
+ const cwd = options.cwd ?? process.cwd();
7
+ const reportDir = path.resolve(cwd, options.reportDir ?? "test-results/spec-report");
8
+ const screenshotsDirName = options.screenshotsDirName ?? "screenshots";
9
+ const screenshotDir = path.join(reportDir, screenshotsDirName);
10
+ const stepsPromise = loadSpecSteps(options.specs, cwd);
11
+ const entriesByWorker = new Map();
12
+ return {
13
+ async specStep(page, testInfo, scenarioId, stepText, body) {
14
+ const step = await findSpecStep(stepsPromise, scenarioId, stepText);
15
+ await test.step(`${step.keyword} ${step.text}`, async () => {
16
+ await body();
17
+ await captureStepScreenshot({
18
+ entriesByWorker,
19
+ page,
20
+ reportDir,
21
+ screenshotDir,
22
+ screenshotsDirName,
23
+ step,
24
+ testInfo,
25
+ });
26
+ });
27
+ },
28
+ };
29
+ }
30
+ /** Parse spec files and return all scenario step lines addressable by Playwright tests. */
31
+ export async function loadSpecSteps(patterns, cwd = process.cwd()) {
32
+ const previousCwd = process.cwd();
33
+ const steps = [];
34
+ try {
35
+ process.chdir(cwd);
36
+ for (const specPath of await expandFilePatterns(patterns)) {
37
+ const source = await readFile(path.resolve(cwd, specPath), "utf8");
38
+ let scenarioId = "";
39
+ for (const [index, line] of source
40
+ .replace(/\r\n/g, "\n")
41
+ .split("\n")
42
+ .entries()) {
43
+ const scenario = line.match(/^###\s+([A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-S\d{3}):/);
44
+ if (scenario) {
45
+ scenarioId = scenario[1];
46
+ continue;
47
+ }
48
+ const step = line.trim().match(/^(Given|When|Then|And|But)\s+(.+)$/);
49
+ if (scenarioId && step) {
50
+ steps.push({
51
+ scenarioId,
52
+ specPath,
53
+ line: index + 1,
54
+ keyword: step[1],
55
+ text: step[2].trim(),
56
+ });
57
+ }
58
+ }
59
+ }
60
+ }
61
+ finally {
62
+ process.chdir(previousCwd);
63
+ }
64
+ return steps;
65
+ }
66
+ async function findSpecStep(stepsPromise, scenarioId, stepText) {
67
+ const steps = await stepsPromise;
68
+ const normalizedStepText = stepText.replace(/^(Given|When|Then|And|But)\s+/, "");
69
+ const step = steps.find((candidate) => candidate.scenarioId === scenarioId &&
70
+ candidate.text === normalizedStepText);
71
+ if (!step) {
72
+ throw new Error(`No spec step found for ${scenarioId}: ${stepText}`);
73
+ }
74
+ return step;
75
+ }
76
+ async function captureStepScreenshot(options) {
77
+ await mkdir(options.screenshotDir, { recursive: true });
78
+ const fileName = `${options.step.scenarioId}-line-${options.step.line}-${slug(options.step.text)}.png`;
79
+ const screenshotPath = path.join(options.screenshotDir, fileName);
80
+ const relativePath = `${options.screenshotsDirName}/${fileName}`;
81
+ const title = `${options.step.scenarioId}:${options.step.line} ${options.step.keyword} ${options.step.text}`;
82
+ await options.page.screenshot({ fullPage: true, path: screenshotPath });
83
+ await options.testInfo.attach(title, {
84
+ contentType: "image/png",
85
+ path: screenshotPath,
86
+ });
87
+ const entries = options.entriesByWorker.get(options.testInfo.workerIndex) ?? [];
88
+ entries.push({
89
+ specPath: options.step.specPath,
90
+ line: options.step.line,
91
+ path: relativePath,
92
+ title,
93
+ testPath: options.testInfo.file,
94
+ });
95
+ options.entriesByWorker.set(options.testInfo.workerIndex, entries);
96
+ await writeWorkerManifest(options.reportDir, options.testInfo.workerIndex, entries);
97
+ }
98
+ async function writeWorkerManifest(reportDir, workerIndex, screenshots) {
99
+ await mkdir(reportDir, { recursive: true });
100
+ await writeFile(path.join(reportDir, `screenshots-${workerIndex}.json`), JSON.stringify({ screenshots }, null, 2), "utf8");
101
+ }
102
+ function slug(value) {
103
+ return value
104
+ .toLowerCase()
105
+ .replace(/[^a-z0-9]+/g, "-")
106
+ .replace(/^-|-$/g, "")
107
+ .slice(0, 72);
108
+ }
109
+ //# sourceMappingURL=playwright.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright.js","sourceRoot":"","sources":["../src/playwright.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { CoverageSummary, FeatureSpec, SpecScreenshot, ValidationIssue } from "./types.js";
2
+ export type ReportOptions = {
3
+ coverage?: CoverageSummary;
4
+ screenshots?: SpecScreenshot[];
5
+ validationIssues?: ValidationIssue[];
6
+ title?: string;
7
+ generatedAt?: string;
8
+ };
9
+ /** Render a complete self-contained feature spec report as HTML. */
10
+ export declare function renderHtmlReport(specs: FeatureSpec[], options?: ReportOptions): string;
11
+ //# sourceMappingURL=reportTemplate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reportTemplate.d.ts","sourceRoot":"","sources":["../src/reportTemplate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,eAAe,EACf,WAAW,EAEX,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,oEAAoE;AACpE,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAAE,EACpB,OAAO,GAAE,aAAkB,UAoC5B"}
@@ -0,0 +1,124 @@
1
+ import { html } from "./html.js";
2
+ import { screenshotKey } from "./screenshots.js";
3
+ /** Render a complete self-contained feature spec report as HTML. */
4
+ export function renderHtmlReport(specs, options = {}) {
5
+ const title = options.title ?? "Feature Spec Report";
6
+ const issues = options.validationIssues ?? [];
7
+ const screenshots = options.screenshots ?? [];
8
+ return `<!doctype html>
9
+ <html lang="en">
10
+ <head>
11
+ <meta charset="utf-8">
12
+ <meta name="viewport" content="width=device-width,initial-scale=1">
13
+ <title>${html(title)}</title>
14
+ <style>
15
+ body{font-family:system-ui,sans-serif;max-width:1180px;margin:0 auto;padding:40px 24px;color:#1f2328}
16
+ .panel{border:1px solid #d0d7de;border-radius:8px;padding:20px;margin:18px 0}
17
+ .ok{color:#1a7f37}.missing,.error{color:#cf222e}.warning{color:#9a6700}
18
+ .badge{border:1px solid #d0d7de;border-radius:999px;padding:2px 8px;font-size:12px;white-space:nowrap}
19
+ .feature-header{display:flex;gap:12px;align-items:center;justify-content:space-between}
20
+ .scenario{border:1px solid #d0d7de;border-radius:8px;margin:12px 0;background:#fff}
21
+ .scenario summary{cursor:pointer;padding:14px 16px;font-weight:600}
22
+ .scenario-body{padding:0 16px 16px}
23
+ .step{border-left:3px solid #d0d7de;margin:12px 0;padding:2px 0 2px 12px}
24
+ .step p{margin:8px 0}
25
+ .screenshots{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px;margin:10px 0 14px}
26
+ .screenshot{border:1px solid #d0d7de;border-radius:8px;overflow:hidden;background:#f6f8fa}
27
+ .screenshot img{display:block;width:100%;height:auto}
28
+ .screenshot figcaption{font-size:12px;padding:8px;color:#57606a}
29
+ </style>
30
+ </head>
31
+ <body>
32
+ <h1>${html(title)}</h1>
33
+ <p>Generated ${html(options.generatedAt ?? new Date().toISOString())}.</p>
34
+ ${renderIssues(issues)}
35
+ ${specs.map((spec) => renderSpec(spec, options.coverage, screenshots)).join("\n")}
36
+ </body>
37
+ </html>`;
38
+ }
39
+ function renderIssues(issues) {
40
+ if (!issues.length) {
41
+ return `<section class="panel"><h2>Validation</h2><p class="ok">No validation issues found.</p></section>`;
42
+ }
43
+ return `<section class="panel"><h2>Validation</h2><ul>${issues
44
+ .map((issue) => `<li class="${issue.severity}"><code>${html(`${issue.filePath ?? ""}${issue.line ? `:${issue.line}` : ""}`)}</code> ${html(issue.message)}</li>`)
45
+ .join("")}</ul></section>`;
46
+ }
47
+ function renderSpec(spec, coverage, screenshots = []) {
48
+ const screenshotsByLine = groupScreenshotsByLine(screenshots);
49
+ const ruleCoverage = coverage?.ruleCoverage ?? [];
50
+ const scenarioCoverage = coverage?.scenarioCoverage ?? [];
51
+ return `<section class="panel">
52
+ <div class="feature-header">
53
+ <h2>${html(spec.frontmatter.id)} ${html(spec.title)}</h2>
54
+ <span class="badge">${html(spec.frontmatter.status ?? "draft")}</span>
55
+ </div>
56
+ <p>${html(spec.purpose)}</p>
57
+ <h3>Rules</h3>
58
+ <ul>${spec.rules
59
+ .map((rule) => {
60
+ const item = ruleCoverage.find((coverageItem) => coverageItem.id === rule.id);
61
+ return `<li><code>${html(rule.id)}</code>: ${html(rule.text)} ${coverageBadge(item?.covered, ruleScenarioShortIds(item, scenarioCoverage))}</li>`;
62
+ })
63
+ .join("")}</ul>
64
+ <h3>Scenarios</h3>
65
+ ${spec.scenarios
66
+ .map((scenario) => {
67
+ const screenshotCount = scenario.steps.reduce((count, step) => count +
68
+ (screenshotsByLine.get(screenshotKey(spec.filePath, step.line))
69
+ ?.length ?? 0), 0);
70
+ return `<details class="scenario">
71
+ <summary><code>${html(scenario.id)}</code>: ${html(scenario.title)} ${coverageBadge(scenarioCoverage.find((item) => item.id === scenario.id)?.covered)} <span class="badge">${screenshotCount} screenshot${screenshotCount === 1 ? "" : "s"}</span></summary>
72
+ <div class="scenario-body">${scenario.steps.map((step) => renderStep(spec, step, screenshotsByLine)).join("")}</div>
73
+ </details>`;
74
+ })
75
+ .join("\n")}
76
+ </section>`;
77
+ }
78
+ function renderStep(spec, step, screenshotsByLine) {
79
+ const screenshots = screenshotsByLine.get(screenshotKey(spec.filePath, step.line)) ?? [];
80
+ const evidenceBadge = screenshots.length
81
+ ? `<span class="badge ok">${screenshots.length} screenshot${screenshots.length === 1 ? "" : "s"}</span>`
82
+ : `<span class="badge missing">missing screenshot</span>`;
83
+ return `<div class="step"><p><strong>${html(step.keyword)}</strong> ${html(step.text)} <span class="badge">line ${step.line}</span> ${evidenceBadge}</p>${renderScreenshots(screenshots)}</div>`;
84
+ }
85
+ function renderScreenshots(screenshots) {
86
+ if (!screenshots.length)
87
+ return "";
88
+ return `<div class="screenshots">${screenshots
89
+ .map((screenshot) => `<figure class="screenshot"><img src="${html(screenshot.path)}" alt="${html(screenshot.title ?? `Screenshot for ${screenshot.specPath}:${screenshot.line}`)}"><figcaption>${html(screenshot.title ?? `${screenshot.specPath}:${screenshot.line}`)}</figcaption></figure>`)
90
+ .join("")}</div>`;
91
+ }
92
+ function coverageBadge(covered, suffixes = []) {
93
+ return covered === undefined
94
+ ? ""
95
+ : covered
96
+ ? `<span class="badge ok">covered${suffixes.length ? ` ${suffixes.map(html).join(" ")}` : ""}</span>`
97
+ : `<span class="badge missing">missing coverage</span>`;
98
+ }
99
+ function ruleScenarioShortIds(ruleCoverage, scenarioCoverage) {
100
+ if (!ruleCoverage?.covered)
101
+ return [];
102
+ const scenarioIds = new Set();
103
+ for (const ruleReference of ruleCoverage.references) {
104
+ for (const scenario of scenarioCoverage) {
105
+ const coversRule = scenario.references.some((scenarioReference) => scenarioReference.filePath === ruleReference.filePath &&
106
+ scenarioReference.line === ruleReference.line);
107
+ if (coversRule)
108
+ scenarioIds.add(shortScenarioId(scenario.id));
109
+ }
110
+ }
111
+ return Array.from(scenarioIds).sort();
112
+ }
113
+ function shortScenarioId(id) {
114
+ return id.match(/-(S\d{3})$/)?.[1] ?? id;
115
+ }
116
+ function groupScreenshotsByLine(screenshots) {
117
+ const grouped = new Map();
118
+ for (const screenshot of screenshots) {
119
+ const key = screenshotKey(screenshot.specPath, screenshot.line);
120
+ grouped.set(key, [...(grouped.get(key) ?? []), screenshot]);
121
+ }
122
+ return grouped;
123
+ }
124
+ //# sourceMappingURL=reportTemplate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reportTemplate.js","sourceRoot":"","sources":["../src/reportTemplate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { SpecScreenshot } from "./types.js";
2
+ /** Load screenshot evidence manifests and normalize entries for report rendering. */
3
+ export declare function collectSpecScreenshots(patterns: string[]): Promise<SpecScreenshot[]>;
4
+ export declare function screenshotKey(filePath: string, line: number): string;
5
+ export declare function normalizeFilePath(filePath: string): string;
6
+ //# sourceMappingURL=screenshots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshots.d.ts","sourceRoot":"","sources":["../src/screenshots.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qFAAqF;AACrF,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,6BAgB9D;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAE3D;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,UAEjD"}
@@ -0,0 +1,49 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { expandArtifactPatterns } from "./filePatterns.js";
3
+ /** Load screenshot evidence manifests and normalize entries for report rendering. */
4
+ export async function collectSpecScreenshots(patterns) {
5
+ const screenshots = [];
6
+ for (const file of await expandArtifactPatterns(patterns)) {
7
+ const parsed = JSON.parse(await readFile(file, "utf8"));
8
+ const entries = Array.isArray(parsed)
9
+ ? parsed
10
+ : isRecord(parsed) && Array.isArray(parsed.screenshots)
11
+ ? parsed.screenshots
12
+ : [];
13
+ for (const entry of entries) {
14
+ const screenshot = normalizeScreenshot(entry);
15
+ if (screenshot)
16
+ screenshots.push(screenshot);
17
+ }
18
+ }
19
+ return screenshots;
20
+ }
21
+ export function screenshotKey(filePath, line) {
22
+ return `${normalizeFilePath(filePath)}:${line}`;
23
+ }
24
+ export function normalizeFilePath(filePath) {
25
+ return filePath.replace(/\\/g, "/").replace(/^\.\//, "");
26
+ }
27
+ function normalizeScreenshot(value) {
28
+ if (!isRecord(value))
29
+ return null;
30
+ const specPath = value.specPath;
31
+ const line = value.line;
32
+ const imagePath = value.path ?? value.imagePath;
33
+ if (typeof specPath !== "string" ||
34
+ typeof line !== "number" ||
35
+ typeof imagePath !== "string") {
36
+ return null;
37
+ }
38
+ return {
39
+ specPath: normalizeFilePath(specPath),
40
+ line,
41
+ path: imagePath,
42
+ title: typeof value.title === "string" ? value.title : undefined,
43
+ testPath: typeof value.testPath === "string" ? value.testPath : undefined,
44
+ };
45
+ }
46
+ function isRecord(value) {
47
+ return typeof value === "object" && value !== null;
48
+ }
49
+ //# sourceMappingURL=screenshots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshots.js","sourceRoot":"","sources":["../src/screenshots.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAG3D,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,QAAkB;IAC7D,MAAM,WAAW,GAAqB,EAAE,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,MAAM,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAY,CAAC;QACnE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YACnC,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC;gBACrD,CAAC,CAAC,MAAM,CAAC,WAAW;gBACpB,CAAC,CAAC,EAAE,CAAC;QAET,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,UAAU,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC9C,IAAI,UAAU;gBAAE,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,IAAY;IAC1D,OAAO,GAAG,iBAAiB,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACxB,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC;IAChD,IACE,OAAO,QAAQ,KAAK,QAAQ;QAC5B,OAAO,IAAI,KAAK,QAAQ;QACxB,OAAO,SAAS,KAAK,QAAQ,EAC7B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,CAAC;QACrC,IAAI;QACJ,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QAChE,QAAQ,EAAE,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;KAC1E,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC"}
@@ -0,0 +1,81 @@
1
+ /** Parsed contents of one `*.feature.md` file. */
2
+ export type FeatureSpec = {
3
+ filePath: string;
4
+ frontmatter: FeatureFrontmatter;
5
+ title: string;
6
+ purpose: string;
7
+ rules: FeatureRule[];
8
+ scenarios: FeatureScenario[];
9
+ source: string;
10
+ };
11
+ /** Frontmatter fields supported by the feature spec format. */
12
+ export type FeatureFrontmatter = {
13
+ id: string;
14
+ title: string;
15
+ status?: "draft" | "active" | "deprecated";
16
+ owner?: string;
17
+ };
18
+ /** A business rule declared in the `## Rules` section. */
19
+ export type FeatureRule = {
20
+ id: string;
21
+ text: string;
22
+ keyword?: RuleKeyword;
23
+ strength: "required" | "recommended" | "optional" | "unspecified";
24
+ line: number;
25
+ };
26
+ /** A concrete example declared in the `## Scenarios` section. */
27
+ export type FeatureScenario = {
28
+ id: string;
29
+ title: string;
30
+ line: number;
31
+ steps: FeatureStep[];
32
+ };
33
+ /** A single Given / When / Then style step inside a scenario. */
34
+ export type FeatureStep = {
35
+ keyword: StepKeyword;
36
+ text: string;
37
+ line: number;
38
+ };
39
+ export type RuleKeyword = "MUST" | "MUST NOT" | "SHOULD" | "SHOULD NOT" | "MAY" | "OPTIONAL";
40
+ export type StepKeyword = "Given" | "When" | "Then" | "And" | "But";
41
+ /** Validation problem found in a spec, test reference, or report input. */
42
+ export type ValidationIssue = {
43
+ code: string;
44
+ severity: "error" | "warning";
45
+ message: string;
46
+ filePath?: string;
47
+ line?: number;
48
+ };
49
+ /** A rule or scenario ID found in executable tests. */
50
+ export type TestReference = {
51
+ id: string;
52
+ filePath: string;
53
+ line: number;
54
+ kind: "scenario" | "rule";
55
+ source: "title" | "tag" | "covers" | "annotation" | "free-text";
56
+ };
57
+ /** Coverage state for one expected rule or scenario. */
58
+ export type CoverageItem = {
59
+ id: string;
60
+ title?: string;
61
+ filePath?: string;
62
+ line?: number;
63
+ covered: boolean;
64
+ references: TestReference[];
65
+ };
66
+ /** Complete test coverage mapping for a set of feature specs. */
67
+ export type CoverageSummary = {
68
+ scenarioCoverage: CoverageItem[];
69
+ ruleCoverage: CoverageItem[];
70
+ orphanScenarioReferences: TestReference[];
71
+ orphanRuleReferences: TestReference[];
72
+ };
73
+ /** Screenshot evidence associated with an exact spec line. */
74
+ export type SpecScreenshot = {
75
+ specPath: string;
76
+ line: number;
77
+ path: string;
78
+ title?: string;
79
+ testPath?: string;
80
+ };
81
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anselmdk/feature-spec-md",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Markdown feature specs with rule/scenario IDs, validation, coverage checks, and generated reports.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,6 +10,10 @@
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js"
13
+ },
14
+ "./playwright": {
15
+ "types": "./dist/playwright.d.ts",
16
+ "import": "./dist/playwright.js"
13
17
  }
14
18
  },
15
19
  "files": [
@@ -27,9 +31,15 @@
27
31
  "build": "tsc -p tsconfig.build.json",
28
32
  "prepare": "npm run build",
29
33
  "dev": "tsx src/cli.ts",
30
- "check:example": "tsx src/cli.ts check --specs examples/**/*.feature.md --tests tests/**/*.test.ts --require-scenario-coverage=false",
34
+ "spec": "tsx src/cli.ts check",
35
+ "spec:init": "tsx src/cli.ts init",
36
+ "spec:report": "tsx src/cli.ts report",
37
+ "format": "prettier --write .",
38
+ "check:example": "tsx src/cli.ts check --specs examples/**/*.feature.md --require-scenario-coverage=false",
31
39
  "report:example": "tsx src/cli.ts report --specs examples/**/*.feature.md --tests tests/**/*.test.ts --out test-results/feature-spec-report/index.html",
32
- "test": "tsx --test tests/**/*.test.ts",
40
+ "test": "npm run test:unit && npm run test:playwright",
41
+ "test:unit": "tsx --test tests/**/*.test.ts",
42
+ "test:playwright": "playwright install chromium && playwright test",
33
43
  "typecheck": "tsc -p tsconfig.json --noEmit",
34
44
  "verify": "npm run typecheck && npm test && npm run build && npm run check:example"
35
45
  },
@@ -43,7 +53,9 @@
43
53
  ],
44
54
  "license": "MIT",
45
55
  "devDependencies": {
56
+ "@playwright/test": "^1.60.0",
46
57
  "@types/node": "^25.3.2",
58
+ "prettier": "^3.8.4",
47
59
  "tsx": "^4.21.0",
48
60
  "typescript": "^5.9.3"
49
61
  }