executable-stories-react 0.2.0 → 0.3.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 +369 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +307 -9
- package/dist/index.d.ts +307 -9
- package/dist/index.js +353 -145
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +557 -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 +518 -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 +299 -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 +296 -115
- package/dist/ssr.js.map +1 -1
- package/dist/styles.css +26 -0
- package/dist/tailwind.css +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -50,11 +50,23 @@ function useReport() {
|
|
|
50
50
|
return ctx.report;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
// ../executable-stories-core/dist/utils/duration.js
|
|
54
|
+
function formatDuration(ms) {
|
|
55
|
+
if (ms < 1e3) {
|
|
56
|
+
return `${Math.round(ms)} ms`;
|
|
57
|
+
}
|
|
58
|
+
if (ms < 6e4) {
|
|
59
|
+
return `${(ms / 1e3).toFixed(2)} s`;
|
|
60
|
+
}
|
|
61
|
+
const minutes = Math.floor(ms / 6e4);
|
|
62
|
+
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
63
|
+
if (minutes < 60) {
|
|
64
|
+
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
65
|
+
}
|
|
66
|
+
const hours = Math.floor(minutes / 60);
|
|
67
|
+
const remainingMinutes = minutes % 60;
|
|
68
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
69
|
+
}
|
|
58
70
|
|
|
59
71
|
// src/components/doc/DocNote.tsx
|
|
60
72
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
@@ -208,6 +220,15 @@ function safeUrl(value) {
|
|
|
208
220
|
if (scheme && !/^https?$/i.test(scheme[1] ?? "")) return void 0;
|
|
209
221
|
return trimmed;
|
|
210
222
|
}
|
|
223
|
+
function safeImageUrl(value) {
|
|
224
|
+
if (!value) return void 0;
|
|
225
|
+
const trimmed = value.trim();
|
|
226
|
+
if (/^data:image\//i.test(trimmed)) return trimmed;
|
|
227
|
+
return safeUrl(trimmed);
|
|
228
|
+
}
|
|
229
|
+
function isLocalFsPath(value) {
|
|
230
|
+
return /^(?:[/\\]|[A-Za-z]:[/\\])/.test(value);
|
|
231
|
+
}
|
|
211
232
|
|
|
212
233
|
// src/components/doc/DocSection.tsx
|
|
213
234
|
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -263,11 +284,19 @@ function DocMermaid({ entry }) {
|
|
|
263
284
|
// src/components/doc/DocScreenshot.tsx
|
|
264
285
|
import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
265
286
|
function DocScreenshot({ entry }) {
|
|
287
|
+
const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
|
|
288
|
+
if (!src) {
|
|
289
|
+
return /* @__PURE__ */ jsxs6("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
290
|
+
/* @__PURE__ */ jsx10("div", { className: "font-medium", children: "Screenshot unavailable" }),
|
|
291
|
+
/* @__PURE__ */ jsx10("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
292
|
+
entry.alt ? /* @__PURE__ */ jsx10("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
|
|
293
|
+
] });
|
|
294
|
+
}
|
|
266
295
|
return /* @__PURE__ */ jsxs6("figure", { className: "my-3", children: [
|
|
267
296
|
/* @__PURE__ */ jsx10(
|
|
268
297
|
"img",
|
|
269
298
|
{
|
|
270
|
-
src
|
|
299
|
+
src,
|
|
271
300
|
alt: entry.alt ?? "",
|
|
272
301
|
loading: "lazy",
|
|
273
302
|
className: "max-w-full rounded-md border border-border"
|
|
@@ -280,6 +309,13 @@ function DocScreenshot({ entry }) {
|
|
|
280
309
|
// src/components/doc/DocVideo.tsx
|
|
281
310
|
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
282
311
|
function DocVideo({ entry }) {
|
|
312
|
+
if (isLocalFsPath(entry.path)) {
|
|
313
|
+
return /* @__PURE__ */ jsxs7("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
314
|
+
/* @__PURE__ */ jsx11("div", { className: "font-medium", children: "Video unavailable" }),
|
|
315
|
+
/* @__PURE__ */ jsx11("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
316
|
+
entry.caption ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
|
|
317
|
+
] });
|
|
318
|
+
}
|
|
283
319
|
const src = safeUrl(entry.path);
|
|
284
320
|
const poster = safeUrl(entry.poster);
|
|
285
321
|
return /* @__PURE__ */ jsxs7("figure", { className: "my-3", children: [
|
|
@@ -513,9 +549,6 @@ function ReportAttachments({ attachments }) {
|
|
|
513
549
|
);
|
|
514
550
|
}
|
|
515
551
|
|
|
516
|
-
// src/components/ReportTrace.tsx
|
|
517
|
-
import { formatDuration as formatDuration2 } from "executable-stories-core/utils/duration";
|
|
518
|
-
|
|
519
552
|
// src/lib/trace.ts
|
|
520
553
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
521
554
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -610,7 +643,7 @@ function ReportTrace({ spans }) {
|
|
|
610
643
|
" span",
|
|
611
644
|
rows.length === 1 ? "" : "s",
|
|
612
645
|
", ",
|
|
613
|
-
|
|
646
|
+
formatDuration(totalMs),
|
|
614
647
|
")"
|
|
615
648
|
] }),
|
|
616
649
|
/* @__PURE__ */ jsx19("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
@@ -633,33 +666,128 @@ function ReportTrace({ spans }) {
|
|
|
633
666
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
634
667
|
}
|
|
635
668
|
) }),
|
|
636
|
-
/* @__PURE__ */ jsx19("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children:
|
|
669
|
+
/* @__PURE__ */ jsx19("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
637
670
|
] }, `${row.spanId}-${i}`);
|
|
638
671
|
}) })
|
|
639
672
|
] });
|
|
640
673
|
}
|
|
641
674
|
|
|
675
|
+
// src/interactive/scenario-history-context.ts
|
|
676
|
+
import { createContext as createContext2, useContext as useContext3 } from "react";
|
|
677
|
+
var ScenarioHistoryContext = createContext2(null);
|
|
678
|
+
var ScenarioHistoryProvider = ScenarioHistoryContext.Provider;
|
|
679
|
+
function useScenarioHistory() {
|
|
680
|
+
return useContext3(ScenarioHistoryContext);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// src/lib/run-history.ts
|
|
684
|
+
function currentStreak(entries) {
|
|
685
|
+
const last = entries[entries.length - 1];
|
|
686
|
+
if (!last) return void 0;
|
|
687
|
+
let count = 0;
|
|
688
|
+
for (let i = entries.length - 1; i >= 0 && entries[i].status === last.status; i--) count++;
|
|
689
|
+
return { status: last.status, count };
|
|
690
|
+
}
|
|
691
|
+
var STREAK_VERB = {
|
|
692
|
+
passed: "Passing",
|
|
693
|
+
failed: "Failing",
|
|
694
|
+
skipped: "Skipped",
|
|
695
|
+
pending: "Pending"
|
|
696
|
+
};
|
|
697
|
+
function describeRunHistory(entries) {
|
|
698
|
+
const passed = entries.filter((e) => e.status === "passed").length;
|
|
699
|
+
const base = `${passed}/${entries.length} runs passed`;
|
|
700
|
+
const streak = currentStreak(entries);
|
|
701
|
+
if (!streak || entries.length < 2) return base;
|
|
702
|
+
return `${base} \xB7 ${STREAK_VERB[streak.status]} for the last ${streak.count === 1 ? "run" : `${streak.count} runs`}`;
|
|
703
|
+
}
|
|
704
|
+
var MIN_FLAKINESS_SAMPLES = 3;
|
|
705
|
+
function flakinessOf(entries) {
|
|
706
|
+
const countable = entries.filter((e) => e.status === "passed" || e.status === "failed");
|
|
707
|
+
if (countable.length < MIN_FLAKINESS_SAMPLES) return "stable";
|
|
708
|
+
let transitions = 0;
|
|
709
|
+
for (let i = 1; i < countable.length; i++) {
|
|
710
|
+
if (countable[i].status !== countable[i - 1].status) transitions++;
|
|
711
|
+
}
|
|
712
|
+
const transitionScore = transitions / (countable.length - 1);
|
|
713
|
+
const failureRate = countable.filter((e) => e.status === "failed").length / countable.length;
|
|
714
|
+
if (transitionScore > 0.5 || transitionScore > 0.3 && failureRate > 0.2) return "flaky";
|
|
715
|
+
if (transitionScore > 0.2 || failureRate > 0.3) return "unstable";
|
|
716
|
+
return "stable";
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// src/components/ScenarioRunHistory.tsx
|
|
720
|
+
import { Fragment as Fragment7, jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
721
|
+
var MAX_DOTS = 10;
|
|
722
|
+
var DOT_COLOR = {
|
|
723
|
+
passed: "bg-pass",
|
|
724
|
+
failed: "bg-fail",
|
|
725
|
+
skipped: "bg-skip",
|
|
726
|
+
pending: "bg-pend"
|
|
727
|
+
};
|
|
728
|
+
function dotTitle(e) {
|
|
729
|
+
const parts = [new Date(e.timestamp).toLocaleString(), e.status];
|
|
730
|
+
if (e.commitSha) parts.push(e.commitSha.slice(0, 8));
|
|
731
|
+
return parts.join(" \xB7 ");
|
|
732
|
+
}
|
|
733
|
+
function ScenarioRunHistory({ scenarioId }) {
|
|
734
|
+
const history = useScenarioHistory();
|
|
735
|
+
const entries = history?.[scenarioId];
|
|
736
|
+
if (!entries || entries.length < 2) return null;
|
|
737
|
+
const recent = entries.slice(-MAX_DOTS);
|
|
738
|
+
const flaky = flakinessOf(recent) === "flaky";
|
|
739
|
+
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
740
|
+
return /* @__PURE__ */ jsxs13(Fragment7, { children: [
|
|
741
|
+
flaky ? /* @__PURE__ */ jsx20(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
742
|
+
/* @__PURE__ */ jsx20(
|
|
743
|
+
"span",
|
|
744
|
+
{
|
|
745
|
+
role: "img",
|
|
746
|
+
"aria-label": `Run history: ${summary}`,
|
|
747
|
+
title: summary,
|
|
748
|
+
className: "flex shrink-0 items-center gap-[3px]",
|
|
749
|
+
children: recent.map((e, i) => /* @__PURE__ */ jsx20(
|
|
750
|
+
"span",
|
|
751
|
+
{
|
|
752
|
+
"aria-hidden": true,
|
|
753
|
+
title: dotTitle(e),
|
|
754
|
+
className: cn(
|
|
755
|
+
"inline-block size-1.5 rounded-full",
|
|
756
|
+
DOT_COLOR[e.status],
|
|
757
|
+
// The newest run (rightmost dot) is the one the card's status
|
|
758
|
+
// badge already describes; ring it so the timeline reads as
|
|
759
|
+
// "…leading up to now".
|
|
760
|
+
i === recent.length - 1 && "ring-1 ring-border ring-offset-1 ring-offset-card"
|
|
761
|
+
)
|
|
762
|
+
},
|
|
763
|
+
`${e.timestamp}-${i}`
|
|
764
|
+
))
|
|
765
|
+
}
|
|
766
|
+
)
|
|
767
|
+
] });
|
|
768
|
+
}
|
|
769
|
+
|
|
642
770
|
// src/interactive/collapse-context.ts
|
|
643
|
-
import { createContext as
|
|
644
|
-
var CollapseContext =
|
|
771
|
+
import { createContext as createContext3, useCallback, useContext as useContext4, useState } from "react";
|
|
772
|
+
var CollapseContext = createContext3(null);
|
|
645
773
|
var CollapseProvider = CollapseContext.Provider;
|
|
646
774
|
function useCollapse() {
|
|
647
|
-
return
|
|
775
|
+
return useContext4(CollapseContext);
|
|
648
776
|
}
|
|
649
777
|
|
|
650
778
|
// src/interactive/scenario-actions.tsx
|
|
651
|
-
import { createContext as
|
|
652
|
-
var ScenarioActionsContext =
|
|
779
|
+
import { createContext as createContext4, useContext as useContext5 } from "react";
|
|
780
|
+
var ScenarioActionsContext = createContext4(null);
|
|
653
781
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
654
782
|
function useScenarioActions() {
|
|
655
|
-
return
|
|
783
|
+
return useContext5(ScenarioActionsContext);
|
|
656
784
|
}
|
|
657
785
|
|
|
658
786
|
// src/components/ui/card.tsx
|
|
659
787
|
import "react";
|
|
660
|
-
import { jsx as
|
|
788
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
661
789
|
function Card({ className, ...props }) {
|
|
662
|
-
return /* @__PURE__ */
|
|
790
|
+
return /* @__PURE__ */ jsx21(
|
|
663
791
|
"div",
|
|
664
792
|
{
|
|
665
793
|
"data-slot": "card",
|
|
@@ -672,7 +800,7 @@ function Card({ className, ...props }) {
|
|
|
672
800
|
);
|
|
673
801
|
}
|
|
674
802
|
function CardHeader({ className, ...props }) {
|
|
675
|
-
return /* @__PURE__ */
|
|
803
|
+
return /* @__PURE__ */ jsx21(
|
|
676
804
|
"div",
|
|
677
805
|
{
|
|
678
806
|
"data-slot": "card-header",
|
|
@@ -685,7 +813,7 @@ function CardHeader({ className, ...props }) {
|
|
|
685
813
|
);
|
|
686
814
|
}
|
|
687
815
|
function CardContent({ className, ...props }) {
|
|
688
|
-
return /* @__PURE__ */
|
|
816
|
+
return /* @__PURE__ */ jsx21(
|
|
689
817
|
"div",
|
|
690
818
|
{
|
|
691
819
|
"data-slot": "card-content",
|
|
@@ -696,7 +824,7 @@ function CardContent({ className, ...props }) {
|
|
|
696
824
|
}
|
|
697
825
|
|
|
698
826
|
// src/components/ReportScenario.tsx
|
|
699
|
-
import { jsx as
|
|
827
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
700
828
|
var STATUS_LABEL = {
|
|
701
829
|
passed: "Passed",
|
|
702
830
|
failed: "Failed",
|
|
@@ -724,12 +852,12 @@ var STATUS_BADGE = {
|
|
|
724
852
|
function ReportScenario({ scenario, hideTitle = false }) {
|
|
725
853
|
const titleId = `${scenario.id}-title`;
|
|
726
854
|
const bodyId = `${scenario.id}-body`;
|
|
727
|
-
const label = STATUS_LABEL[scenario.status];
|
|
855
|
+
const label = scenario.planned ? "Planned" : STATUS_LABEL[scenario.status];
|
|
728
856
|
const collapse = useCollapse();
|
|
729
857
|
const collapsible = collapse !== null && !hideTitle;
|
|
730
858
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
731
859
|
const actions = useScenarioActions();
|
|
732
|
-
return /* @__PURE__ */
|
|
860
|
+
return /* @__PURE__ */ jsxs14(
|
|
733
861
|
Card,
|
|
734
862
|
{
|
|
735
863
|
id: scenario.id,
|
|
@@ -737,10 +865,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
737
865
|
...hideTitle ? { "aria-label": `${scenario.title} \u2014 ${label}` } : { "aria-labelledby": titleId },
|
|
738
866
|
className: "gap-0 py-0",
|
|
739
867
|
children: [
|
|
740
|
-
/* @__PURE__ */
|
|
741
|
-
/* @__PURE__ */
|
|
742
|
-
hideTitle ? null : /* @__PURE__ */
|
|
743
|
-
collapsible ? /* @__PURE__ */
|
|
868
|
+
/* @__PURE__ */ jsxs14(CardHeader, { className: "px-4 py-3", children: [
|
|
869
|
+
/* @__PURE__ */ jsxs14("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
870
|
+
hideTitle ? null : /* @__PURE__ */ jsxs14("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
871
|
+
collapsible ? /* @__PURE__ */ jsx22(
|
|
744
872
|
"button",
|
|
745
873
|
{
|
|
746
874
|
type: "button",
|
|
@@ -749,17 +877,18 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
749
877
|
"aria-controls": bodyId,
|
|
750
878
|
"aria-label": `Toggle ${scenario.title}`,
|
|
751
879
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
752
|
-
children: /* @__PURE__ */
|
|
880
|
+
children: /* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
753
881
|
}
|
|
754
882
|
) : null,
|
|
755
|
-
/* @__PURE__ */
|
|
756
|
-
/* @__PURE__ */
|
|
883
|
+
/* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: cn("text-sm leading-none", STATUS_GLYPH_COLOR[scenario.status]), children: STATUS_GLYPH[scenario.status] }),
|
|
884
|
+
/* @__PURE__ */ jsx22("span", { children: scenario.title })
|
|
757
885
|
] }),
|
|
758
|
-
/* @__PURE__ */
|
|
759
|
-
|
|
760
|
-
/* @__PURE__ */
|
|
761
|
-
|
|
762
|
-
|
|
886
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
887
|
+
/* @__PURE__ */ jsx22(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
888
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ jsx22("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
889
|
+
/* @__PURE__ */ jsx22(Badge, { variant: STATUS_BADGE[scenario.status], "aria-label": `Status: ${label}`, children: label }),
|
|
890
|
+
actions ? /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-0.5", children: [
|
|
891
|
+
/* @__PURE__ */ jsx22(
|
|
763
892
|
"button",
|
|
764
893
|
{
|
|
765
894
|
type: "button",
|
|
@@ -770,7 +899,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
770
899
|
children: "link"
|
|
771
900
|
}
|
|
772
901
|
),
|
|
773
|
-
/* @__PURE__ */
|
|
902
|
+
/* @__PURE__ */ jsx22(
|
|
774
903
|
"button",
|
|
775
904
|
{
|
|
776
905
|
type: "button",
|
|
@@ -781,7 +910,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
781
910
|
children: "md"
|
|
782
911
|
}
|
|
783
912
|
),
|
|
784
|
-
/* @__PURE__ */
|
|
913
|
+
/* @__PURE__ */ jsx22(
|
|
785
914
|
"button",
|
|
786
915
|
{
|
|
787
916
|
type: "button",
|
|
@@ -795,13 +924,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
795
924
|
] }) : null
|
|
796
925
|
] })
|
|
797
926
|
] }),
|
|
798
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */
|
|
799
|
-
scenario.tags.map((t) => /* @__PURE__ */
|
|
800
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */
|
|
927
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs14("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
928
|
+
scenario.tags.map((t) => /* @__PURE__ */ jsx22("li", { children: /* @__PURE__ */ jsx22(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
929
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx22("li", { children: ticket.url ? /* @__PURE__ */ jsx22("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx22(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx22(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
801
930
|
] }) : null
|
|
802
931
|
] }),
|
|
803
|
-
/* @__PURE__ */
|
|
804
|
-
scenario.errorMessage ? /* @__PURE__ */
|
|
932
|
+
/* @__PURE__ */ jsxs14(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
933
|
+
scenario.errorMessage ? /* @__PURE__ */ jsx22(
|
|
805
934
|
"pre",
|
|
806
935
|
{
|
|
807
936
|
role: "alert",
|
|
@@ -809,10 +938,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
809
938
|
children: scenario.errorMessage
|
|
810
939
|
}
|
|
811
940
|
) : null,
|
|
812
|
-
/* @__PURE__ */
|
|
813
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */
|
|
814
|
-
/* @__PURE__ */
|
|
815
|
-
/* @__PURE__ */
|
|
941
|
+
/* @__PURE__ */ jsx22(ReportSteps, { scenario }),
|
|
942
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx22("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx22(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
943
|
+
/* @__PURE__ */ jsx22(ReportAttachments, { attachments: scenario.attachments }),
|
|
944
|
+
/* @__PURE__ */ jsx22(ReportTrace, { spans: scenario.otelSpans })
|
|
816
945
|
] })
|
|
817
946
|
]
|
|
818
947
|
}
|
|
@@ -820,13 +949,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
820
949
|
}
|
|
821
950
|
|
|
822
951
|
// src/components/ReportScenarioList.tsx
|
|
823
|
-
import { Fragment as
|
|
952
|
+
import { Fragment as Fragment8, jsx as jsx23 } from "react/jsx-runtime";
|
|
824
953
|
function ReportScenarioList({ feature }) {
|
|
825
|
-
return /* @__PURE__ */
|
|
954
|
+
return /* @__PURE__ */ jsx23(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx23(ReportScenario, { scenario }, scenario.id)) });
|
|
826
955
|
}
|
|
827
956
|
|
|
828
957
|
// src/components/ReportFeature.tsx
|
|
829
|
-
import { jsx as
|
|
958
|
+
import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
830
959
|
function ReportFeature({ feature }) {
|
|
831
960
|
const titleId = `${feature.id}-title`;
|
|
832
961
|
const bodyId = `${feature.id}-body`;
|
|
@@ -834,7 +963,7 @@ function ReportFeature({ feature }) {
|
|
|
834
963
|
const skipped = s.skipped + s.pending;
|
|
835
964
|
const collapse = useCollapse();
|
|
836
965
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
837
|
-
return /* @__PURE__ */
|
|
966
|
+
return /* @__PURE__ */ jsxs15(
|
|
838
967
|
"section",
|
|
839
968
|
{
|
|
840
969
|
id: feature.id,
|
|
@@ -842,9 +971,9 @@ function ReportFeature({ feature }) {
|
|
|
842
971
|
"aria-labelledby": titleId,
|
|
843
972
|
className: "overflow-hidden rounded-xl border border-border bg-card shadow-sm",
|
|
844
973
|
children: [
|
|
845
|
-
/* @__PURE__ */
|
|
846
|
-
/* @__PURE__ */
|
|
847
|
-
collapse ? /* @__PURE__ */
|
|
974
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between gap-4 border-b border-border bg-muted/40 px-4 py-3", children: [
|
|
975
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
976
|
+
collapse ? /* @__PURE__ */ jsx24(
|
|
848
977
|
"button",
|
|
849
978
|
{
|
|
850
979
|
type: "button",
|
|
@@ -853,30 +982,30 @@ function ReportFeature({ feature }) {
|
|
|
853
982
|
"aria-controls": bodyId,
|
|
854
983
|
"aria-label": `Toggle ${feature.title}`,
|
|
855
984
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
856
|
-
children: /* @__PURE__ */
|
|
985
|
+
children: /* @__PURE__ */ jsx24("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
857
986
|
}
|
|
858
987
|
) : null,
|
|
859
|
-
/* @__PURE__ */
|
|
860
|
-
/* @__PURE__ */
|
|
861
|
-
/* @__PURE__ */
|
|
988
|
+
/* @__PURE__ */ jsxs15("div", { className: "min-w-0", children: [
|
|
989
|
+
/* @__PURE__ */ jsx24("h2", { id: titleId, className: "text-sm font-semibold tracking-tight text-foreground", children: feature.title }),
|
|
990
|
+
/* @__PURE__ */ jsx24("p", { className: "mt-0.5 truncate font-mono text-xs text-muted-foreground", children: feature.sourceFile })
|
|
862
991
|
] })
|
|
863
992
|
] }),
|
|
864
|
-
/* @__PURE__ */
|
|
993
|
+
/* @__PURE__ */ jsxs15(
|
|
865
994
|
"div",
|
|
866
995
|
{
|
|
867
996
|
role: "img",
|
|
868
997
|
className: "flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium",
|
|
869
998
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
870
999
|
children: [
|
|
871
|
-
/* @__PURE__ */
|
|
1000
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-pass", children: [
|
|
872
1001
|
"\u2713",
|
|
873
1002
|
s.passed
|
|
874
1003
|
] }),
|
|
875
|
-
/* @__PURE__ */
|
|
1004
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-fail", children: [
|
|
876
1005
|
"\u2717",
|
|
877
1006
|
s.failed
|
|
878
1007
|
] }),
|
|
879
|
-
/* @__PURE__ */
|
|
1008
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-skip", children: [
|
|
880
1009
|
"\u25CB",
|
|
881
1010
|
skipped
|
|
882
1011
|
] })
|
|
@@ -884,24 +1013,24 @@ function ReportFeature({ feature }) {
|
|
|
884
1013
|
}
|
|
885
1014
|
)
|
|
886
1015
|
] }),
|
|
887
|
-
/* @__PURE__ */
|
|
1016
|
+
/* @__PURE__ */ jsx24("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-2 p-3", children: /* @__PURE__ */ jsx24(ReportScenarioList, { feature }) })
|
|
888
1017
|
]
|
|
889
1018
|
}
|
|
890
1019
|
);
|
|
891
1020
|
}
|
|
892
1021
|
|
|
893
1022
|
// src/components/ReportFeatureList.tsx
|
|
894
|
-
import { Fragment as
|
|
1023
|
+
import { Fragment as Fragment9, jsx as jsx25 } from "react/jsx-runtime";
|
|
895
1024
|
function ReportFeatureList() {
|
|
896
1025
|
const report = useReport();
|
|
897
|
-
return /* @__PURE__ */
|
|
1026
|
+
return /* @__PURE__ */ jsx25(Fragment9, { children: report.features.map((feature) => /* @__PURE__ */ jsx25(ReportFeature, { feature }, feature.id)) });
|
|
898
1027
|
}
|
|
899
1028
|
|
|
900
1029
|
// src/components/ui/empty.tsx
|
|
901
1030
|
import { cva as cva2 } from "class-variance-authority";
|
|
902
|
-
import { jsx as
|
|
1031
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
903
1032
|
function Empty({ className, ...props }) {
|
|
904
|
-
return /* @__PURE__ */
|
|
1033
|
+
return /* @__PURE__ */ jsx26(
|
|
905
1034
|
"div",
|
|
906
1035
|
{
|
|
907
1036
|
"data-slot": "empty",
|
|
@@ -914,7 +1043,7 @@ function Empty({ className, ...props }) {
|
|
|
914
1043
|
);
|
|
915
1044
|
}
|
|
916
1045
|
function EmptyHeader({ className, ...props }) {
|
|
917
|
-
return /* @__PURE__ */
|
|
1046
|
+
return /* @__PURE__ */ jsx26(
|
|
918
1047
|
"div",
|
|
919
1048
|
{
|
|
920
1049
|
"data-slot": "empty-header",
|
|
@@ -941,7 +1070,7 @@ var emptyMediaVariants = cva2(
|
|
|
941
1070
|
}
|
|
942
1071
|
);
|
|
943
1072
|
function EmptyTitle({ className, ...props }) {
|
|
944
|
-
return /* @__PURE__ */
|
|
1073
|
+
return /* @__PURE__ */ jsx26(
|
|
945
1074
|
"div",
|
|
946
1075
|
{
|
|
947
1076
|
"data-slot": "empty-title",
|
|
@@ -952,16 +1081,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
952
1081
|
}
|
|
953
1082
|
|
|
954
1083
|
// src/components/ReportEmpty.tsx
|
|
955
|
-
import { jsx as
|
|
1084
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
956
1085
|
function ReportEmpty({ message }) {
|
|
957
|
-
return /* @__PURE__ */
|
|
1086
|
+
return /* @__PURE__ */ jsx27(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx27(EmptyHeader, { children: /* @__PURE__ */ jsx27(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
958
1087
|
}
|
|
959
1088
|
|
|
960
1089
|
// src/components/ReportSummary.tsx
|
|
961
|
-
import { Fragment as
|
|
1090
|
+
import { Fragment as Fragment10, jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
962
1091
|
function ReportSummary({ className }) {
|
|
963
1092
|
const report = useReport();
|
|
964
|
-
return /* @__PURE__ */
|
|
1093
|
+
return /* @__PURE__ */ jsx28(
|
|
965
1094
|
ReportSummaryView,
|
|
966
1095
|
{
|
|
967
1096
|
summary: report.summary,
|
|
@@ -971,32 +1100,32 @@ function ReportSummary({ className }) {
|
|
|
971
1100
|
);
|
|
972
1101
|
}
|
|
973
1102
|
function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
974
|
-
return /* @__PURE__ */
|
|
975
|
-
/* @__PURE__ */
|
|
976
|
-
/* @__PURE__ */
|
|
1103
|
+
return /* @__PURE__ */ jsxs16("p", { className: cn("text-sm text-muted-foreground", className), "aria-label": ariaLabel, children: [
|
|
1104
|
+
/* @__PURE__ */ jsxs16("span", { children: [
|
|
1105
|
+
/* @__PURE__ */ jsx28("strong", { className: "font-semibold text-foreground", children: summary.total }),
|
|
977
1106
|
" scenario",
|
|
978
1107
|
summary.total === 1 ? "" : "s"
|
|
979
1108
|
] }),
|
|
980
1109
|
" \xB7 ",
|
|
981
|
-
/* @__PURE__ */
|
|
1110
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "passed", className: "text-pass", children: [
|
|
982
1111
|
summary.passed,
|
|
983
1112
|
" passed"
|
|
984
1113
|
] }),
|
|
985
1114
|
" \xB7 ",
|
|
986
|
-
/* @__PURE__ */
|
|
1115
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "failed", className: "text-fail", children: [
|
|
987
1116
|
summary.failed,
|
|
988
1117
|
" failed"
|
|
989
1118
|
] }),
|
|
990
|
-
summary.skipped > 0 ? /* @__PURE__ */
|
|
1119
|
+
summary.skipped > 0 ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
991
1120
|
" \xB7 ",
|
|
992
|
-
/* @__PURE__ */
|
|
1121
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "skipped", className: "text-skip", children: [
|
|
993
1122
|
summary.skipped,
|
|
994
1123
|
" skipped"
|
|
995
1124
|
] })
|
|
996
1125
|
] }) : null,
|
|
997
|
-
summary.pending > 0 ? /* @__PURE__ */
|
|
1126
|
+
summary.pending > 0 ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
998
1127
|
" \xB7 ",
|
|
999
|
-
/* @__PURE__ */
|
|
1128
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "pending", className: "text-pend", children: [
|
|
1000
1129
|
summary.pending,
|
|
1001
1130
|
" pending"
|
|
1002
1131
|
] })
|
|
@@ -1004,69 +1133,135 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1004
1133
|
] });
|
|
1005
1134
|
}
|
|
1006
1135
|
|
|
1136
|
+
// src/lib/provenance.ts
|
|
1137
|
+
function reportLastRunMs(report) {
|
|
1138
|
+
if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;
|
|
1139
|
+
if (report.startedAtMs && report.startedAtMs > 0) return report.startedAtMs;
|
|
1140
|
+
return void 0;
|
|
1141
|
+
}
|
|
1142
|
+
function formatRelativeAge(thenMs, nowMs) {
|
|
1143
|
+
const deltaMs = Math.max(0, nowMs - thenMs);
|
|
1144
|
+
const minutes = Math.floor(deltaMs / 6e4);
|
|
1145
|
+
if (minutes < 1) return "just now";
|
|
1146
|
+
if (minutes < 60) return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
|
|
1147
|
+
const hours = Math.floor(minutes / 60);
|
|
1148
|
+
if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`;
|
|
1149
|
+
const days = Math.floor(hours / 24);
|
|
1150
|
+
return `${days} day${days === 1 ? "" : "s"} ago`;
|
|
1151
|
+
}
|
|
1152
|
+
function isReportStale(lastRunMs, staleAfterDays, nowMs) {
|
|
1153
|
+
if (lastRunMs === void 0 || staleAfterDays <= 0) return false;
|
|
1154
|
+
return nowMs - lastRunMs >= staleAfterDays * 864e5;
|
|
1155
|
+
}
|
|
1156
|
+
var CI_DISPLAY_NAMES = {
|
|
1157
|
+
github: "GitHub Actions",
|
|
1158
|
+
gitlab: "GitLab CI",
|
|
1159
|
+
circleci: "CircleCI",
|
|
1160
|
+
jenkins: "Jenkins",
|
|
1161
|
+
azure: "Azure DevOps",
|
|
1162
|
+
buildkite: "Buildkite",
|
|
1163
|
+
travis: "Travis CI",
|
|
1164
|
+
ci: "CI"
|
|
1165
|
+
};
|
|
1166
|
+
function ciDisplayName(name) {
|
|
1167
|
+
return CI_DISPLAY_NAMES[name] ?? name;
|
|
1168
|
+
}
|
|
1169
|
+
function commitUrl(ci, sha) {
|
|
1170
|
+
const commitSha = ci?.commitSha ?? sha;
|
|
1171
|
+
if (!ci?.url || !commitSha) return void 0;
|
|
1172
|
+
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1173
|
+
if (github) return `${github[1]}/commit/${commitSha}`;
|
|
1174
|
+
const gitlab = ci.url.match(/^(https?:\/\/.+)\/-\/pipelines\//);
|
|
1175
|
+
if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;
|
|
1176
|
+
return void 0;
|
|
1177
|
+
}
|
|
1178
|
+
function prUrl(ci) {
|
|
1179
|
+
if (!ci?.url || !ci.prNumber) return void 0;
|
|
1180
|
+
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1181
|
+
if (github) return `${github[1]}/pull/${ci.prNumber}`;
|
|
1182
|
+
return void 0;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1007
1185
|
// src/components/ReportMeta.tsx
|
|
1008
|
-
import {
|
|
1009
|
-
import { jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1186
|
+
import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1010
1187
|
function ReportMeta() {
|
|
1011
1188
|
const report = useReport();
|
|
1012
1189
|
const items = [];
|
|
1190
|
+
const linkClass = "text-primary underline underline-offset-2";
|
|
1013
1191
|
if (report.startedAtMs) {
|
|
1014
1192
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1015
1193
|
}
|
|
1016
1194
|
if (report.durationMs) {
|
|
1017
|
-
items.push({ label: "Duration", value:
|
|
1195
|
+
items.push({ label: "Duration", value: formatDuration(report.durationMs) });
|
|
1018
1196
|
}
|
|
1019
1197
|
if (report.packageVersion) {
|
|
1020
1198
|
items.push({ label: "Version", value: report.packageVersion });
|
|
1021
1199
|
}
|
|
1022
|
-
if (report.
|
|
1023
|
-
items.push({ label: "
|
|
1200
|
+
if (report.ci?.branch) {
|
|
1201
|
+
items.push({ label: "Branch", value: report.ci.branch });
|
|
1202
|
+
}
|
|
1203
|
+
const sha = report.ci?.commitSha ?? report.gitSha;
|
|
1204
|
+
if (sha) {
|
|
1205
|
+
const url = commitUrl(report.ci, report.gitSha);
|
|
1206
|
+
const short = sha.slice(0, 8);
|
|
1207
|
+
items.push({
|
|
1208
|
+
label: "Commit",
|
|
1209
|
+
value: url ? /* @__PURE__ */ jsx29("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1210
|
+
});
|
|
1024
1211
|
}
|
|
1025
1212
|
if (report.ci) {
|
|
1026
1213
|
items.push({
|
|
1027
1214
|
label: "CI",
|
|
1028
|
-
value: report.ci.url ? /* @__PURE__ */
|
|
1029
|
-
report.ci.name,
|
|
1215
|
+
value: report.ci.url ? /* @__PURE__ */ jsxs17("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1216
|
+
ciDisplayName(report.ci.name),
|
|
1030
1217
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1031
|
-
] }) : `${report.ci.name}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
1218
|
+
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
if (report.ci?.prNumber) {
|
|
1222
|
+
const url = prUrl(report.ci);
|
|
1223
|
+
const label = `#${report.ci.prNumber}`;
|
|
1224
|
+
items.push({
|
|
1225
|
+
label: "PR",
|
|
1226
|
+
value: url ? /* @__PURE__ */ jsx29("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1032
1227
|
});
|
|
1033
1228
|
}
|
|
1034
1229
|
if (items.length === 0) return null;
|
|
1035
|
-
return /* @__PURE__ */
|
|
1036
|
-
/* @__PURE__ */
|
|
1037
|
-
/* @__PURE__ */
|
|
1230
|
+
return /* @__PURE__ */ jsx29("dl", { "aria-label": "Run metadata", className: "flex flex-wrap gap-x-6 gap-y-1 text-xs text-muted-foreground", children: items.map((item) => /* @__PURE__ */ jsxs17("div", { className: "flex gap-1.5", children: [
|
|
1231
|
+
/* @__PURE__ */ jsx29("dt", { className: "font-medium", children: item.label }),
|
|
1232
|
+
/* @__PURE__ */ jsx29("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1038
1233
|
] }, item.label)) });
|
|
1039
1234
|
}
|
|
1040
1235
|
|
|
1041
1236
|
// src/components/ReportSchemaError.tsx
|
|
1042
|
-
import { jsx as
|
|
1237
|
+
import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1043
1238
|
function ReportSchemaError({ error }) {
|
|
1044
|
-
return /* @__PURE__ */
|
|
1045
|
-
/* @__PURE__ */
|
|
1046
|
-
/* @__PURE__ */
|
|
1047
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */
|
|
1239
|
+
return /* @__PURE__ */ jsxs18("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1240
|
+
/* @__PURE__ */ jsx30("p", { children: /* @__PURE__ */ jsx30("strong", { children: "Report could not be displayed." }) }),
|
|
1241
|
+
/* @__PURE__ */ jsx30("p", { children: error.message }),
|
|
1242
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs18("p", { children: [
|
|
1048
1243
|
"The report bundle is newer than this version of ",
|
|
1049
|
-
/* @__PURE__ */
|
|
1244
|
+
/* @__PURE__ */ jsx30("code", { children: "executable-stories-react" }),
|
|
1050
1245
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1051
1246
|
] }) : null,
|
|
1052
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */
|
|
1053
|
-
/* @__PURE__ */
|
|
1247
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs18("details", { children: [
|
|
1248
|
+
/* @__PURE__ */ jsxs18("summary", { children: [
|
|
1054
1249
|
error.issues.length,
|
|
1055
1250
|
" validation issue",
|
|
1056
1251
|
error.issues.length === 1 ? "" : "s"
|
|
1057
1252
|
] }),
|
|
1058
|
-
/* @__PURE__ */
|
|
1253
|
+
/* @__PURE__ */ jsx30("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1059
1254
|
] }) : null
|
|
1060
1255
|
] });
|
|
1061
1256
|
}
|
|
1062
1257
|
|
|
1063
1258
|
// src/components/ReportShell.tsx
|
|
1064
|
-
import { Fragment as
|
|
1259
|
+
import { Fragment as Fragment11, jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1065
1260
|
function ReportTitleBlock({ title }) {
|
|
1066
|
-
return /* @__PURE__ */
|
|
1067
|
-
/* @__PURE__ */
|
|
1068
|
-
/* @__PURE__ */
|
|
1069
|
-
/* @__PURE__ */
|
|
1261
|
+
return /* @__PURE__ */ jsxs19(Fragment11, { children: [
|
|
1262
|
+
/* @__PURE__ */ jsx31("h1", { children: title ?? "Story Report" }),
|
|
1263
|
+
/* @__PURE__ */ jsx31(ReportSummary, {}),
|
|
1264
|
+
/* @__PURE__ */ jsx31(ReportMeta, {})
|
|
1070
1265
|
] });
|
|
1071
1266
|
}
|
|
1072
1267
|
function ReportErrorShell({
|
|
@@ -1075,28 +1270,28 @@ function ReportErrorShell({
|
|
|
1075
1270
|
title,
|
|
1076
1271
|
dataTheme
|
|
1077
1272
|
}) {
|
|
1078
|
-
return /* @__PURE__ */
|
|
1273
|
+
return /* @__PURE__ */ jsx31("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx31(ReportSchemaError, { error }) });
|
|
1079
1274
|
}
|
|
1080
1275
|
|
|
1081
1276
|
// src/components/Report.tsx
|
|
1082
|
-
import { jsx as
|
|
1277
|
+
import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1083
1278
|
function Report(props) {
|
|
1084
1279
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1085
1280
|
const result = unwrapReport(report);
|
|
1086
1281
|
if (!result.ok) {
|
|
1087
|
-
return /* @__PURE__ */
|
|
1282
|
+
return /* @__PURE__ */ jsx32(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1088
1283
|
}
|
|
1089
1284
|
const data = result.data;
|
|
1090
1285
|
const hasContent = data.features.length > 0;
|
|
1091
|
-
return /* @__PURE__ */
|
|
1092
|
-
/* @__PURE__ */
|
|
1093
|
-
hasContent ? /* @__PURE__ */
|
|
1286
|
+
return /* @__PURE__ */ jsx32(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs20("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1287
|
+
/* @__PURE__ */ jsx32("header", { className: "es-report-header", children: /* @__PURE__ */ jsx32(ReportTitleBlock, { title }) }),
|
|
1288
|
+
hasContent ? /* @__PURE__ */ jsx32(ReportFeatureList, {}) : /* @__PURE__ */ jsx32(ReportEmpty, {})
|
|
1094
1289
|
] }) });
|
|
1095
1290
|
}
|
|
1096
1291
|
|
|
1097
1292
|
// src/components/doc/MermaidView.tsx
|
|
1098
1293
|
import { useEffect, useRef, useState as useState2 } from "react";
|
|
1099
|
-
import { jsx as
|
|
1294
|
+
import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1100
1295
|
function prefersDark(el) {
|
|
1101
1296
|
const themed = el?.closest("[data-theme]");
|
|
1102
1297
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -1133,9 +1328,9 @@ function MermaidView({ entry, load }) {
|
|
|
1133
1328
|
};
|
|
1134
1329
|
}, [entry.code, load]);
|
|
1135
1330
|
if (svg) {
|
|
1136
|
-
return /* @__PURE__ */
|
|
1137
|
-
entry.title ? /* @__PURE__ */
|
|
1138
|
-
/* @__PURE__ */
|
|
1331
|
+
return /* @__PURE__ */ jsxs21("figure", { ref, className: "my-3", children: [
|
|
1332
|
+
entry.title ? /* @__PURE__ */ jsx33("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
1333
|
+
/* @__PURE__ */ jsx33(
|
|
1139
1334
|
"div",
|
|
1140
1335
|
{
|
|
1141
1336
|
role: "img",
|
|
@@ -1146,18 +1341,18 @@ function MermaidView({ entry, load }) {
|
|
|
1146
1341
|
)
|
|
1147
1342
|
] });
|
|
1148
1343
|
}
|
|
1149
|
-
return /* @__PURE__ */
|
|
1344
|
+
return /* @__PURE__ */ jsx33(MermaidSource, { entry, ref });
|
|
1150
1345
|
}
|
|
1151
1346
|
|
|
1152
1347
|
// src/components/doc/MermaidDiagram.tsx
|
|
1153
|
-
import { jsx as
|
|
1348
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
1154
1349
|
var mermaidLoader;
|
|
1155
1350
|
function loadMermaid() {
|
|
1156
1351
|
mermaidLoader ??= import("mermaid").then((m) => m.default);
|
|
1157
1352
|
return mermaidLoader;
|
|
1158
1353
|
}
|
|
1159
1354
|
function MermaidDiagram({ entry, load = loadMermaid }) {
|
|
1160
|
-
return /* @__PURE__ */
|
|
1355
|
+
return /* @__PURE__ */ jsx34(MermaidView, { entry, load });
|
|
1161
1356
|
}
|
|
1162
1357
|
|
|
1163
1358
|
// src/components/ScenarioExplorer.tsx
|
|
@@ -1167,12 +1362,12 @@ import { useState as useState3 } from "react";
|
|
|
1167
1362
|
import "react";
|
|
1168
1363
|
import { Command as CommandPrimitive } from "cmdk";
|
|
1169
1364
|
import { SearchIcon } from "lucide-react";
|
|
1170
|
-
import { jsx as
|
|
1365
|
+
import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1171
1366
|
function Command({
|
|
1172
1367
|
className,
|
|
1173
1368
|
...props
|
|
1174
1369
|
}) {
|
|
1175
|
-
return /* @__PURE__ */
|
|
1370
|
+
return /* @__PURE__ */ jsx35(
|
|
1176
1371
|
CommandPrimitive,
|
|
1177
1372
|
{
|
|
1178
1373
|
"data-slot": "command",
|
|
@@ -1188,14 +1383,14 @@ function CommandInput({
|
|
|
1188
1383
|
className,
|
|
1189
1384
|
...props
|
|
1190
1385
|
}) {
|
|
1191
|
-
return /* @__PURE__ */
|
|
1386
|
+
return /* @__PURE__ */ jsxs22(
|
|
1192
1387
|
"div",
|
|
1193
1388
|
{
|
|
1194
1389
|
"data-slot": "command-input-wrapper",
|
|
1195
1390
|
className: "flex h-9 items-center gap-2 border-b px-3",
|
|
1196
1391
|
children: [
|
|
1197
|
-
/* @__PURE__ */
|
|
1198
|
-
/* @__PURE__ */
|
|
1392
|
+
/* @__PURE__ */ jsx35(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
|
|
1393
|
+
/* @__PURE__ */ jsx35(
|
|
1199
1394
|
CommandPrimitive.Input,
|
|
1200
1395
|
{
|
|
1201
1396
|
"data-slot": "command-input",
|
|
@@ -1214,7 +1409,7 @@ function CommandList({
|
|
|
1214
1409
|
className,
|
|
1215
1410
|
...props
|
|
1216
1411
|
}) {
|
|
1217
|
-
return /* @__PURE__ */
|
|
1412
|
+
return /* @__PURE__ */ jsx35(
|
|
1218
1413
|
CommandPrimitive.List,
|
|
1219
1414
|
{
|
|
1220
1415
|
"data-slot": "command-list",
|
|
@@ -1229,7 +1424,7 @@ function CommandList({
|
|
|
1229
1424
|
function CommandEmpty({
|
|
1230
1425
|
...props
|
|
1231
1426
|
}) {
|
|
1232
|
-
return /* @__PURE__ */
|
|
1427
|
+
return /* @__PURE__ */ jsx35(
|
|
1233
1428
|
CommandPrimitive.Empty,
|
|
1234
1429
|
{
|
|
1235
1430
|
"data-slot": "command-empty",
|
|
@@ -1242,7 +1437,7 @@ function CommandGroup({
|
|
|
1242
1437
|
className,
|
|
1243
1438
|
...props
|
|
1244
1439
|
}) {
|
|
1245
|
-
return /* @__PURE__ */
|
|
1440
|
+
return /* @__PURE__ */ jsx35(
|
|
1246
1441
|
CommandPrimitive.Group,
|
|
1247
1442
|
{
|
|
1248
1443
|
"data-slot": "command-group",
|
|
@@ -1258,7 +1453,7 @@ function CommandItem({
|
|
|
1258
1453
|
className,
|
|
1259
1454
|
...props
|
|
1260
1455
|
}) {
|
|
1261
|
-
return /* @__PURE__ */
|
|
1456
|
+
return /* @__PURE__ */ jsx35(
|
|
1262
1457
|
CommandPrimitive.Item,
|
|
1263
1458
|
{
|
|
1264
1459
|
"data-slot": "command-item",
|
|
@@ -1272,7 +1467,7 @@ function CommandItem({
|
|
|
1272
1467
|
}
|
|
1273
1468
|
|
|
1274
1469
|
// src/components/ScenarioExplorer.tsx
|
|
1275
|
-
import { jsx as
|
|
1470
|
+
import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1276
1471
|
var STATUS_FILTERS = [
|
|
1277
1472
|
{ value: "all", label: "All" },
|
|
1278
1473
|
{ value: "passed", label: "Passed" },
|
|
@@ -1283,22 +1478,22 @@ var STATUS_FILTERS = [
|
|
|
1283
1478
|
function ScenarioExplorer({ scenarios, summary }) {
|
|
1284
1479
|
const [status, setStatus] = useState3("all");
|
|
1285
1480
|
const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
|
|
1286
|
-
return /* @__PURE__ */
|
|
1287
|
-
summary ? /* @__PURE__ */
|
|
1481
|
+
return /* @__PURE__ */ jsxs23("div", { className: "font-sans text-foreground", children: [
|
|
1482
|
+
summary ? /* @__PURE__ */ jsxs23("p", { className: "mb-3 text-sm text-muted-foreground", children: [
|
|
1288
1483
|
summary.total,
|
|
1289
1484
|
" scenarios \xB7 ",
|
|
1290
|
-
/* @__PURE__ */
|
|
1485
|
+
/* @__PURE__ */ jsxs23("span", { className: "text-pass", children: [
|
|
1291
1486
|
summary.passed,
|
|
1292
1487
|
" passed"
|
|
1293
1488
|
] }),
|
|
1294
1489
|
" \xB7",
|
|
1295
1490
|
" ",
|
|
1296
|
-
/* @__PURE__ */
|
|
1491
|
+
/* @__PURE__ */ jsxs23("span", { className: "text-fail", children: [
|
|
1297
1492
|
summary.failed,
|
|
1298
1493
|
" failed"
|
|
1299
1494
|
] })
|
|
1300
1495
|
] }) : null,
|
|
1301
|
-
/* @__PURE__ */
|
|
1496
|
+
/* @__PURE__ */ jsx36("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ jsx36(
|
|
1302
1497
|
"button",
|
|
1303
1498
|
{
|
|
1304
1499
|
type: "button",
|
|
@@ -1313,26 +1508,26 @@ function ScenarioExplorer({ scenarios, summary }) {
|
|
|
1313
1508
|
},
|
|
1314
1509
|
f.value
|
|
1315
1510
|
)) }),
|
|
1316
|
-
/* @__PURE__ */
|
|
1511
|
+
/* @__PURE__ */ jsxs23(
|
|
1317
1512
|
Command,
|
|
1318
1513
|
{
|
|
1319
1514
|
className: "rounded-lg border border-border bg-card",
|
|
1320
1515
|
filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
|
|
1321
1516
|
children: [
|
|
1322
|
-
/* @__PURE__ */
|
|
1323
|
-
/* @__PURE__ */
|
|
1324
|
-
/* @__PURE__ */
|
|
1325
|
-
/* @__PURE__ */
|
|
1517
|
+
/* @__PURE__ */ jsx36(CommandInput, { placeholder: "Search scenarios\u2026" }),
|
|
1518
|
+
/* @__PURE__ */ jsxs23(CommandList, { className: "max-h-none", children: [
|
|
1519
|
+
/* @__PURE__ */ jsx36(CommandEmpty, { children: "No scenarios match your filters." }),
|
|
1520
|
+
/* @__PURE__ */ jsx36(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx36(
|
|
1326
1521
|
CommandItem,
|
|
1327
1522
|
{
|
|
1328
1523
|
value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
|
|
1329
1524
|
asChild: true,
|
|
1330
1525
|
className: "cursor-pointer",
|
|
1331
|
-
children: /* @__PURE__ */
|
|
1332
|
-
/* @__PURE__ */
|
|
1333
|
-
/* @__PURE__ */
|
|
1334
|
-
s.tags.slice(0, 3).map((t) => /* @__PURE__ */
|
|
1335
|
-
/* @__PURE__ */
|
|
1526
|
+
children: /* @__PURE__ */ jsxs23("a", { href: s.href, className: "flex items-center gap-3", children: [
|
|
1527
|
+
/* @__PURE__ */ jsx36(Badge, { variant: s.status, children: s.status }),
|
|
1528
|
+
/* @__PURE__ */ jsx36("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
|
|
1529
|
+
s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx36(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
|
|
1530
|
+
/* @__PURE__ */ jsx36("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
|
|
1336
1531
|
] })
|
|
1337
1532
|
},
|
|
1338
1533
|
s.id
|
|
@@ -1522,6 +1717,10 @@ var story_report_v1_default = {
|
|
|
1522
1717
|
status: {
|
|
1523
1718
|
$ref: "#/$defs/TestStatus"
|
|
1524
1719
|
},
|
|
1720
|
+
planned: {
|
|
1721
|
+
type: "boolean",
|
|
1722
|
+
description: "True for scenarios authored with the framework's todo modifier (e.g. it.todo): specified behavior with no implementation yet. Canonical status stays 'pending'; this flags why."
|
|
1723
|
+
},
|
|
1525
1724
|
durationMs: {
|
|
1526
1725
|
type: "number",
|
|
1527
1726
|
minimum: 0
|
|
@@ -2353,9 +2552,18 @@ export {
|
|
|
2353
2552
|
ReportTrace,
|
|
2354
2553
|
STORY_REPORT_SCHEMA_MAJOR,
|
|
2355
2554
|
ScenarioExplorer,
|
|
2555
|
+
ScenarioRunHistory,
|
|
2556
|
+
ciDisplayName,
|
|
2557
|
+
commitUrl,
|
|
2558
|
+
currentStreak,
|
|
2559
|
+
describeRunHistory,
|
|
2356
2560
|
err,
|
|
2561
|
+
formatRelativeAge,
|
|
2562
|
+
isReportStale,
|
|
2357
2563
|
ok,
|
|
2358
2564
|
parseStoryReport,
|
|
2565
|
+
prUrl,
|
|
2566
|
+
reportLastRunMs,
|
|
2359
2567
|
storyReportSchema,
|
|
2360
2568
|
useBuiltinRenderers,
|
|
2361
2569
|
useCustomRenderers,
|