executable-stories-react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +238 -0
- package/dist/index.cjs +1021 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +202 -0
- package/dist/index.d.ts +202 -0
- package/dist/index.js +964 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive.cjs +846 -0
- package/dist/interactive.cjs.map +1 -0
- package/dist/interactive.d.cts +116 -0
- package/dist/interactive.d.ts +116 -0
- package/dist/interactive.js +820 -0
- package/dist/interactive.js.map +1 -0
- package/dist/parse.cjs +495 -0
- package/dist/parse.cjs.map +1 -0
- package/dist/parse.d.cts +51 -0
- package/dist/parse.d.ts +51 -0
- package/dist/parse.js +464 -0
- package/dist/parse.js.map +1 -0
- package/dist/styles.css +244 -0
- package/package.json +84 -0
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/interactive/index.ts
|
|
22
|
+
var interactive_exports = {};
|
|
23
|
+
__export(interactive_exports, {
|
|
24
|
+
ReportFailureBanner: () => ReportFailureBanner,
|
|
25
|
+
ReportInteractive: () => ReportInteractive,
|
|
26
|
+
ReportSearch: () => ReportSearch,
|
|
27
|
+
ReportShortcutsHelp: () => ReportShortcutsHelp,
|
|
28
|
+
filterReport: () => filterReport,
|
|
29
|
+
listFailures: () => listFailures,
|
|
30
|
+
normalizeQuery: () => normalizeQuery,
|
|
31
|
+
useDeepLinkScroll: () => useDeepLinkScroll,
|
|
32
|
+
useKeyboardShortcuts: () => useKeyboardShortcuts
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(interactive_exports);
|
|
35
|
+
|
|
36
|
+
// src/interactive/ReportInteractive.tsx
|
|
37
|
+
var import_react10 = require("react");
|
|
38
|
+
|
|
39
|
+
// src/context/ReportRoot.tsx
|
|
40
|
+
var import_react2 = require("react");
|
|
41
|
+
|
|
42
|
+
// src/context/ReportContext.ts
|
|
43
|
+
var import_react = require("react");
|
|
44
|
+
var ReportContext = (0, import_react.createContext)(null);
|
|
45
|
+
|
|
46
|
+
// src/context/ReportRoot.tsx
|
|
47
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
48
|
+
var EMPTY_CUSTOM = {};
|
|
49
|
+
var EMPTY_RENDERERS = {};
|
|
50
|
+
function ReportRoot({
|
|
51
|
+
report,
|
|
52
|
+
customRenderers,
|
|
53
|
+
renderers,
|
|
54
|
+
children
|
|
55
|
+
}) {
|
|
56
|
+
const value = (0, import_react2.useMemo)(
|
|
57
|
+
() => ({
|
|
58
|
+
report,
|
|
59
|
+
customRenderers: customRenderers ?? EMPTY_CUSTOM,
|
|
60
|
+
renderers: renderers ?? EMPTY_RENDERERS
|
|
61
|
+
}),
|
|
62
|
+
[report, customRenderers, renderers]
|
|
63
|
+
);
|
|
64
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReportContext.Provider, { value, children });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/hooks/useReport.ts
|
|
68
|
+
var import_react3 = require("react");
|
|
69
|
+
function useReport() {
|
|
70
|
+
const ctx = (0, import_react3.useContext)(ReportContext);
|
|
71
|
+
if (!ctx) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return ctx.report;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/components/ReportSummary.tsx
|
|
80
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
81
|
+
function ReportSummary({ className }) {
|
|
82
|
+
const report = useReport();
|
|
83
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
84
|
+
ReportSummaryView,
|
|
85
|
+
{
|
|
86
|
+
summary: report.summary,
|
|
87
|
+
...className !== void 0 && { className },
|
|
88
|
+
ariaLabel: "Run summary"
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
93
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
94
|
+
"p",
|
|
95
|
+
{
|
|
96
|
+
className: ["es-report-summary", className].filter(Boolean).join(" "),
|
|
97
|
+
"aria-label": ariaLabel,
|
|
98
|
+
children: [
|
|
99
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
100
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: summary.total }),
|
|
101
|
+
" scenario",
|
|
102
|
+
summary.total === 1 ? "" : "s"
|
|
103
|
+
] }),
|
|
104
|
+
" \xB7 ",
|
|
105
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { "data-status": "passed", children: [
|
|
106
|
+
summary.passed,
|
|
107
|
+
" passed"
|
|
108
|
+
] }),
|
|
109
|
+
" \xB7 ",
|
|
110
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { "data-status": "failed", children: [
|
|
111
|
+
summary.failed,
|
|
112
|
+
" failed"
|
|
113
|
+
] }),
|
|
114
|
+
summary.skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
115
|
+
" \xB7 ",
|
|
116
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { "data-status": "skipped", children: [
|
|
117
|
+
summary.skipped,
|
|
118
|
+
" skipped"
|
|
119
|
+
] })
|
|
120
|
+
] }) : null,
|
|
121
|
+
summary.pending > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
122
|
+
" \xB7 ",
|
|
123
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { "data-status": "pending", children: [
|
|
124
|
+
summary.pending,
|
|
125
|
+
" pending"
|
|
126
|
+
] })
|
|
127
|
+
] }) : null
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/components/doc/DocNote.tsx
|
|
134
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
135
|
+
function DocNote({ entry }) {
|
|
136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "es-doc es-doc-note", children: entry.text });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/components/doc/DocTag.tsx
|
|
140
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
141
|
+
function DocTag({ entry }) {
|
|
142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "es-doc es-tags", "aria-label": "Tags", children: entry.names.map((n) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: n }, n)) });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/components/doc/DocKv.tsx
|
|
146
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
147
|
+
function formatValue(value) {
|
|
148
|
+
if (value === null) return "null";
|
|
149
|
+
if (typeof value === "string") return value;
|
|
150
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
151
|
+
try {
|
|
152
|
+
return JSON.stringify(value);
|
|
153
|
+
} catch {
|
|
154
|
+
return String(value);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function DocKv({ entry }) {
|
|
158
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "es-doc es-doc-kv", children: [
|
|
159
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: entry.label }),
|
|
160
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: formatValue(entry.value) })
|
|
161
|
+
] });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/hooks/useRenderers.ts
|
|
165
|
+
var import_react4 = require("react");
|
|
166
|
+
var EMPTY_CUSTOM2 = {};
|
|
167
|
+
var EMPTY_RENDERERS2 = {};
|
|
168
|
+
function useCustomRenderers() {
|
|
169
|
+
const ctx = (0, import_react4.useContext)(ReportContext);
|
|
170
|
+
return ctx?.customRenderers ?? EMPTY_CUSTOM2;
|
|
171
|
+
}
|
|
172
|
+
function useBuiltinRenderers() {
|
|
173
|
+
const ctx = (0, import_react4.useContext)(ReportContext);
|
|
174
|
+
return ctx?.renderers ?? EMPTY_RENDERERS2;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/components/doc/DocCode.tsx
|
|
178
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
179
|
+
function DocCode({ entry }) {
|
|
180
|
+
const renderers = useBuiltinRenderers();
|
|
181
|
+
if (renderers.code) {
|
|
182
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: renderers.code(entry) });
|
|
183
|
+
}
|
|
184
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("figure", { className: "es-doc es-doc-code", children: [
|
|
185
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("figcaption", { children: entry.label }),
|
|
186
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: entry.lang ? `language-${entry.lang}` : void 0, children: entry.content }) })
|
|
187
|
+
] });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/components/doc/DocTable.tsx
|
|
191
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
192
|
+
function DocTable({ entry }) {
|
|
193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("figure", { className: "es-doc es-doc-table", children: [
|
|
194
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("figcaption", { children: entry.label }),
|
|
195
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { children: [
|
|
196
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { children: entry.columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { scope: "col", children: c }, c)) }) }),
|
|
197
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { children: row.map((cell, j) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { children: cell }, j)) }, i)) })
|
|
198
|
+
] })
|
|
199
|
+
] });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/components/doc/DocLink.tsx
|
|
203
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
204
|
+
function DocLink({ entry }) {
|
|
205
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
206
|
+
"a",
|
|
207
|
+
{
|
|
208
|
+
className: "es-doc es-doc-link",
|
|
209
|
+
href: entry.url,
|
|
210
|
+
rel: "noreferrer noopener",
|
|
211
|
+
target: "_blank",
|
|
212
|
+
children: entry.label
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/components/doc/DocSection.tsx
|
|
218
|
+
var import_marked = require("marked");
|
|
219
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
220
|
+
function safeMarkdownHtml(markdown) {
|
|
221
|
+
const raw = import_marked.marked.parse(markdown, { async: false });
|
|
222
|
+
return raw.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/\son[a-z]+\s*=\s*"[^"]*"/gi, "").replace(/\son[a-z]+\s*=\s*'[^']*'/gi, "").replace(/\son[a-z]+\s*=\s*[^\s>]+/gi, "").replace(/(href|src)\s*=\s*"\s*javascript:[^"]*"/gi, '$1="#"').replace(/(href|src)\s*=\s*'\s*javascript:[^']*'/gi, "$1='#'");
|
|
223
|
+
}
|
|
224
|
+
function DocSection({ entry }) {
|
|
225
|
+
const renderers = useBuiltinRenderers();
|
|
226
|
+
if (renderers.section) {
|
|
227
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: renderers.section(entry) });
|
|
228
|
+
}
|
|
229
|
+
const html = safeMarkdownHtml(entry.markdown);
|
|
230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { className: "es-doc es-doc-section", "aria-label": entry.title, children: [
|
|
231
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h4", { className: "es-doc-section-title", children: entry.title }) : null,
|
|
232
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
233
|
+
"div",
|
|
234
|
+
{
|
|
235
|
+
className: "es-doc-section-content",
|
|
236
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
237
|
+
}
|
|
238
|
+
)
|
|
239
|
+
] });
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/components/doc/DocMermaid.tsx
|
|
243
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
244
|
+
function DocMermaid({ entry }) {
|
|
245
|
+
const renderers = useBuiltinRenderers();
|
|
246
|
+
if (renderers.mermaid) {
|
|
247
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: renderers.mermaid(entry) });
|
|
248
|
+
}
|
|
249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
250
|
+
"figure",
|
|
251
|
+
{
|
|
252
|
+
className: "es-doc es-doc-mermaid",
|
|
253
|
+
"aria-label": entry.title ?? "Diagram",
|
|
254
|
+
children: [
|
|
255
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("figcaption", { children: entry.title }) : null,
|
|
256
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("pre", { "data-mermaid": true, children: entry.code })
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/components/doc/DocScreenshot.tsx
|
|
263
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
264
|
+
function DocScreenshot({ entry }) {
|
|
265
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "es-doc es-doc-screenshot", children: [
|
|
266
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { src: entry.path, alt: entry.alt ?? "", loading: "lazy" }),
|
|
267
|
+
entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { children: entry.alt }) : null
|
|
268
|
+
] });
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/components/doc/DocCustom.tsx
|
|
272
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
273
|
+
function DocCustom({ entry }) {
|
|
274
|
+
const renderers = useCustomRenderers();
|
|
275
|
+
const renderer = renderers[entry.type];
|
|
276
|
+
if (renderer) {
|
|
277
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: renderer(entry) });
|
|
278
|
+
}
|
|
279
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "es-doc es-doc-custom", "data-type": entry.type, children: [
|
|
280
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "es-doc-custom-type", children: entry.type }),
|
|
281
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("pre", { children: safeStringify(entry.data) })
|
|
282
|
+
] });
|
|
283
|
+
}
|
|
284
|
+
function safeStringify(value) {
|
|
285
|
+
try {
|
|
286
|
+
return JSON.stringify(value, null, 2);
|
|
287
|
+
} catch {
|
|
288
|
+
return String(value);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// src/components/doc/DocEntry.tsx
|
|
293
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
294
|
+
function DocEntry({ entry }) {
|
|
295
|
+
switch (entry.kind) {
|
|
296
|
+
case "note":
|
|
297
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocNote, { entry });
|
|
298
|
+
case "tag":
|
|
299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocTag, { entry });
|
|
300
|
+
case "kv":
|
|
301
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocKv, { entry });
|
|
302
|
+
case "code":
|
|
303
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocCode, { entry });
|
|
304
|
+
case "table":
|
|
305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocTable, { entry });
|
|
306
|
+
case "link":
|
|
307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocLink, { entry });
|
|
308
|
+
case "section":
|
|
309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocSection, { entry });
|
|
310
|
+
case "mermaid":
|
|
311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocMermaid, { entry });
|
|
312
|
+
case "screenshot":
|
|
313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocScreenshot, { entry });
|
|
314
|
+
case "custom":
|
|
315
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocCustom, { entry });
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/components/ReportDocEntries.tsx
|
|
320
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
321
|
+
function ReportDocEntries({ entries }) {
|
|
322
|
+
if (entries.length === 0) return null;
|
|
323
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocEntry, { entry }, i)) });
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// src/components/ReportSteps.tsx
|
|
327
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
328
|
+
function ReportSteps({ scenario }) {
|
|
329
|
+
if (scenario.steps.length === 0) return null;
|
|
330
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("ol", { className: "es-steps", children: scenario.steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ReportStepItem, { step }, step.id)) });
|
|
331
|
+
}
|
|
332
|
+
function ReportStepItem({ step }) {
|
|
333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
334
|
+
"li",
|
|
335
|
+
{
|
|
336
|
+
id: step.id,
|
|
337
|
+
className: `es-step es-step-${step.status}`,
|
|
338
|
+
"data-status": step.status,
|
|
339
|
+
children: [
|
|
340
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "es-step-keyword", children: step.keyword }),
|
|
341
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "es-step-text", children: step.text }),
|
|
342
|
+
step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("pre", { className: "es-scenario-error", role: "alert", children: step.errorMessage }) : null,
|
|
343
|
+
step.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "es-step-docs", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ReportDocEntries, { entries: step.docEntries }) }) : null
|
|
344
|
+
]
|
|
345
|
+
}
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// src/components/ReportScenario.tsx
|
|
350
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
351
|
+
var STATUS_LABEL = {
|
|
352
|
+
passed: "Passed",
|
|
353
|
+
failed: "Failed",
|
|
354
|
+
skipped: "Skipped",
|
|
355
|
+
pending: "Pending"
|
|
356
|
+
};
|
|
357
|
+
function ReportScenario({ scenario }) {
|
|
358
|
+
const titleId = `${scenario.id}-title`;
|
|
359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
360
|
+
"article",
|
|
361
|
+
{
|
|
362
|
+
id: scenario.id,
|
|
363
|
+
className: `es-scenario es-status-${scenario.status}`,
|
|
364
|
+
"aria-labelledby": titleId,
|
|
365
|
+
"data-status": scenario.status,
|
|
366
|
+
children: [
|
|
367
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("h3", { id: titleId, className: "es-scenario-title", children: [
|
|
368
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: scenario.title }),
|
|
369
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "es-scenario-status", "aria-label": `Status: ${STATUS_LABEL[scenario.status]}`, children: STATUS_LABEL[scenario.status] })
|
|
370
|
+
] }),
|
|
371
|
+
scenario.tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("ul", { className: "es-tags", "aria-label": "Tags", children: scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("li", { children: t }, t)) }) : null,
|
|
372
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("pre", { className: "es-scenario-error", role: "alert", children: scenario.errorMessage }) : null,
|
|
373
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "es-scenario-docs", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ReportSteps, { scenario })
|
|
375
|
+
]
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// src/components/ReportScenarioList.tsx
|
|
381
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
382
|
+
function ReportScenarioList({ feature }) {
|
|
383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReportScenario, { scenario }, scenario.id)) });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/components/ReportFeature.tsx
|
|
387
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
388
|
+
function ReportFeature({ feature }) {
|
|
389
|
+
const titleId = `${feature.id}-title`;
|
|
390
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
391
|
+
"section",
|
|
392
|
+
{
|
|
393
|
+
id: feature.id,
|
|
394
|
+
className: "es-feature",
|
|
395
|
+
"aria-labelledby": titleId,
|
|
396
|
+
children: [
|
|
397
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h2", { id: titleId, className: "es-feature-title", children: feature.title }),
|
|
398
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "es-feature-source", children: feature.sourceFile }),
|
|
399
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportSummaryView, { summary: feature.summary, className: "es-feature-summary" }),
|
|
400
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportScenarioList, { feature })
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// src/components/ReportFeatureList.tsx
|
|
407
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
408
|
+
function ReportFeatureList() {
|
|
409
|
+
const report = useReport();
|
|
410
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ReportFeature, { feature }, feature.id)) });
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/components/ReportEmpty.tsx
|
|
414
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
415
|
+
function ReportEmpty({ message }) {
|
|
416
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("section", { className: "es-empty", "aria-live": "polite", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: message ?? "No scenarios in this report." }) });
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// src/components/ReportSchemaError.tsx
|
|
420
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
421
|
+
function ReportSchemaError({ error }) {
|
|
422
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
423
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
424
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: error.message }),
|
|
425
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("p", { children: [
|
|
426
|
+
"The report bundle is newer than this version of ",
|
|
427
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("code", { children: "executable-stories-react" }),
|
|
428
|
+
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
429
|
+
] }) : null,
|
|
430
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { children: [
|
|
431
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { children: [
|
|
432
|
+
error.issues.length,
|
|
433
|
+
" validation issue",
|
|
434
|
+
error.issues.length === 1 ? "" : "s"
|
|
435
|
+
] }),
|
|
436
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
437
|
+
] }) : null
|
|
438
|
+
] });
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// src/interactive/ReportSearch.tsx
|
|
442
|
+
var import_react5 = require("react");
|
|
443
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
444
|
+
var ReportSearch = (0, import_react5.forwardRef)(
|
|
445
|
+
function ReportSearch2(props, ref) {
|
|
446
|
+
const {
|
|
447
|
+
value,
|
|
448
|
+
onChange,
|
|
449
|
+
matchedCount,
|
|
450
|
+
totalCount,
|
|
451
|
+
placeholder = "Search scenarios, tags, or step text\u2026",
|
|
452
|
+
className
|
|
453
|
+
} = props;
|
|
454
|
+
const inputId = (0, import_react5.useId)();
|
|
455
|
+
const showCounts = typeof matchedCount === "number" && typeof totalCount === "number";
|
|
456
|
+
function handleChange(e) {
|
|
457
|
+
onChange(e.target.value);
|
|
458
|
+
}
|
|
459
|
+
function handleKeyDown(e) {
|
|
460
|
+
if (e.key === "Escape" && value !== "") {
|
|
461
|
+
onChange("");
|
|
462
|
+
e.preventDefault();
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: ["es-search", className].filter(Boolean).join(" "), children: [
|
|
466
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { htmlFor: inputId, className: "es-search-label", children: "Search" }),
|
|
467
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
468
|
+
"input",
|
|
469
|
+
{
|
|
470
|
+
ref,
|
|
471
|
+
id: inputId,
|
|
472
|
+
type: "search",
|
|
473
|
+
value,
|
|
474
|
+
onChange: handleChange,
|
|
475
|
+
onKeyDown: handleKeyDown,
|
|
476
|
+
placeholder,
|
|
477
|
+
autoComplete: "off",
|
|
478
|
+
spellCheck: false,
|
|
479
|
+
"aria-keyshortcuts": "/"
|
|
480
|
+
}
|
|
481
|
+
),
|
|
482
|
+
showCounts ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "es-search-counts", "aria-live": "polite", children: value ? `${matchedCount} of ${totalCount}` : `${totalCount} total` }) : null
|
|
483
|
+
] });
|
|
484
|
+
}
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
// src/interactive/ReportFailureBanner.tsx
|
|
488
|
+
var import_react6 = require("react");
|
|
489
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
490
|
+
function ReportFailureBanner({ failures }) {
|
|
491
|
+
const first = failures[0];
|
|
492
|
+
const jumpToFirst = (0, import_react6.useCallback)(() => {
|
|
493
|
+
if (!first) return;
|
|
494
|
+
if (typeof window === "undefined") return;
|
|
495
|
+
const el = document.getElementById(first.scenarioId);
|
|
496
|
+
el?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
497
|
+
if (typeof history !== "undefined") {
|
|
498
|
+
history.replaceState(null, "", `#${first.scenarioId}`);
|
|
499
|
+
}
|
|
500
|
+
}, [first]);
|
|
501
|
+
if (failures.length === 0) return null;
|
|
502
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
503
|
+
"aside",
|
|
504
|
+
{
|
|
505
|
+
className: "es-failure-banner",
|
|
506
|
+
role: "status",
|
|
507
|
+
"aria-live": "polite",
|
|
508
|
+
"aria-label": "Failure summary",
|
|
509
|
+
children: [
|
|
510
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "es-failure-banner-text", children: [
|
|
511
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("strong", { children: failures.length }),
|
|
512
|
+
" ",
|
|
513
|
+
"failure",
|
|
514
|
+
failures.length === 1 ? "" : "s"
|
|
515
|
+
] }),
|
|
516
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
517
|
+
"button",
|
|
518
|
+
{
|
|
519
|
+
type: "button",
|
|
520
|
+
className: "es-failure-banner-jump",
|
|
521
|
+
onClick: jumpToFirst,
|
|
522
|
+
"aria-label": "Jump to first failure",
|
|
523
|
+
children: "Jump to first \u2193"
|
|
524
|
+
}
|
|
525
|
+
)
|
|
526
|
+
]
|
|
527
|
+
}
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// src/interactive/ReportShortcutsHelp.tsx
|
|
532
|
+
var import_react7 = require("react");
|
|
533
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
534
|
+
var SHORTCUTS = [
|
|
535
|
+
{ keys: "/", description: "Focus search" },
|
|
536
|
+
{ keys: "f", description: "Jump to next failure" },
|
|
537
|
+
{ keys: "Shift+F", description: "Jump to previous failure" },
|
|
538
|
+
{ keys: "Esc", description: "Clear search / close dialog" },
|
|
539
|
+
{ keys: "?", description: "Toggle this help" }
|
|
540
|
+
];
|
|
541
|
+
function ReportShortcutsHelp({ open, onClose }) {
|
|
542
|
+
const dialogRef = (0, import_react7.useRef)(null);
|
|
543
|
+
(0, import_react7.useEffect)(() => {
|
|
544
|
+
const dialog = dialogRef.current;
|
|
545
|
+
if (!dialog) return;
|
|
546
|
+
if (open && !dialog.open) dialog.showModal();
|
|
547
|
+
else if (!open && dialog.open) dialog.close();
|
|
548
|
+
}, [open]);
|
|
549
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
550
|
+
"dialog",
|
|
551
|
+
{
|
|
552
|
+
ref: dialogRef,
|
|
553
|
+
className: "es-shortcuts-help",
|
|
554
|
+
"aria-label": "Keyboard shortcuts",
|
|
555
|
+
onClose,
|
|
556
|
+
children: [
|
|
557
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { children: "Keyboard shortcuts" }),
|
|
558
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dl", { children: SHORTCUTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { children: [
|
|
559
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dt", { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("kbd", { children: s.keys }) }),
|
|
560
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dd", { children: s.description })
|
|
561
|
+
] }, s.keys)) }),
|
|
562
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("form", { method: "dialog", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "submit", className: "es-shortcuts-close", children: "Close" }) })
|
|
563
|
+
]
|
|
564
|
+
}
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// src/interactive/use-keyboard-shortcuts.ts
|
|
569
|
+
var import_react8 = require("react");
|
|
570
|
+
function isEditableTarget(target) {
|
|
571
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
572
|
+
const tag = target.tagName;
|
|
573
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
574
|
+
if (target.isContentEditable) return true;
|
|
575
|
+
return false;
|
|
576
|
+
}
|
|
577
|
+
function useKeyboardShortcuts(handlers) {
|
|
578
|
+
const ref = (0, import_react8.useRef)(handlers);
|
|
579
|
+
ref.current = handlers;
|
|
580
|
+
(0, import_react8.useEffect)(() => {
|
|
581
|
+
function onKeyDown(e) {
|
|
582
|
+
const h = ref.current;
|
|
583
|
+
if (e.key === "Escape") {
|
|
584
|
+
h.onEscape?.();
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
if (isEditableTarget(e.target)) return;
|
|
588
|
+
if (e.metaKey || e.ctrlKey || e.altKey) return;
|
|
589
|
+
switch (e.key) {
|
|
590
|
+
case "/":
|
|
591
|
+
h.onFocusSearch?.();
|
|
592
|
+
e.preventDefault();
|
|
593
|
+
return;
|
|
594
|
+
case "?":
|
|
595
|
+
h.onToggleHelp?.();
|
|
596
|
+
e.preventDefault();
|
|
597
|
+
return;
|
|
598
|
+
case "f":
|
|
599
|
+
h.onNextFailure?.();
|
|
600
|
+
e.preventDefault();
|
|
601
|
+
return;
|
|
602
|
+
case "F":
|
|
603
|
+
h.onPrevFailure?.();
|
|
604
|
+
e.preventDefault();
|
|
605
|
+
return;
|
|
606
|
+
default:
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
window.addEventListener("keydown", onKeyDown);
|
|
611
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
612
|
+
}, []);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// src/interactive/use-deep-link-scroll.ts
|
|
616
|
+
var import_react9 = require("react");
|
|
617
|
+
function useDeepLinkScroll() {
|
|
618
|
+
(0, import_react9.useEffect)(() => {
|
|
619
|
+
function scrollToHash() {
|
|
620
|
+
const hash = window.location.hash.replace(/^#/, "");
|
|
621
|
+
if (!hash) return;
|
|
622
|
+
const el = document.getElementById(hash);
|
|
623
|
+
if (!el) return;
|
|
624
|
+
requestAnimationFrame(() => {
|
|
625
|
+
el.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
scrollToHash();
|
|
629
|
+
window.addEventListener("hashchange", scrollToHash);
|
|
630
|
+
return () => window.removeEventListener("hashchange", scrollToHash);
|
|
631
|
+
}, []);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// src/interactive/filter.ts
|
|
635
|
+
function normalizeQuery(query) {
|
|
636
|
+
return query.trim().toLowerCase();
|
|
637
|
+
}
|
|
638
|
+
function scenarioMatches(scenario, q) {
|
|
639
|
+
if (q === "") return true;
|
|
640
|
+
if (scenario.title.toLowerCase().includes(q)) return true;
|
|
641
|
+
for (const tag of scenario.tags) {
|
|
642
|
+
if (tag.toLowerCase().includes(q)) return true;
|
|
643
|
+
}
|
|
644
|
+
for (const step of scenario.steps) {
|
|
645
|
+
if (step.text.toLowerCase().includes(q)) return true;
|
|
646
|
+
}
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
function summarizeScenarios(scenarios) {
|
|
650
|
+
let total = 0, passed = 0, failed = 0, skipped = 0, pending = 0, durationMs = 0;
|
|
651
|
+
for (const s of scenarios) {
|
|
652
|
+
total += 1;
|
|
653
|
+
durationMs += s.durationMs;
|
|
654
|
+
if (s.status === "passed") passed += 1;
|
|
655
|
+
else if (s.status === "failed") failed += 1;
|
|
656
|
+
else if (s.status === "skipped") skipped += 1;
|
|
657
|
+
else pending += 1;
|
|
658
|
+
}
|
|
659
|
+
return { total, passed, failed, skipped, pending, durationMs };
|
|
660
|
+
}
|
|
661
|
+
function filterReport(report, query) {
|
|
662
|
+
const q = normalizeQuery(query);
|
|
663
|
+
if (q === "") return report;
|
|
664
|
+
const features = [];
|
|
665
|
+
let topTotal = 0, topPassed = 0, topFailed = 0, topSkipped = 0, topPending = 0, topDuration = 0;
|
|
666
|
+
for (const feature of report.features) {
|
|
667
|
+
const matched = feature.scenarios.filter((s) => scenarioMatches(s, q));
|
|
668
|
+
if (matched.length === 0) continue;
|
|
669
|
+
const summary = summarizeScenarios(matched);
|
|
670
|
+
features.push({ ...feature, summary, scenarios: matched });
|
|
671
|
+
topTotal += summary.total;
|
|
672
|
+
topPassed += summary.passed;
|
|
673
|
+
topFailed += summary.failed;
|
|
674
|
+
topSkipped += summary.skipped;
|
|
675
|
+
topPending += summary.pending;
|
|
676
|
+
topDuration += summary.durationMs;
|
|
677
|
+
}
|
|
678
|
+
return {
|
|
679
|
+
...report,
|
|
680
|
+
summary: {
|
|
681
|
+
total: topTotal,
|
|
682
|
+
passed: topPassed,
|
|
683
|
+
failed: topFailed,
|
|
684
|
+
skipped: topSkipped,
|
|
685
|
+
pending: topPending,
|
|
686
|
+
durationMs: topDuration
|
|
687
|
+
},
|
|
688
|
+
features
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
function listFailures(report) {
|
|
692
|
+
const out = [];
|
|
693
|
+
for (const feature of report.features) {
|
|
694
|
+
for (const scenario of feature.scenarios) {
|
|
695
|
+
if (scenario.status === "failed") {
|
|
696
|
+
const ref = {
|
|
697
|
+
featureId: feature.id,
|
|
698
|
+
scenarioId: scenario.id,
|
|
699
|
+
scenarioTitle: scenario.title
|
|
700
|
+
};
|
|
701
|
+
if (scenario.errorMessage !== void 0) {
|
|
702
|
+
ref.errorMessage = scenario.errorMessage;
|
|
703
|
+
}
|
|
704
|
+
out.push(ref);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return out;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// src/interactive/ReportInteractive.tsx
|
|
712
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
713
|
+
function isResult(value) {
|
|
714
|
+
return typeof value === "object" && value !== null && "ok" in value && typeof value.ok === "boolean";
|
|
715
|
+
}
|
|
716
|
+
function ReportInteractive(props) {
|
|
717
|
+
const { report, className, title, dataTheme } = props;
|
|
718
|
+
if (isResult(report)) {
|
|
719
|
+
if (!report.ok) {
|
|
720
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
721
|
+
"main",
|
|
722
|
+
{
|
|
723
|
+
className: ["es-report", className].filter(Boolean).join(" "),
|
|
724
|
+
"aria-label": title ?? "Test report",
|
|
725
|
+
"data-theme": dataTheme,
|
|
726
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportSchemaError, { error: report.error })
|
|
727
|
+
}
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportInteractiveView, { ...props, report: report.data });
|
|
731
|
+
}
|
|
732
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportInteractiveView, { ...props, report });
|
|
733
|
+
}
|
|
734
|
+
function ReportInteractiveView({
|
|
735
|
+
report,
|
|
736
|
+
customRenderers,
|
|
737
|
+
renderers,
|
|
738
|
+
className,
|
|
739
|
+
title,
|
|
740
|
+
dataTheme
|
|
741
|
+
}) {
|
|
742
|
+
const [query, setQuery] = (0, import_react10.useState)("");
|
|
743
|
+
const [helpOpen, setHelpOpen] = (0, import_react10.useState)(false);
|
|
744
|
+
const searchRef = (0, import_react10.useRef)(null);
|
|
745
|
+
const failures = (0, import_react10.useMemo)(() => listFailures(report), [report]);
|
|
746
|
+
const filtered = (0, import_react10.useMemo)(() => filterReport(report, query), [report, query]);
|
|
747
|
+
const failureIndexRef = (0, import_react10.useRef)(0);
|
|
748
|
+
const focusSearch = (0, import_react10.useCallback)(() => {
|
|
749
|
+
searchRef.current?.focus();
|
|
750
|
+
}, []);
|
|
751
|
+
const scrollToScenario = (0, import_react10.useCallback)((scenarioId) => {
|
|
752
|
+
if (typeof document === "undefined") return;
|
|
753
|
+
const el = document.getElementById(scenarioId);
|
|
754
|
+
if (!el) return;
|
|
755
|
+
el.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
756
|
+
if (typeof history !== "undefined") {
|
|
757
|
+
history.replaceState(null, "", `#${scenarioId}`);
|
|
758
|
+
}
|
|
759
|
+
}, []);
|
|
760
|
+
const stepFailure = (0, import_react10.useCallback)(
|
|
761
|
+
(direction) => {
|
|
762
|
+
if (failures.length === 0) return;
|
|
763
|
+
failureIndexRef.current = (failureIndexRef.current + direction + failures.length) % failures.length;
|
|
764
|
+
const target = failures[failureIndexRef.current];
|
|
765
|
+
if (target) scrollToScenario(target.scenarioId);
|
|
766
|
+
},
|
|
767
|
+
[failures, scrollToScenario]
|
|
768
|
+
);
|
|
769
|
+
const toggleHelp = (0, import_react10.useCallback)(() => {
|
|
770
|
+
setHelpOpen((v) => !v);
|
|
771
|
+
}, []);
|
|
772
|
+
const escape = (0, import_react10.useCallback)(() => {
|
|
773
|
+
if (helpOpen) setHelpOpen(false);
|
|
774
|
+
else if (query !== "") setQuery("");
|
|
775
|
+
}, [helpOpen, query]);
|
|
776
|
+
useKeyboardShortcuts({
|
|
777
|
+
onFocusSearch: focusSearch,
|
|
778
|
+
onNextFailure: () => stepFailure(1),
|
|
779
|
+
onPrevFailure: () => stepFailure(-1),
|
|
780
|
+
onToggleHelp: toggleHelp,
|
|
781
|
+
onEscape: escape
|
|
782
|
+
});
|
|
783
|
+
useDeepLinkScroll();
|
|
784
|
+
const hasContent = filtered.features.length > 0;
|
|
785
|
+
const totalScenarios = report.summary.total;
|
|
786
|
+
const matchedScenarios = filtered.summary.total;
|
|
787
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
788
|
+
ReportRoot,
|
|
789
|
+
{
|
|
790
|
+
report: filtered,
|
|
791
|
+
customRenderers,
|
|
792
|
+
renderers,
|
|
793
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
794
|
+
"main",
|
|
795
|
+
{
|
|
796
|
+
className: ["es-report", "es-report-interactive", className].filter(Boolean).join(" "),
|
|
797
|
+
"aria-label": title ?? "Test report",
|
|
798
|
+
"data-theme": dataTheme,
|
|
799
|
+
children: [
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("header", { className: "es-report-header", children: [
|
|
801
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h1", { children: title ?? "Story Report" }),
|
|
802
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportSummary, {}),
|
|
803
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
804
|
+
ReportSearch,
|
|
805
|
+
{
|
|
806
|
+
ref: searchRef,
|
|
807
|
+
value: query,
|
|
808
|
+
onChange: setQuery,
|
|
809
|
+
matchedCount: matchedScenarios,
|
|
810
|
+
totalCount: totalScenarios
|
|
811
|
+
}
|
|
812
|
+
)
|
|
813
|
+
] }),
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportFailureBanner, { failures }),
|
|
815
|
+
hasContent ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportEmpty, { message: query ? "No scenarios match the search." : void 0 }),
|
|
816
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
817
|
+
"button",
|
|
818
|
+
{
|
|
819
|
+
type: "button",
|
|
820
|
+
className: "es-shortcuts-trigger",
|
|
821
|
+
"aria-label": "Keyboard shortcuts",
|
|
822
|
+
"aria-keyshortcuts": "Shift+?",
|
|
823
|
+
onClick: toggleHelp,
|
|
824
|
+
children: "?"
|
|
825
|
+
}
|
|
826
|
+
),
|
|
827
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) })
|
|
828
|
+
]
|
|
829
|
+
}
|
|
830
|
+
)
|
|
831
|
+
}
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
835
|
+
0 && (module.exports = {
|
|
836
|
+
ReportFailureBanner,
|
|
837
|
+
ReportInteractive,
|
|
838
|
+
ReportSearch,
|
|
839
|
+
ReportShortcutsHelp,
|
|
840
|
+
filterReport,
|
|
841
|
+
listFailures,
|
|
842
|
+
normalizeQuery,
|
|
843
|
+
useDeepLinkScroll,
|
|
844
|
+
useKeyboardShortcuts
|
|
845
|
+
});
|
|
846
|
+
//# sourceMappingURL=interactive.cjs.map
|