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/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";
|
|
@@ -238,7 +250,7 @@ function DocSection({ entry }) {
|
|
|
238
250
|
/* @__PURE__ */ jsx8(
|
|
239
251
|
"div",
|
|
240
252
|
{
|
|
241
|
-
className: "es-doc-prose
|
|
253
|
+
className: "es-doc-prose prose prose-sm max-w-none",
|
|
242
254
|
dangerouslySetInnerHTML: { __html: html }
|
|
243
255
|
}
|
|
244
256
|
)
|
|
@@ -537,9 +549,6 @@ function ReportAttachments({ attachments }) {
|
|
|
537
549
|
);
|
|
538
550
|
}
|
|
539
551
|
|
|
540
|
-
// src/components/ReportTrace.tsx
|
|
541
|
-
import { formatDuration as formatDuration2 } from "executable-stories-core/utils/duration";
|
|
542
|
-
|
|
543
552
|
// src/lib/trace.ts
|
|
544
553
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
545
554
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -634,7 +643,7 @@ function ReportTrace({ spans }) {
|
|
|
634
643
|
" span",
|
|
635
644
|
rows.length === 1 ? "" : "s",
|
|
636
645
|
", ",
|
|
637
|
-
|
|
646
|
+
formatDuration(totalMs),
|
|
638
647
|
")"
|
|
639
648
|
] }),
|
|
640
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) => {
|
|
@@ -657,33 +666,128 @@ function ReportTrace({ spans }) {
|
|
|
657
666
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
658
667
|
}
|
|
659
668
|
) }),
|
|
660
|
-
/* @__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) })
|
|
661
670
|
] }, `${row.spanId}-${i}`);
|
|
662
671
|
}) })
|
|
663
672
|
] });
|
|
664
673
|
}
|
|
665
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
|
+
|
|
666
770
|
// src/interactive/collapse-context.ts
|
|
667
|
-
import { createContext as
|
|
668
|
-
var CollapseContext =
|
|
771
|
+
import { createContext as createContext3, useCallback, useContext as useContext4, useState } from "react";
|
|
772
|
+
var CollapseContext = createContext3(null);
|
|
669
773
|
var CollapseProvider = CollapseContext.Provider;
|
|
670
774
|
function useCollapse() {
|
|
671
|
-
return
|
|
775
|
+
return useContext4(CollapseContext);
|
|
672
776
|
}
|
|
673
777
|
|
|
674
778
|
// src/interactive/scenario-actions.tsx
|
|
675
|
-
import { createContext as
|
|
676
|
-
var ScenarioActionsContext =
|
|
779
|
+
import { createContext as createContext4, useContext as useContext5 } from "react";
|
|
780
|
+
var ScenarioActionsContext = createContext4(null);
|
|
677
781
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
678
782
|
function useScenarioActions() {
|
|
679
|
-
return
|
|
783
|
+
return useContext5(ScenarioActionsContext);
|
|
680
784
|
}
|
|
681
785
|
|
|
682
786
|
// src/components/ui/card.tsx
|
|
683
787
|
import "react";
|
|
684
|
-
import { jsx as
|
|
788
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
685
789
|
function Card({ className, ...props }) {
|
|
686
|
-
return /* @__PURE__ */
|
|
790
|
+
return /* @__PURE__ */ jsx21(
|
|
687
791
|
"div",
|
|
688
792
|
{
|
|
689
793
|
"data-slot": "card",
|
|
@@ -696,7 +800,7 @@ function Card({ className, ...props }) {
|
|
|
696
800
|
);
|
|
697
801
|
}
|
|
698
802
|
function CardHeader({ className, ...props }) {
|
|
699
|
-
return /* @__PURE__ */
|
|
803
|
+
return /* @__PURE__ */ jsx21(
|
|
700
804
|
"div",
|
|
701
805
|
{
|
|
702
806
|
"data-slot": "card-header",
|
|
@@ -709,7 +813,7 @@ function CardHeader({ className, ...props }) {
|
|
|
709
813
|
);
|
|
710
814
|
}
|
|
711
815
|
function CardContent({ className, ...props }) {
|
|
712
|
-
return /* @__PURE__ */
|
|
816
|
+
return /* @__PURE__ */ jsx21(
|
|
713
817
|
"div",
|
|
714
818
|
{
|
|
715
819
|
"data-slot": "card-content",
|
|
@@ -720,7 +824,7 @@ function CardContent({ className, ...props }) {
|
|
|
720
824
|
}
|
|
721
825
|
|
|
722
826
|
// src/components/ReportScenario.tsx
|
|
723
|
-
import { jsx as
|
|
827
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
724
828
|
var STATUS_LABEL = {
|
|
725
829
|
passed: "Passed",
|
|
726
830
|
failed: "Failed",
|
|
@@ -748,12 +852,12 @@ var STATUS_BADGE = {
|
|
|
748
852
|
function ReportScenario({ scenario, hideTitle = false }) {
|
|
749
853
|
const titleId = `${scenario.id}-title`;
|
|
750
854
|
const bodyId = `${scenario.id}-body`;
|
|
751
|
-
const label = STATUS_LABEL[scenario.status];
|
|
855
|
+
const label = scenario.planned ? "Planned" : STATUS_LABEL[scenario.status];
|
|
752
856
|
const collapse = useCollapse();
|
|
753
857
|
const collapsible = collapse !== null && !hideTitle;
|
|
754
858
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
755
859
|
const actions = useScenarioActions();
|
|
756
|
-
return /* @__PURE__ */
|
|
860
|
+
return /* @__PURE__ */ jsxs14(
|
|
757
861
|
Card,
|
|
758
862
|
{
|
|
759
863
|
id: scenario.id,
|
|
@@ -761,10 +865,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
761
865
|
...hideTitle ? { "aria-label": `${scenario.title} \u2014 ${label}` } : { "aria-labelledby": titleId },
|
|
762
866
|
className: "gap-0 py-0",
|
|
763
867
|
children: [
|
|
764
|
-
/* @__PURE__ */
|
|
765
|
-
/* @__PURE__ */
|
|
766
|
-
hideTitle ? null : /* @__PURE__ */
|
|
767
|
-
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(
|
|
768
872
|
"button",
|
|
769
873
|
{
|
|
770
874
|
type: "button",
|
|
@@ -773,17 +877,18 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
773
877
|
"aria-controls": bodyId,
|
|
774
878
|
"aria-label": `Toggle ${scenario.title}`,
|
|
775
879
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
776
|
-
children: /* @__PURE__ */
|
|
880
|
+
children: /* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
777
881
|
}
|
|
778
882
|
) : null,
|
|
779
|
-
/* @__PURE__ */
|
|
780
|
-
/* @__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 })
|
|
781
885
|
] }),
|
|
782
|
-
/* @__PURE__ */
|
|
783
|
-
|
|
784
|
-
/* @__PURE__ */
|
|
785
|
-
|
|
786
|
-
|
|
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(
|
|
787
892
|
"button",
|
|
788
893
|
{
|
|
789
894
|
type: "button",
|
|
@@ -794,7 +899,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
794
899
|
children: "link"
|
|
795
900
|
}
|
|
796
901
|
),
|
|
797
|
-
/* @__PURE__ */
|
|
902
|
+
/* @__PURE__ */ jsx22(
|
|
798
903
|
"button",
|
|
799
904
|
{
|
|
800
905
|
type: "button",
|
|
@@ -805,7 +910,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
805
910
|
children: "md"
|
|
806
911
|
}
|
|
807
912
|
),
|
|
808
|
-
/* @__PURE__ */
|
|
913
|
+
/* @__PURE__ */ jsx22(
|
|
809
914
|
"button",
|
|
810
915
|
{
|
|
811
916
|
type: "button",
|
|
@@ -819,13 +924,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
819
924
|
] }) : null
|
|
820
925
|
] })
|
|
821
926
|
] }),
|
|
822
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */
|
|
823
|
-
scenario.tags.map((t) => /* @__PURE__ */
|
|
824
|
-
(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}`))
|
|
825
930
|
] }) : null
|
|
826
931
|
] }),
|
|
827
|
-
/* @__PURE__ */
|
|
828
|
-
scenario.errorMessage ? /* @__PURE__ */
|
|
932
|
+
/* @__PURE__ */ jsxs14(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
933
|
+
scenario.errorMessage ? /* @__PURE__ */ jsx22(
|
|
829
934
|
"pre",
|
|
830
935
|
{
|
|
831
936
|
role: "alert",
|
|
@@ -833,10 +938,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
833
938
|
children: scenario.errorMessage
|
|
834
939
|
}
|
|
835
940
|
) : null,
|
|
836
|
-
/* @__PURE__ */
|
|
837
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */
|
|
838
|
-
/* @__PURE__ */
|
|
839
|
-
/* @__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 })
|
|
840
945
|
] })
|
|
841
946
|
]
|
|
842
947
|
}
|
|
@@ -844,13 +949,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
844
949
|
}
|
|
845
950
|
|
|
846
951
|
// src/components/ReportScenarioList.tsx
|
|
847
|
-
import { Fragment as
|
|
952
|
+
import { Fragment as Fragment8, jsx as jsx23 } from "react/jsx-runtime";
|
|
848
953
|
function ReportScenarioList({ feature }) {
|
|
849
|
-
return /* @__PURE__ */
|
|
954
|
+
return /* @__PURE__ */ jsx23(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx23(ReportScenario, { scenario }, scenario.id)) });
|
|
850
955
|
}
|
|
851
956
|
|
|
852
957
|
// src/components/ReportFeature.tsx
|
|
853
|
-
import { jsx as
|
|
958
|
+
import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
854
959
|
function ReportFeature({ feature }) {
|
|
855
960
|
const titleId = `${feature.id}-title`;
|
|
856
961
|
const bodyId = `${feature.id}-body`;
|
|
@@ -858,7 +963,7 @@ function ReportFeature({ feature }) {
|
|
|
858
963
|
const skipped = s.skipped + s.pending;
|
|
859
964
|
const collapse = useCollapse();
|
|
860
965
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
861
|
-
return /* @__PURE__ */
|
|
966
|
+
return /* @__PURE__ */ jsxs15(
|
|
862
967
|
"section",
|
|
863
968
|
{
|
|
864
969
|
id: feature.id,
|
|
@@ -866,9 +971,9 @@ function ReportFeature({ feature }) {
|
|
|
866
971
|
"aria-labelledby": titleId,
|
|
867
972
|
className: "overflow-hidden rounded-xl border border-border bg-card shadow-sm",
|
|
868
973
|
children: [
|
|
869
|
-
/* @__PURE__ */
|
|
870
|
-
/* @__PURE__ */
|
|
871
|
-
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(
|
|
872
977
|
"button",
|
|
873
978
|
{
|
|
874
979
|
type: "button",
|
|
@@ -877,30 +982,30 @@ function ReportFeature({ feature }) {
|
|
|
877
982
|
"aria-controls": bodyId,
|
|
878
983
|
"aria-label": `Toggle ${feature.title}`,
|
|
879
984
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
880
|
-
children: /* @__PURE__ */
|
|
985
|
+
children: /* @__PURE__ */ jsx24("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
881
986
|
}
|
|
882
987
|
) : null,
|
|
883
|
-
/* @__PURE__ */
|
|
884
|
-
/* @__PURE__ */
|
|
885
|
-
/* @__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 })
|
|
886
991
|
] })
|
|
887
992
|
] }),
|
|
888
|
-
/* @__PURE__ */
|
|
993
|
+
/* @__PURE__ */ jsxs15(
|
|
889
994
|
"div",
|
|
890
995
|
{
|
|
891
996
|
role: "img",
|
|
892
997
|
className: "flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium",
|
|
893
998
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
894
999
|
children: [
|
|
895
|
-
/* @__PURE__ */
|
|
1000
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-pass", children: [
|
|
896
1001
|
"\u2713",
|
|
897
1002
|
s.passed
|
|
898
1003
|
] }),
|
|
899
|
-
/* @__PURE__ */
|
|
1004
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-fail", children: [
|
|
900
1005
|
"\u2717",
|
|
901
1006
|
s.failed
|
|
902
1007
|
] }),
|
|
903
|
-
/* @__PURE__ */
|
|
1008
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-skip", children: [
|
|
904
1009
|
"\u25CB",
|
|
905
1010
|
skipped
|
|
906
1011
|
] })
|
|
@@ -908,24 +1013,24 @@ function ReportFeature({ feature }) {
|
|
|
908
1013
|
}
|
|
909
1014
|
)
|
|
910
1015
|
] }),
|
|
911
|
-
/* @__PURE__ */
|
|
1016
|
+
/* @__PURE__ */ jsx24("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-2 p-3", children: /* @__PURE__ */ jsx24(ReportScenarioList, { feature }) })
|
|
912
1017
|
]
|
|
913
1018
|
}
|
|
914
1019
|
);
|
|
915
1020
|
}
|
|
916
1021
|
|
|
917
1022
|
// src/components/ReportFeatureList.tsx
|
|
918
|
-
import { Fragment as
|
|
1023
|
+
import { Fragment as Fragment9, jsx as jsx25 } from "react/jsx-runtime";
|
|
919
1024
|
function ReportFeatureList() {
|
|
920
1025
|
const report = useReport();
|
|
921
|
-
return /* @__PURE__ */
|
|
1026
|
+
return /* @__PURE__ */ jsx25(Fragment9, { children: report.features.map((feature) => /* @__PURE__ */ jsx25(ReportFeature, { feature }, feature.id)) });
|
|
922
1027
|
}
|
|
923
1028
|
|
|
924
1029
|
// src/components/ui/empty.tsx
|
|
925
1030
|
import { cva as cva2 } from "class-variance-authority";
|
|
926
|
-
import { jsx as
|
|
1031
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
927
1032
|
function Empty({ className, ...props }) {
|
|
928
|
-
return /* @__PURE__ */
|
|
1033
|
+
return /* @__PURE__ */ jsx26(
|
|
929
1034
|
"div",
|
|
930
1035
|
{
|
|
931
1036
|
"data-slot": "empty",
|
|
@@ -938,7 +1043,7 @@ function Empty({ className, ...props }) {
|
|
|
938
1043
|
);
|
|
939
1044
|
}
|
|
940
1045
|
function EmptyHeader({ className, ...props }) {
|
|
941
|
-
return /* @__PURE__ */
|
|
1046
|
+
return /* @__PURE__ */ jsx26(
|
|
942
1047
|
"div",
|
|
943
1048
|
{
|
|
944
1049
|
"data-slot": "empty-header",
|
|
@@ -965,7 +1070,7 @@ var emptyMediaVariants = cva2(
|
|
|
965
1070
|
}
|
|
966
1071
|
);
|
|
967
1072
|
function EmptyTitle({ className, ...props }) {
|
|
968
|
-
return /* @__PURE__ */
|
|
1073
|
+
return /* @__PURE__ */ jsx26(
|
|
969
1074
|
"div",
|
|
970
1075
|
{
|
|
971
1076
|
"data-slot": "empty-title",
|
|
@@ -976,16 +1081,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
976
1081
|
}
|
|
977
1082
|
|
|
978
1083
|
// src/components/ReportEmpty.tsx
|
|
979
|
-
import { jsx as
|
|
1084
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
980
1085
|
function ReportEmpty({ message }) {
|
|
981
|
-
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." }) }) });
|
|
982
1087
|
}
|
|
983
1088
|
|
|
984
1089
|
// src/components/ReportSummary.tsx
|
|
985
|
-
import { Fragment as
|
|
1090
|
+
import { Fragment as Fragment10, jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
986
1091
|
function ReportSummary({ className }) {
|
|
987
1092
|
const report = useReport();
|
|
988
|
-
return /* @__PURE__ */
|
|
1093
|
+
return /* @__PURE__ */ jsx28(
|
|
989
1094
|
ReportSummaryView,
|
|
990
1095
|
{
|
|
991
1096
|
summary: report.summary,
|
|
@@ -995,32 +1100,32 @@ function ReportSummary({ className }) {
|
|
|
995
1100
|
);
|
|
996
1101
|
}
|
|
997
1102
|
function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
998
|
-
return /* @__PURE__ */
|
|
999
|
-
/* @__PURE__ */
|
|
1000
|
-
/* @__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 }),
|
|
1001
1106
|
" scenario",
|
|
1002
1107
|
summary.total === 1 ? "" : "s"
|
|
1003
1108
|
] }),
|
|
1004
1109
|
" \xB7 ",
|
|
1005
|
-
/* @__PURE__ */
|
|
1110
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "passed", className: "text-pass", children: [
|
|
1006
1111
|
summary.passed,
|
|
1007
1112
|
" passed"
|
|
1008
1113
|
] }),
|
|
1009
1114
|
" \xB7 ",
|
|
1010
|
-
/* @__PURE__ */
|
|
1115
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "failed", className: "text-fail", children: [
|
|
1011
1116
|
summary.failed,
|
|
1012
1117
|
" failed"
|
|
1013
1118
|
] }),
|
|
1014
|
-
summary.skipped > 0 ? /* @__PURE__ */
|
|
1119
|
+
summary.skipped > 0 ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
1015
1120
|
" \xB7 ",
|
|
1016
|
-
/* @__PURE__ */
|
|
1121
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "skipped", className: "text-skip", children: [
|
|
1017
1122
|
summary.skipped,
|
|
1018
1123
|
" skipped"
|
|
1019
1124
|
] })
|
|
1020
1125
|
] }) : null,
|
|
1021
|
-
summary.pending > 0 ? /* @__PURE__ */
|
|
1126
|
+
summary.pending > 0 ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
1022
1127
|
" \xB7 ",
|
|
1023
|
-
/* @__PURE__ */
|
|
1128
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "pending", className: "text-pend", children: [
|
|
1024
1129
|
summary.pending,
|
|
1025
1130
|
" pending"
|
|
1026
1131
|
] })
|
|
@@ -1028,69 +1133,135 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1028
1133
|
] });
|
|
1029
1134
|
}
|
|
1030
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
|
+
|
|
1031
1185
|
// src/components/ReportMeta.tsx
|
|
1032
|
-
import {
|
|
1033
|
-
import { jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1186
|
+
import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1034
1187
|
function ReportMeta() {
|
|
1035
1188
|
const report = useReport();
|
|
1036
1189
|
const items = [];
|
|
1190
|
+
const linkClass = "text-primary underline underline-offset-2";
|
|
1037
1191
|
if (report.startedAtMs) {
|
|
1038
1192
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1039
1193
|
}
|
|
1040
1194
|
if (report.durationMs) {
|
|
1041
|
-
items.push({ label: "Duration", value:
|
|
1195
|
+
items.push({ label: "Duration", value: formatDuration(report.durationMs) });
|
|
1042
1196
|
}
|
|
1043
1197
|
if (report.packageVersion) {
|
|
1044
1198
|
items.push({ label: "Version", value: report.packageVersion });
|
|
1045
1199
|
}
|
|
1046
|
-
if (report.
|
|
1047
|
-
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
|
+
});
|
|
1048
1211
|
}
|
|
1049
1212
|
if (report.ci) {
|
|
1050
1213
|
items.push({
|
|
1051
1214
|
label: "CI",
|
|
1052
|
-
value: report.ci.url ? /* @__PURE__ */
|
|
1053
|
-
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),
|
|
1054
1217
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1055
|
-
] }) : `${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
|
|
1056
1227
|
});
|
|
1057
1228
|
}
|
|
1058
1229
|
if (items.length === 0) return null;
|
|
1059
|
-
return /* @__PURE__ */
|
|
1060
|
-
/* @__PURE__ */
|
|
1061
|
-
/* @__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 })
|
|
1062
1233
|
] }, item.label)) });
|
|
1063
1234
|
}
|
|
1064
1235
|
|
|
1065
1236
|
// src/components/ReportSchemaError.tsx
|
|
1066
|
-
import { jsx as
|
|
1237
|
+
import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1067
1238
|
function ReportSchemaError({ error }) {
|
|
1068
|
-
return /* @__PURE__ */
|
|
1069
|
-
/* @__PURE__ */
|
|
1070
|
-
/* @__PURE__ */
|
|
1071
|
-
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: [
|
|
1072
1243
|
"The report bundle is newer than this version of ",
|
|
1073
|
-
/* @__PURE__ */
|
|
1244
|
+
/* @__PURE__ */ jsx30("code", { children: "executable-stories-react" }),
|
|
1074
1245
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1075
1246
|
] }) : null,
|
|
1076
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */
|
|
1077
|
-
/* @__PURE__ */
|
|
1247
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs18("details", { children: [
|
|
1248
|
+
/* @__PURE__ */ jsxs18("summary", { children: [
|
|
1078
1249
|
error.issues.length,
|
|
1079
1250
|
" validation issue",
|
|
1080
1251
|
error.issues.length === 1 ? "" : "s"
|
|
1081
1252
|
] }),
|
|
1082
|
-
/* @__PURE__ */
|
|
1253
|
+
/* @__PURE__ */ jsx30("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1083
1254
|
] }) : null
|
|
1084
1255
|
] });
|
|
1085
1256
|
}
|
|
1086
1257
|
|
|
1087
1258
|
// src/components/ReportShell.tsx
|
|
1088
|
-
import { Fragment as
|
|
1259
|
+
import { Fragment as Fragment11, jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1089
1260
|
function ReportTitleBlock({ title }) {
|
|
1090
|
-
return /* @__PURE__ */
|
|
1091
|
-
/* @__PURE__ */
|
|
1092
|
-
/* @__PURE__ */
|
|
1093
|
-
/* @__PURE__ */
|
|
1261
|
+
return /* @__PURE__ */ jsxs19(Fragment11, { children: [
|
|
1262
|
+
/* @__PURE__ */ jsx31("h1", { children: title ?? "Story Report" }),
|
|
1263
|
+
/* @__PURE__ */ jsx31(ReportSummary, {}),
|
|
1264
|
+
/* @__PURE__ */ jsx31(ReportMeta, {})
|
|
1094
1265
|
] });
|
|
1095
1266
|
}
|
|
1096
1267
|
function ReportErrorShell({
|
|
@@ -1099,28 +1270,28 @@ function ReportErrorShell({
|
|
|
1099
1270
|
title,
|
|
1100
1271
|
dataTheme
|
|
1101
1272
|
}) {
|
|
1102
|
-
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 }) });
|
|
1103
1274
|
}
|
|
1104
1275
|
|
|
1105
1276
|
// src/components/Report.tsx
|
|
1106
|
-
import { jsx as
|
|
1277
|
+
import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1107
1278
|
function Report(props) {
|
|
1108
1279
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1109
1280
|
const result = unwrapReport(report);
|
|
1110
1281
|
if (!result.ok) {
|
|
1111
|
-
return /* @__PURE__ */
|
|
1282
|
+
return /* @__PURE__ */ jsx32(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1112
1283
|
}
|
|
1113
1284
|
const data = result.data;
|
|
1114
1285
|
const hasContent = data.features.length > 0;
|
|
1115
|
-
return /* @__PURE__ */
|
|
1116
|
-
/* @__PURE__ */
|
|
1117
|
-
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, {})
|
|
1118
1289
|
] }) });
|
|
1119
1290
|
}
|
|
1120
1291
|
|
|
1121
1292
|
// src/components/doc/MermaidView.tsx
|
|
1122
1293
|
import { useEffect, useRef, useState as useState2 } from "react";
|
|
1123
|
-
import { jsx as
|
|
1294
|
+
import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1124
1295
|
function prefersDark(el) {
|
|
1125
1296
|
const themed = el?.closest("[data-theme]");
|
|
1126
1297
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -1157,9 +1328,9 @@ function MermaidView({ entry, load }) {
|
|
|
1157
1328
|
};
|
|
1158
1329
|
}, [entry.code, load]);
|
|
1159
1330
|
if (svg) {
|
|
1160
|
-
return /* @__PURE__ */
|
|
1161
|
-
entry.title ? /* @__PURE__ */
|
|
1162
|
-
/* @__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(
|
|
1163
1334
|
"div",
|
|
1164
1335
|
{
|
|
1165
1336
|
role: "img",
|
|
@@ -1170,18 +1341,18 @@ function MermaidView({ entry, load }) {
|
|
|
1170
1341
|
)
|
|
1171
1342
|
] });
|
|
1172
1343
|
}
|
|
1173
|
-
return /* @__PURE__ */
|
|
1344
|
+
return /* @__PURE__ */ jsx33(MermaidSource, { entry, ref });
|
|
1174
1345
|
}
|
|
1175
1346
|
|
|
1176
1347
|
// src/components/doc/MermaidDiagram.tsx
|
|
1177
|
-
import { jsx as
|
|
1348
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
1178
1349
|
var mermaidLoader;
|
|
1179
1350
|
function loadMermaid() {
|
|
1180
1351
|
mermaidLoader ??= import("mermaid").then((m) => m.default);
|
|
1181
1352
|
return mermaidLoader;
|
|
1182
1353
|
}
|
|
1183
1354
|
function MermaidDiagram({ entry, load = loadMermaid }) {
|
|
1184
|
-
return /* @__PURE__ */
|
|
1355
|
+
return /* @__PURE__ */ jsx34(MermaidView, { entry, load });
|
|
1185
1356
|
}
|
|
1186
1357
|
|
|
1187
1358
|
// src/components/ScenarioExplorer.tsx
|
|
@@ -1191,12 +1362,12 @@ import { useState as useState3 } from "react";
|
|
|
1191
1362
|
import "react";
|
|
1192
1363
|
import { Command as CommandPrimitive } from "cmdk";
|
|
1193
1364
|
import { SearchIcon } from "lucide-react";
|
|
1194
|
-
import { jsx as
|
|
1365
|
+
import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1195
1366
|
function Command({
|
|
1196
1367
|
className,
|
|
1197
1368
|
...props
|
|
1198
1369
|
}) {
|
|
1199
|
-
return /* @__PURE__ */
|
|
1370
|
+
return /* @__PURE__ */ jsx35(
|
|
1200
1371
|
CommandPrimitive,
|
|
1201
1372
|
{
|
|
1202
1373
|
"data-slot": "command",
|
|
@@ -1212,14 +1383,14 @@ function CommandInput({
|
|
|
1212
1383
|
className,
|
|
1213
1384
|
...props
|
|
1214
1385
|
}) {
|
|
1215
|
-
return /* @__PURE__ */
|
|
1386
|
+
return /* @__PURE__ */ jsxs22(
|
|
1216
1387
|
"div",
|
|
1217
1388
|
{
|
|
1218
1389
|
"data-slot": "command-input-wrapper",
|
|
1219
1390
|
className: "flex h-9 items-center gap-2 border-b px-3",
|
|
1220
1391
|
children: [
|
|
1221
|
-
/* @__PURE__ */
|
|
1222
|
-
/* @__PURE__ */
|
|
1392
|
+
/* @__PURE__ */ jsx35(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
|
|
1393
|
+
/* @__PURE__ */ jsx35(
|
|
1223
1394
|
CommandPrimitive.Input,
|
|
1224
1395
|
{
|
|
1225
1396
|
"data-slot": "command-input",
|
|
@@ -1238,7 +1409,7 @@ function CommandList({
|
|
|
1238
1409
|
className,
|
|
1239
1410
|
...props
|
|
1240
1411
|
}) {
|
|
1241
|
-
return /* @__PURE__ */
|
|
1412
|
+
return /* @__PURE__ */ jsx35(
|
|
1242
1413
|
CommandPrimitive.List,
|
|
1243
1414
|
{
|
|
1244
1415
|
"data-slot": "command-list",
|
|
@@ -1253,7 +1424,7 @@ function CommandList({
|
|
|
1253
1424
|
function CommandEmpty({
|
|
1254
1425
|
...props
|
|
1255
1426
|
}) {
|
|
1256
|
-
return /* @__PURE__ */
|
|
1427
|
+
return /* @__PURE__ */ jsx35(
|
|
1257
1428
|
CommandPrimitive.Empty,
|
|
1258
1429
|
{
|
|
1259
1430
|
"data-slot": "command-empty",
|
|
@@ -1266,7 +1437,7 @@ function CommandGroup({
|
|
|
1266
1437
|
className,
|
|
1267
1438
|
...props
|
|
1268
1439
|
}) {
|
|
1269
|
-
return /* @__PURE__ */
|
|
1440
|
+
return /* @__PURE__ */ jsx35(
|
|
1270
1441
|
CommandPrimitive.Group,
|
|
1271
1442
|
{
|
|
1272
1443
|
"data-slot": "command-group",
|
|
@@ -1282,7 +1453,7 @@ function CommandItem({
|
|
|
1282
1453
|
className,
|
|
1283
1454
|
...props
|
|
1284
1455
|
}) {
|
|
1285
|
-
return /* @__PURE__ */
|
|
1456
|
+
return /* @__PURE__ */ jsx35(
|
|
1286
1457
|
CommandPrimitive.Item,
|
|
1287
1458
|
{
|
|
1288
1459
|
"data-slot": "command-item",
|
|
@@ -1296,7 +1467,7 @@ function CommandItem({
|
|
|
1296
1467
|
}
|
|
1297
1468
|
|
|
1298
1469
|
// src/components/ScenarioExplorer.tsx
|
|
1299
|
-
import { jsx as
|
|
1470
|
+
import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1300
1471
|
var STATUS_FILTERS = [
|
|
1301
1472
|
{ value: "all", label: "All" },
|
|
1302
1473
|
{ value: "passed", label: "Passed" },
|
|
@@ -1307,22 +1478,22 @@ var STATUS_FILTERS = [
|
|
|
1307
1478
|
function ScenarioExplorer({ scenarios, summary }) {
|
|
1308
1479
|
const [status, setStatus] = useState3("all");
|
|
1309
1480
|
const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
|
|
1310
|
-
return /* @__PURE__ */
|
|
1311
|
-
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: [
|
|
1312
1483
|
summary.total,
|
|
1313
1484
|
" scenarios \xB7 ",
|
|
1314
|
-
/* @__PURE__ */
|
|
1485
|
+
/* @__PURE__ */ jsxs23("span", { className: "text-pass", children: [
|
|
1315
1486
|
summary.passed,
|
|
1316
1487
|
" passed"
|
|
1317
1488
|
] }),
|
|
1318
1489
|
" \xB7",
|
|
1319
1490
|
" ",
|
|
1320
|
-
/* @__PURE__ */
|
|
1491
|
+
/* @__PURE__ */ jsxs23("span", { className: "text-fail", children: [
|
|
1321
1492
|
summary.failed,
|
|
1322
1493
|
" failed"
|
|
1323
1494
|
] })
|
|
1324
1495
|
] }) : null,
|
|
1325
|
-
/* @__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(
|
|
1326
1497
|
"button",
|
|
1327
1498
|
{
|
|
1328
1499
|
type: "button",
|
|
@@ -1337,26 +1508,26 @@ function ScenarioExplorer({ scenarios, summary }) {
|
|
|
1337
1508
|
},
|
|
1338
1509
|
f.value
|
|
1339
1510
|
)) }),
|
|
1340
|
-
/* @__PURE__ */
|
|
1511
|
+
/* @__PURE__ */ jsxs23(
|
|
1341
1512
|
Command,
|
|
1342
1513
|
{
|
|
1343
1514
|
className: "rounded-lg border border-border bg-card",
|
|
1344
1515
|
filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
|
|
1345
1516
|
children: [
|
|
1346
|
-
/* @__PURE__ */
|
|
1347
|
-
/* @__PURE__ */
|
|
1348
|
-
/* @__PURE__ */
|
|
1349
|
-
/* @__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(
|
|
1350
1521
|
CommandItem,
|
|
1351
1522
|
{
|
|
1352
1523
|
value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
|
|
1353
1524
|
asChild: true,
|
|
1354
1525
|
className: "cursor-pointer",
|
|
1355
|
-
children: /* @__PURE__ */
|
|
1356
|
-
/* @__PURE__ */
|
|
1357
|
-
/* @__PURE__ */
|
|
1358
|
-
s.tags.slice(0, 3).map((t) => /* @__PURE__ */
|
|
1359
|
-
/* @__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 })
|
|
1360
1531
|
] })
|
|
1361
1532
|
},
|
|
1362
1533
|
s.id
|
|
@@ -1546,6 +1717,10 @@ var story_report_v1_default = {
|
|
|
1546
1717
|
status: {
|
|
1547
1718
|
$ref: "#/$defs/TestStatus"
|
|
1548
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
|
+
},
|
|
1549
1724
|
durationMs: {
|
|
1550
1725
|
type: "number",
|
|
1551
1726
|
minimum: 0
|
|
@@ -2377,9 +2552,18 @@ export {
|
|
|
2377
2552
|
ReportTrace,
|
|
2378
2553
|
STORY_REPORT_SCHEMA_MAJOR,
|
|
2379
2554
|
ScenarioExplorer,
|
|
2555
|
+
ScenarioRunHistory,
|
|
2556
|
+
ciDisplayName,
|
|
2557
|
+
commitUrl,
|
|
2558
|
+
currentStreak,
|
|
2559
|
+
describeRunHistory,
|
|
2380
2560
|
err,
|
|
2561
|
+
formatRelativeAge,
|
|
2562
|
+
isReportStale,
|
|
2381
2563
|
ok,
|
|
2382
2564
|
parseStoryReport,
|
|
2565
|
+
prUrl,
|
|
2566
|
+
reportLastRunMs,
|
|
2383
2567
|
storyReportSchema,
|
|
2384
2568
|
useBuiltinRenderers,
|
|
2385
2569
|
useCustomRenderers,
|