executable-stories-react 0.2.1 → 0.4.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/dist/index.cjs +345 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +295 -9
- package/dist/index.d.ts +295 -9
- package/dist/index.js +329 -145
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +533 -239
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +269 -2
- package/dist/interactive.d.ts +269 -2
- package/dist/interactive.js +494 -201
- package/dist/interactive.js.map +1 -1
- package/dist/parse.cjs +4 -0
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.d.cts +225 -3
- package/dist/parse.d.ts +225 -3
- package/dist/parse.js +4 -0
- package/dist/parse.js.map +1 -1
- package/dist/report-island.global.js +32 -32
- package/dist/ssr.cjs +275 -118
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.d.cts +250 -2
- package/dist/ssr.d.ts +250 -2
- package/dist/ssr.js +272 -115
- package/dist/ssr.js.map +1 -1
- package/dist/styles.css +26 -0
- package/dist/tailwind.css +1 -1
- package/package.json +7 -6
package/dist/interactive.d.cts
CHANGED
|
@@ -1,6 +1,229 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* OTel span types for trace waterfall rendering.
|
|
6
|
+
*
|
|
7
|
+
* Structurally compatible with autotel's SerializedSpan
|
|
8
|
+
* and raw OTel nanosecond formats. No import dependency on autotel.
|
|
9
|
+
*/
|
|
10
|
+
type OtelAttributeValue = string | number | boolean | string[] | number[] | boolean[];
|
|
11
|
+
interface OtelSpan {
|
|
12
|
+
spanId: string;
|
|
13
|
+
parentSpanId?: string;
|
|
14
|
+
name: string;
|
|
15
|
+
/** Preferred: epoch-based milliseconds (from autotel's SerializedSpan) */
|
|
16
|
+
startTimeMs?: number;
|
|
17
|
+
durationMs?: number;
|
|
18
|
+
/** Compatibility: raw OTel nanosecond timestamps */
|
|
19
|
+
startTimeUnixNano?: number;
|
|
20
|
+
endTimeUnixNano?: number;
|
|
21
|
+
status: "ok" | "error" | "unset";
|
|
22
|
+
statusMessage?: string;
|
|
23
|
+
attributes?: Record<string, OtelAttributeValue>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Phase tracks when the doc entry was added */
|
|
27
|
+
type DocPhase = "static" | "runtime";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* StoryReport — public, frozen contract for UI renderers.
|
|
31
|
+
*
|
|
32
|
+
* Distinct from internal TestRunResult. Pre-grouped feature → scenario tree,
|
|
33
|
+
* with pre-computed summaries at every level. Adapter concerns (rawStatus,
|
|
34
|
+
* projectName, titlePath) are stripped at the toStoryReport boundary.
|
|
35
|
+
*
|
|
36
|
+
* Versioning: semver-style "<major>.<minor>". Additive-only within a major.
|
|
37
|
+
* Source of truth: schemas/story-report-v1.json. Types here must stay in sync.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
type StoryReportSchemaVersion = `1.${number}`;
|
|
41
|
+
type TestStatus = "passed" | "failed" | "skipped" | "pending";
|
|
42
|
+
type StepKeyword = "Given" | "When" | "Then" | "And" | "But";
|
|
43
|
+
type StepMode = "normal" | "skip" | "only" | "todo" | "fails" | "concurrent";
|
|
44
|
+
interface ReportSummary {
|
|
45
|
+
total: number;
|
|
46
|
+
passed: number;
|
|
47
|
+
failed: number;
|
|
48
|
+
skipped: number;
|
|
49
|
+
pending: number;
|
|
50
|
+
durationMs: number;
|
|
51
|
+
}
|
|
52
|
+
interface ReportTicket {
|
|
53
|
+
id: string;
|
|
54
|
+
url?: string;
|
|
55
|
+
}
|
|
56
|
+
interface ReportAttachment {
|
|
57
|
+
name: string;
|
|
58
|
+
mediaType: string;
|
|
59
|
+
body: string;
|
|
60
|
+
contentEncoding: "BASE64" | "IDENTITY";
|
|
61
|
+
}
|
|
62
|
+
interface ReportCIInfo {
|
|
63
|
+
name: string;
|
|
64
|
+
url?: string;
|
|
65
|
+
buildNumber?: string;
|
|
66
|
+
branch?: string;
|
|
67
|
+
commitSha?: string;
|
|
68
|
+
prNumber?: string;
|
|
69
|
+
}
|
|
70
|
+
interface ReportCoverageSummary {
|
|
71
|
+
linesPct?: number;
|
|
72
|
+
branchesPct?: number;
|
|
73
|
+
functionsPct?: number;
|
|
74
|
+
statementsPct?: number;
|
|
75
|
+
}
|
|
76
|
+
type ReportDocEntry = ReportDocNote | ReportDocTag | ReportDocKv | ReportDocCode | ReportDocTable | ReportDocLink | ReportDocSection | ReportDocMermaid | ReportDocScreenshot | ReportDocVideo | ReportDocHtml | ReportDocCustom;
|
|
77
|
+
interface ReportDocNote {
|
|
78
|
+
kind: "note";
|
|
79
|
+
text: string;
|
|
80
|
+
phase: DocPhase;
|
|
81
|
+
children?: ReportDocEntry[];
|
|
82
|
+
}
|
|
83
|
+
interface ReportDocTag {
|
|
84
|
+
kind: "tag";
|
|
85
|
+
names: string[];
|
|
86
|
+
phase: DocPhase;
|
|
87
|
+
children?: ReportDocEntry[];
|
|
88
|
+
}
|
|
89
|
+
interface ReportDocKv {
|
|
90
|
+
kind: "kv";
|
|
91
|
+
label: string;
|
|
92
|
+
value: unknown;
|
|
93
|
+
phase: DocPhase;
|
|
94
|
+
children?: ReportDocEntry[];
|
|
95
|
+
}
|
|
96
|
+
interface ReportDocCode {
|
|
97
|
+
kind: "code";
|
|
98
|
+
label: string;
|
|
99
|
+
content: string;
|
|
100
|
+
lang?: string;
|
|
101
|
+
phase: DocPhase;
|
|
102
|
+
children?: ReportDocEntry[];
|
|
103
|
+
}
|
|
104
|
+
interface ReportDocTable {
|
|
105
|
+
kind: "table";
|
|
106
|
+
label: string;
|
|
107
|
+
columns: string[];
|
|
108
|
+
rows: string[][];
|
|
109
|
+
phase: DocPhase;
|
|
110
|
+
children?: ReportDocEntry[];
|
|
111
|
+
}
|
|
112
|
+
interface ReportDocLink {
|
|
113
|
+
kind: "link";
|
|
114
|
+
label: string;
|
|
115
|
+
url: string;
|
|
116
|
+
phase: DocPhase;
|
|
117
|
+
children?: ReportDocEntry[];
|
|
118
|
+
}
|
|
119
|
+
interface ReportDocSection {
|
|
120
|
+
kind: "section";
|
|
121
|
+
title: string;
|
|
122
|
+
markdown: string;
|
|
123
|
+
phase: DocPhase;
|
|
124
|
+
children?: ReportDocEntry[];
|
|
125
|
+
}
|
|
126
|
+
interface ReportDocMermaid {
|
|
127
|
+
kind: "mermaid";
|
|
128
|
+
code: string;
|
|
129
|
+
title?: string;
|
|
130
|
+
phase: DocPhase;
|
|
131
|
+
children?: ReportDocEntry[];
|
|
132
|
+
}
|
|
133
|
+
interface ReportDocScreenshot {
|
|
134
|
+
kind: "screenshot";
|
|
135
|
+
path: string;
|
|
136
|
+
alt?: string;
|
|
137
|
+
phase: DocPhase;
|
|
138
|
+
children?: ReportDocEntry[];
|
|
139
|
+
}
|
|
140
|
+
interface ReportDocVideo {
|
|
141
|
+
kind: "video";
|
|
142
|
+
path: string;
|
|
143
|
+
caption?: string;
|
|
144
|
+
poster?: string;
|
|
145
|
+
phase: DocPhase;
|
|
146
|
+
children?: ReportDocEntry[];
|
|
147
|
+
}
|
|
148
|
+
interface ReportDocHtml {
|
|
149
|
+
kind: "html";
|
|
150
|
+
/** Local HTML file path (exactly one of path/url/content) */
|
|
151
|
+
path?: string;
|
|
152
|
+
/** Remote URL rendered via iframe src (exactly one of path/url/content) */
|
|
153
|
+
url?: string;
|
|
154
|
+
/** Inline HTML content rendered via iframe srcdoc (exactly one of path/url/content) */
|
|
155
|
+
content?: string;
|
|
156
|
+
title?: string;
|
|
157
|
+
/** Iframe height: number → px, string passed through (e.g. "60vh"). Default 400px. */
|
|
158
|
+
height?: number | string;
|
|
159
|
+
phase: DocPhase;
|
|
160
|
+
children?: ReportDocEntry[];
|
|
161
|
+
}
|
|
162
|
+
interface ReportDocCustom {
|
|
163
|
+
kind: "custom";
|
|
164
|
+
type: string;
|
|
165
|
+
data: unknown;
|
|
166
|
+
phase: DocPhase;
|
|
167
|
+
children?: ReportDocEntry[];
|
|
168
|
+
}
|
|
169
|
+
interface ReportStep {
|
|
170
|
+
id: string;
|
|
171
|
+
index: number;
|
|
172
|
+
keyword: StepKeyword;
|
|
173
|
+
text: string;
|
|
174
|
+
status: TestStatus;
|
|
175
|
+
durationMs: number;
|
|
176
|
+
errorMessage?: string;
|
|
177
|
+
mode?: StepMode;
|
|
178
|
+
docEntries: ReportDocEntry[];
|
|
179
|
+
}
|
|
180
|
+
interface ReportScenario {
|
|
181
|
+
id: string;
|
|
182
|
+
title: string;
|
|
183
|
+
status: TestStatus;
|
|
184
|
+
/**
|
|
185
|
+
* True for scenarios authored with the framework's todo modifier
|
|
186
|
+
* (e.g. `it.todo`): specified behavior with no implementation yet.
|
|
187
|
+
* Canonical status stays "pending"; this flags why.
|
|
188
|
+
*/
|
|
189
|
+
planned?: boolean;
|
|
190
|
+
durationMs: number;
|
|
191
|
+
tags: string[];
|
|
192
|
+
tickets?: ReportTicket[];
|
|
193
|
+
/** Product-code paths/globs this scenario exercises (project-root-relative). */
|
|
194
|
+
covers?: string[];
|
|
195
|
+
sourceLine?: number;
|
|
196
|
+
errorMessage?: string;
|
|
197
|
+
errorStack?: string;
|
|
198
|
+
retry: number;
|
|
199
|
+
retries: number;
|
|
200
|
+
docEntries: ReportDocEntry[];
|
|
201
|
+
steps: ReportStep[];
|
|
202
|
+
attachments: ReportAttachment[];
|
|
203
|
+
/** OTel spans for the trace waterfall (carried through from the run). */
|
|
204
|
+
otelSpans?: OtelSpan[];
|
|
205
|
+
}
|
|
206
|
+
interface ReportFeature {
|
|
207
|
+
id: string;
|
|
208
|
+
title: string;
|
|
209
|
+
sourceFile: string;
|
|
210
|
+
summary: ReportSummary;
|
|
211
|
+
scenarios: ReportScenario[];
|
|
212
|
+
}
|
|
213
|
+
interface StoryReport {
|
|
214
|
+
schemaVersion: StoryReportSchemaVersion;
|
|
215
|
+
runId: string;
|
|
216
|
+
startedAtMs: number;
|
|
217
|
+
finishedAtMs: number;
|
|
218
|
+
durationMs: number;
|
|
219
|
+
projectRoot: string;
|
|
220
|
+
packageVersion?: string;
|
|
221
|
+
gitSha?: string;
|
|
222
|
+
ci?: ReportCIInfo;
|
|
223
|
+
coverage?: ReportCoverageSummary;
|
|
224
|
+
summary: ReportSummary;
|
|
225
|
+
features: ReportFeature[];
|
|
226
|
+
}
|
|
4
227
|
|
|
5
228
|
/**
|
|
6
229
|
* Result<T> — explicit success/error type matching the cookbook convention.
|
|
@@ -43,6 +266,20 @@ interface BuiltinRenderers {
|
|
|
43
266
|
section?: (entry: ReportDocSection) => ReactNode;
|
|
44
267
|
}
|
|
45
268
|
|
|
269
|
+
type ScenarioRunStatus = "passed" | "failed" | "skipped" | "pending";
|
|
270
|
+
/** One historical run of a scenario, oldest → newest in a history array. */
|
|
271
|
+
interface ScenarioRunEvent {
|
|
272
|
+
/** Epoch ms the run started. */
|
|
273
|
+
timestamp: number;
|
|
274
|
+
status: ScenarioRunStatus;
|
|
275
|
+
runId?: string;
|
|
276
|
+
durationMs?: number;
|
|
277
|
+
commitSha?: string;
|
|
278
|
+
branch?: string;
|
|
279
|
+
}
|
|
280
|
+
/** Recent run events keyed by ReportScenario.id. */
|
|
281
|
+
type ScenarioHistoryMap = Record<string, ScenarioRunEvent[]>;
|
|
282
|
+
|
|
46
283
|
interface ReportInteractiveProps {
|
|
47
284
|
/** A StoryReport, or a Result-wrapped one (e.g., from parseStoryReport). */
|
|
48
285
|
report: StoryReport | Result<StoryReport>;
|
|
@@ -60,6 +297,16 @@ interface ReportInteractiveProps {
|
|
|
60
297
|
* Starlight, where Starlight renders the page `<h1>`.
|
|
61
298
|
*/
|
|
62
299
|
hideHeader?: boolean;
|
|
300
|
+
/**
|
|
301
|
+
* Days before the report is flagged as stale (warning banner instead of the
|
|
302
|
+
* "Verified N ago" line). 0 disables the stale warning. Default 7.
|
|
303
|
+
*/
|
|
304
|
+
staleAfterDays?: number;
|
|
305
|
+
/**
|
|
306
|
+
* Recent run events per scenario id (from the CLI's --history-file store).
|
|
307
|
+
* When present, scenario cards show a run-over-run timeline strip.
|
|
308
|
+
*/
|
|
309
|
+
scenarioHistory?: ScenarioHistoryMap;
|
|
63
310
|
}
|
|
64
311
|
declare function ReportInteractive(props: ReportInteractiveProps): react.JSX.Element;
|
|
65
312
|
|
|
@@ -134,6 +381,26 @@ interface ReportFailureBannerProps {
|
|
|
134
381
|
}
|
|
135
382
|
declare function ReportFailureBanner({ failures }: ReportFailureBannerProps): react.JSX.Element | null;
|
|
136
383
|
|
|
384
|
+
interface ReportFreshnessProps {
|
|
385
|
+
/** Epoch ms of the run this report documents (see reportLastRunMs). */
|
|
386
|
+
lastRunMs?: number;
|
|
387
|
+
/** CI run URL, linked from the banner so readers can check for newer runs. */
|
|
388
|
+
ciUrl?: string;
|
|
389
|
+
/** Days before the report counts as stale; 0 disables the warning. */
|
|
390
|
+
staleAfterDays: number;
|
|
391
|
+
/** Test seam: fixed "now"; defaults to Date.now() on mount. */
|
|
392
|
+
nowMs?: number;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* The report's freshness signal. Fresh reports get a one-line "Last verified
|
|
396
|
+
* N ago" status; reports older than `staleAfterDays` get a warning banner —
|
|
397
|
+
* living documentation is only trustworthy while it is recent.
|
|
398
|
+
*
|
|
399
|
+
* Age is computed on mount (never during server render): the static HTML is
|
|
400
|
+
* generated once but read later, so any age baked in at build time would lie.
|
|
401
|
+
*/
|
|
402
|
+
declare function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }: ReportFreshnessProps): react.JSX.Element | null;
|
|
403
|
+
|
|
137
404
|
interface ReportShortcutsHelpProps {
|
|
138
405
|
open: boolean;
|
|
139
406
|
onClose: () => void;
|
|
@@ -163,4 +430,4 @@ declare function useKeyboardShortcuts(handlers: KeyboardShortcutHandlers): void;
|
|
|
163
430
|
*/
|
|
164
431
|
declare function useDeepLinkScroll(): void;
|
|
165
432
|
|
|
166
|
-
export { type FailureRef, type IslandRendererOptions, type KeyboardShortcutHandlers, ReportFailureBanner, type ReportFailureBannerProps, ReportInteractive, ReportInteractiveIsland, type ReportInteractiveIslandProps, type ReportInteractiveProps, ReportSearch, type ReportSearchProps, ReportShortcutsHelp, type ReportShortcutsHelpProps, buildIslandRenderers, filterReport, listFailures, normalizeQuery, useDeepLinkScroll, useKeyboardShortcuts };
|
|
433
|
+
export { type FailureRef, type IslandRendererOptions, type KeyboardShortcutHandlers, ReportFailureBanner, type ReportFailureBannerProps, ReportFreshness, type ReportFreshnessProps, ReportInteractive, ReportInteractiveIsland, type ReportInteractiveIslandProps, type ReportInteractiveProps, ReportSearch, type ReportSearchProps, ReportShortcutsHelp, type ReportShortcutsHelpProps, buildIslandRenderers, filterReport, listFailures, normalizeQuery, useDeepLinkScroll, useKeyboardShortcuts };
|
package/dist/interactive.d.ts
CHANGED
|
@@ -1,6 +1,229 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* OTel span types for trace waterfall rendering.
|
|
6
|
+
*
|
|
7
|
+
* Structurally compatible with autotel's SerializedSpan
|
|
8
|
+
* and raw OTel nanosecond formats. No import dependency on autotel.
|
|
9
|
+
*/
|
|
10
|
+
type OtelAttributeValue = string | number | boolean | string[] | number[] | boolean[];
|
|
11
|
+
interface OtelSpan {
|
|
12
|
+
spanId: string;
|
|
13
|
+
parentSpanId?: string;
|
|
14
|
+
name: string;
|
|
15
|
+
/** Preferred: epoch-based milliseconds (from autotel's SerializedSpan) */
|
|
16
|
+
startTimeMs?: number;
|
|
17
|
+
durationMs?: number;
|
|
18
|
+
/** Compatibility: raw OTel nanosecond timestamps */
|
|
19
|
+
startTimeUnixNano?: number;
|
|
20
|
+
endTimeUnixNano?: number;
|
|
21
|
+
status: "ok" | "error" | "unset";
|
|
22
|
+
statusMessage?: string;
|
|
23
|
+
attributes?: Record<string, OtelAttributeValue>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Phase tracks when the doc entry was added */
|
|
27
|
+
type DocPhase = "static" | "runtime";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* StoryReport — public, frozen contract for UI renderers.
|
|
31
|
+
*
|
|
32
|
+
* Distinct from internal TestRunResult. Pre-grouped feature → scenario tree,
|
|
33
|
+
* with pre-computed summaries at every level. Adapter concerns (rawStatus,
|
|
34
|
+
* projectName, titlePath) are stripped at the toStoryReport boundary.
|
|
35
|
+
*
|
|
36
|
+
* Versioning: semver-style "<major>.<minor>". Additive-only within a major.
|
|
37
|
+
* Source of truth: schemas/story-report-v1.json. Types here must stay in sync.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
type StoryReportSchemaVersion = `1.${number}`;
|
|
41
|
+
type TestStatus = "passed" | "failed" | "skipped" | "pending";
|
|
42
|
+
type StepKeyword = "Given" | "When" | "Then" | "And" | "But";
|
|
43
|
+
type StepMode = "normal" | "skip" | "only" | "todo" | "fails" | "concurrent";
|
|
44
|
+
interface ReportSummary {
|
|
45
|
+
total: number;
|
|
46
|
+
passed: number;
|
|
47
|
+
failed: number;
|
|
48
|
+
skipped: number;
|
|
49
|
+
pending: number;
|
|
50
|
+
durationMs: number;
|
|
51
|
+
}
|
|
52
|
+
interface ReportTicket {
|
|
53
|
+
id: string;
|
|
54
|
+
url?: string;
|
|
55
|
+
}
|
|
56
|
+
interface ReportAttachment {
|
|
57
|
+
name: string;
|
|
58
|
+
mediaType: string;
|
|
59
|
+
body: string;
|
|
60
|
+
contentEncoding: "BASE64" | "IDENTITY";
|
|
61
|
+
}
|
|
62
|
+
interface ReportCIInfo {
|
|
63
|
+
name: string;
|
|
64
|
+
url?: string;
|
|
65
|
+
buildNumber?: string;
|
|
66
|
+
branch?: string;
|
|
67
|
+
commitSha?: string;
|
|
68
|
+
prNumber?: string;
|
|
69
|
+
}
|
|
70
|
+
interface ReportCoverageSummary {
|
|
71
|
+
linesPct?: number;
|
|
72
|
+
branchesPct?: number;
|
|
73
|
+
functionsPct?: number;
|
|
74
|
+
statementsPct?: number;
|
|
75
|
+
}
|
|
76
|
+
type ReportDocEntry = ReportDocNote | ReportDocTag | ReportDocKv | ReportDocCode | ReportDocTable | ReportDocLink | ReportDocSection | ReportDocMermaid | ReportDocScreenshot | ReportDocVideo | ReportDocHtml | ReportDocCustom;
|
|
77
|
+
interface ReportDocNote {
|
|
78
|
+
kind: "note";
|
|
79
|
+
text: string;
|
|
80
|
+
phase: DocPhase;
|
|
81
|
+
children?: ReportDocEntry[];
|
|
82
|
+
}
|
|
83
|
+
interface ReportDocTag {
|
|
84
|
+
kind: "tag";
|
|
85
|
+
names: string[];
|
|
86
|
+
phase: DocPhase;
|
|
87
|
+
children?: ReportDocEntry[];
|
|
88
|
+
}
|
|
89
|
+
interface ReportDocKv {
|
|
90
|
+
kind: "kv";
|
|
91
|
+
label: string;
|
|
92
|
+
value: unknown;
|
|
93
|
+
phase: DocPhase;
|
|
94
|
+
children?: ReportDocEntry[];
|
|
95
|
+
}
|
|
96
|
+
interface ReportDocCode {
|
|
97
|
+
kind: "code";
|
|
98
|
+
label: string;
|
|
99
|
+
content: string;
|
|
100
|
+
lang?: string;
|
|
101
|
+
phase: DocPhase;
|
|
102
|
+
children?: ReportDocEntry[];
|
|
103
|
+
}
|
|
104
|
+
interface ReportDocTable {
|
|
105
|
+
kind: "table";
|
|
106
|
+
label: string;
|
|
107
|
+
columns: string[];
|
|
108
|
+
rows: string[][];
|
|
109
|
+
phase: DocPhase;
|
|
110
|
+
children?: ReportDocEntry[];
|
|
111
|
+
}
|
|
112
|
+
interface ReportDocLink {
|
|
113
|
+
kind: "link";
|
|
114
|
+
label: string;
|
|
115
|
+
url: string;
|
|
116
|
+
phase: DocPhase;
|
|
117
|
+
children?: ReportDocEntry[];
|
|
118
|
+
}
|
|
119
|
+
interface ReportDocSection {
|
|
120
|
+
kind: "section";
|
|
121
|
+
title: string;
|
|
122
|
+
markdown: string;
|
|
123
|
+
phase: DocPhase;
|
|
124
|
+
children?: ReportDocEntry[];
|
|
125
|
+
}
|
|
126
|
+
interface ReportDocMermaid {
|
|
127
|
+
kind: "mermaid";
|
|
128
|
+
code: string;
|
|
129
|
+
title?: string;
|
|
130
|
+
phase: DocPhase;
|
|
131
|
+
children?: ReportDocEntry[];
|
|
132
|
+
}
|
|
133
|
+
interface ReportDocScreenshot {
|
|
134
|
+
kind: "screenshot";
|
|
135
|
+
path: string;
|
|
136
|
+
alt?: string;
|
|
137
|
+
phase: DocPhase;
|
|
138
|
+
children?: ReportDocEntry[];
|
|
139
|
+
}
|
|
140
|
+
interface ReportDocVideo {
|
|
141
|
+
kind: "video";
|
|
142
|
+
path: string;
|
|
143
|
+
caption?: string;
|
|
144
|
+
poster?: string;
|
|
145
|
+
phase: DocPhase;
|
|
146
|
+
children?: ReportDocEntry[];
|
|
147
|
+
}
|
|
148
|
+
interface ReportDocHtml {
|
|
149
|
+
kind: "html";
|
|
150
|
+
/** Local HTML file path (exactly one of path/url/content) */
|
|
151
|
+
path?: string;
|
|
152
|
+
/** Remote URL rendered via iframe src (exactly one of path/url/content) */
|
|
153
|
+
url?: string;
|
|
154
|
+
/** Inline HTML content rendered via iframe srcdoc (exactly one of path/url/content) */
|
|
155
|
+
content?: string;
|
|
156
|
+
title?: string;
|
|
157
|
+
/** Iframe height: number → px, string passed through (e.g. "60vh"). Default 400px. */
|
|
158
|
+
height?: number | string;
|
|
159
|
+
phase: DocPhase;
|
|
160
|
+
children?: ReportDocEntry[];
|
|
161
|
+
}
|
|
162
|
+
interface ReportDocCustom {
|
|
163
|
+
kind: "custom";
|
|
164
|
+
type: string;
|
|
165
|
+
data: unknown;
|
|
166
|
+
phase: DocPhase;
|
|
167
|
+
children?: ReportDocEntry[];
|
|
168
|
+
}
|
|
169
|
+
interface ReportStep {
|
|
170
|
+
id: string;
|
|
171
|
+
index: number;
|
|
172
|
+
keyword: StepKeyword;
|
|
173
|
+
text: string;
|
|
174
|
+
status: TestStatus;
|
|
175
|
+
durationMs: number;
|
|
176
|
+
errorMessage?: string;
|
|
177
|
+
mode?: StepMode;
|
|
178
|
+
docEntries: ReportDocEntry[];
|
|
179
|
+
}
|
|
180
|
+
interface ReportScenario {
|
|
181
|
+
id: string;
|
|
182
|
+
title: string;
|
|
183
|
+
status: TestStatus;
|
|
184
|
+
/**
|
|
185
|
+
* True for scenarios authored with the framework's todo modifier
|
|
186
|
+
* (e.g. `it.todo`): specified behavior with no implementation yet.
|
|
187
|
+
* Canonical status stays "pending"; this flags why.
|
|
188
|
+
*/
|
|
189
|
+
planned?: boolean;
|
|
190
|
+
durationMs: number;
|
|
191
|
+
tags: string[];
|
|
192
|
+
tickets?: ReportTicket[];
|
|
193
|
+
/** Product-code paths/globs this scenario exercises (project-root-relative). */
|
|
194
|
+
covers?: string[];
|
|
195
|
+
sourceLine?: number;
|
|
196
|
+
errorMessage?: string;
|
|
197
|
+
errorStack?: string;
|
|
198
|
+
retry: number;
|
|
199
|
+
retries: number;
|
|
200
|
+
docEntries: ReportDocEntry[];
|
|
201
|
+
steps: ReportStep[];
|
|
202
|
+
attachments: ReportAttachment[];
|
|
203
|
+
/** OTel spans for the trace waterfall (carried through from the run). */
|
|
204
|
+
otelSpans?: OtelSpan[];
|
|
205
|
+
}
|
|
206
|
+
interface ReportFeature {
|
|
207
|
+
id: string;
|
|
208
|
+
title: string;
|
|
209
|
+
sourceFile: string;
|
|
210
|
+
summary: ReportSummary;
|
|
211
|
+
scenarios: ReportScenario[];
|
|
212
|
+
}
|
|
213
|
+
interface StoryReport {
|
|
214
|
+
schemaVersion: StoryReportSchemaVersion;
|
|
215
|
+
runId: string;
|
|
216
|
+
startedAtMs: number;
|
|
217
|
+
finishedAtMs: number;
|
|
218
|
+
durationMs: number;
|
|
219
|
+
projectRoot: string;
|
|
220
|
+
packageVersion?: string;
|
|
221
|
+
gitSha?: string;
|
|
222
|
+
ci?: ReportCIInfo;
|
|
223
|
+
coverage?: ReportCoverageSummary;
|
|
224
|
+
summary: ReportSummary;
|
|
225
|
+
features: ReportFeature[];
|
|
226
|
+
}
|
|
4
227
|
|
|
5
228
|
/**
|
|
6
229
|
* Result<T> — explicit success/error type matching the cookbook convention.
|
|
@@ -43,6 +266,20 @@ interface BuiltinRenderers {
|
|
|
43
266
|
section?: (entry: ReportDocSection) => ReactNode;
|
|
44
267
|
}
|
|
45
268
|
|
|
269
|
+
type ScenarioRunStatus = "passed" | "failed" | "skipped" | "pending";
|
|
270
|
+
/** One historical run of a scenario, oldest → newest in a history array. */
|
|
271
|
+
interface ScenarioRunEvent {
|
|
272
|
+
/** Epoch ms the run started. */
|
|
273
|
+
timestamp: number;
|
|
274
|
+
status: ScenarioRunStatus;
|
|
275
|
+
runId?: string;
|
|
276
|
+
durationMs?: number;
|
|
277
|
+
commitSha?: string;
|
|
278
|
+
branch?: string;
|
|
279
|
+
}
|
|
280
|
+
/** Recent run events keyed by ReportScenario.id. */
|
|
281
|
+
type ScenarioHistoryMap = Record<string, ScenarioRunEvent[]>;
|
|
282
|
+
|
|
46
283
|
interface ReportInteractiveProps {
|
|
47
284
|
/** A StoryReport, or a Result-wrapped one (e.g., from parseStoryReport). */
|
|
48
285
|
report: StoryReport | Result<StoryReport>;
|
|
@@ -60,6 +297,16 @@ interface ReportInteractiveProps {
|
|
|
60
297
|
* Starlight, where Starlight renders the page `<h1>`.
|
|
61
298
|
*/
|
|
62
299
|
hideHeader?: boolean;
|
|
300
|
+
/**
|
|
301
|
+
* Days before the report is flagged as stale (warning banner instead of the
|
|
302
|
+
* "Verified N ago" line). 0 disables the stale warning. Default 7.
|
|
303
|
+
*/
|
|
304
|
+
staleAfterDays?: number;
|
|
305
|
+
/**
|
|
306
|
+
* Recent run events per scenario id (from the CLI's --history-file store).
|
|
307
|
+
* When present, scenario cards show a run-over-run timeline strip.
|
|
308
|
+
*/
|
|
309
|
+
scenarioHistory?: ScenarioHistoryMap;
|
|
63
310
|
}
|
|
64
311
|
declare function ReportInteractive(props: ReportInteractiveProps): react.JSX.Element;
|
|
65
312
|
|
|
@@ -134,6 +381,26 @@ interface ReportFailureBannerProps {
|
|
|
134
381
|
}
|
|
135
382
|
declare function ReportFailureBanner({ failures }: ReportFailureBannerProps): react.JSX.Element | null;
|
|
136
383
|
|
|
384
|
+
interface ReportFreshnessProps {
|
|
385
|
+
/** Epoch ms of the run this report documents (see reportLastRunMs). */
|
|
386
|
+
lastRunMs?: number;
|
|
387
|
+
/** CI run URL, linked from the banner so readers can check for newer runs. */
|
|
388
|
+
ciUrl?: string;
|
|
389
|
+
/** Days before the report counts as stale; 0 disables the warning. */
|
|
390
|
+
staleAfterDays: number;
|
|
391
|
+
/** Test seam: fixed "now"; defaults to Date.now() on mount. */
|
|
392
|
+
nowMs?: number;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* The report's freshness signal. Fresh reports get a one-line "Last verified
|
|
396
|
+
* N ago" status; reports older than `staleAfterDays` get a warning banner —
|
|
397
|
+
* living documentation is only trustworthy while it is recent.
|
|
398
|
+
*
|
|
399
|
+
* Age is computed on mount (never during server render): the static HTML is
|
|
400
|
+
* generated once but read later, so any age baked in at build time would lie.
|
|
401
|
+
*/
|
|
402
|
+
declare function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }: ReportFreshnessProps): react.JSX.Element | null;
|
|
403
|
+
|
|
137
404
|
interface ReportShortcutsHelpProps {
|
|
138
405
|
open: boolean;
|
|
139
406
|
onClose: () => void;
|
|
@@ -163,4 +430,4 @@ declare function useKeyboardShortcuts(handlers: KeyboardShortcutHandlers): void;
|
|
|
163
430
|
*/
|
|
164
431
|
declare function useDeepLinkScroll(): void;
|
|
165
432
|
|
|
166
|
-
export { type FailureRef, type IslandRendererOptions, type KeyboardShortcutHandlers, ReportFailureBanner, type ReportFailureBannerProps, ReportInteractive, ReportInteractiveIsland, type ReportInteractiveIslandProps, type ReportInteractiveProps, ReportSearch, type ReportSearchProps, ReportShortcutsHelp, type ReportShortcutsHelpProps, buildIslandRenderers, filterReport, listFailures, normalizeQuery, useDeepLinkScroll, useKeyboardShortcuts };
|
|
433
|
+
export { type FailureRef, type IslandRendererOptions, type KeyboardShortcutHandlers, ReportFailureBanner, type ReportFailureBannerProps, ReportFreshness, type ReportFreshnessProps, ReportInteractive, ReportInteractiveIsland, type ReportInteractiveIslandProps, type ReportInteractiveProps, ReportSearch, type ReportSearchProps, ReportShortcutsHelp, type ReportShortcutsHelpProps, buildIslandRenderers, filterReport, listFailures, normalizeQuery, useDeepLinkScroll, useKeyboardShortcuts };
|