executable-stories-react 0.18.0 → 0.20.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.d.cts CHANGED
@@ -100,9 +100,9 @@ declare function ReportSummaryView({ summary, className, ariaLabel }: ReportSumm
100
100
  declare function ReportMeta(): react.JSX.Element | null;
101
101
 
102
102
  /**
103
- * Renders scenario attachments. Base64 images embed inline; everything else
104
- * becomes a labelled data-URI download link. Mirrors the report's attachments
105
- * block (which also inlines images and links other media).
103
+ * Renders scenario attachments. Images embed inline; text documents preview
104
+ * above their download link; other types get a labelled download link. An
105
+ * `external` attachment links to its file path and shows no preview.
106
106
  */
107
107
  declare function ReportAttachments({ attachments }: {
108
108
  attachments: ReportAttachment[];
package/dist/index.d.ts CHANGED
@@ -100,9 +100,9 @@ declare function ReportSummaryView({ summary, className, ariaLabel }: ReportSumm
100
100
  declare function ReportMeta(): react.JSX.Element | null;
101
101
 
102
102
  /**
103
- * Renders scenario attachments. Base64 images embed inline; everything else
104
- * becomes a labelled data-URI download link. Mirrors the report's attachments
105
- * block (which also inlines images and links other media).
103
+ * Renders scenario attachments. Images embed inline; text documents preview
104
+ * above their download link; other types get a labelled download link. An
105
+ * `external` attachment links to its file path and shows no preview.
106
106
  */
107
107
  declare function ReportAttachments({ attachments }: {
108
108
  attachments: ReportAttachment[];
package/dist/index.js CHANGED
@@ -658,7 +658,7 @@ function ReportDocEntries({ entries }) {
658
658
  }
659
659
 
660
660
  // src/components/ReportSteps.tsx
661
- import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
661
+ import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
662
662
  var STEP_GLYPH = {
663
663
  passed: "\u2713",
664
664
  failed: "\u2717",
@@ -735,6 +735,23 @@ function ReportStepItem({
735
735
  children: step.errorMessage
736
736
  }
737
737
  ) : null,
738
+ step.expected !== void 0 || step.actual !== void 0 ? /* @__PURE__ */ jsxs11(
739
+ "dl",
740
+ {
741
+ "data-slot": "step-comparison",
742
+ className: "mt-1.5 ml-6 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 font-mono text-xs",
743
+ children: [
744
+ step.expected !== void 0 ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
745
+ /* @__PURE__ */ jsx19("dt", { className: "text-muted-foreground", children: "Expected" }),
746
+ /* @__PURE__ */ jsx19("dd", { className: "overflow-x-auto whitespace-pre-wrap text-pass", children: step.expected })
747
+ ] }) : null,
748
+ step.actual !== void 0 ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
749
+ /* @__PURE__ */ jsx19("dt", { className: "text-muted-foreground", children: "Actual" }),
750
+ /* @__PURE__ */ jsx19("dd", { className: "overflow-x-auto whitespace-pre-wrap text-fail", children: step.actual })
751
+ ] }) : null
752
+ ]
753
+ }
754
+ ) : null,
738
755
  step.docEntries.length > 0 ? /* @__PURE__ */ jsx19("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ jsx19(ReportDocEntries, { entries: step.docEntries }) }) : null
739
756
  ]
740
757
  }
@@ -858,43 +875,77 @@ function StateCardView({ card }) {
858
875
  }
859
876
 
860
877
  // src/components/ReportAttachments.tsx
861
- import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
878
+ import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
879
+ function attachmentText(att) {
880
+ if (att.contentEncoding !== "BASE64") return att.body;
881
+ try {
882
+ return new TextDecoder().decode(Uint8Array.from(atob(att.body), (c) => c.charCodeAt(0)));
883
+ } catch {
884
+ return void 0;
885
+ }
886
+ }
887
+ function preview(att) {
888
+ const type = att.mediaType.split(";")[0].trim().toLowerCase();
889
+ const text = attachmentText(att);
890
+ if (text === void 0) return null;
891
+ if (type === "text/plain") {
892
+ return /* @__PURE__ */ jsx21("pre", { className: "max-h-96 overflow-auto rounded-md border border-border bg-muted/40 p-3 text-xs whitespace-pre-wrap", children: text });
893
+ }
894
+ if (type === "text/markdown") {
895
+ return /* @__PURE__ */ jsx21(
896
+ "div",
897
+ {
898
+ className: "es-doc-prose prose prose-sm max-w-none rounded-md border border-border p-3",
899
+ dangerouslySetInnerHTML: { __html: safeMarkdownHtml(text) }
900
+ }
901
+ );
902
+ }
903
+ if (type === "text/html") {
904
+ return /* @__PURE__ */ jsx21(DocHtml, { entry: { kind: "html", content: text, title: att.name, phase: "runtime" } });
905
+ }
906
+ return null;
907
+ }
862
908
  function ReportAttachments({ attachments }) {
863
909
  if (attachments.length === 0) return null;
864
910
  return (
865
911
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
866
912
  // blocks don't create duplicate "Attachments" region landmarks.
867
913
  /* @__PURE__ */ jsx21("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
868
- const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
869
- const isImage = att.mediaType.startsWith("image/");
870
- return /* @__PURE__ */ jsx21("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
914
+ const dataUri = att.external ? void 0 : att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
915
+ const href = dataUri ?? safeUrl(att.body);
916
+ const imageSrc = dataUri ?? safeImageUrl(att.body);
917
+ const isImage = att.mediaType.startsWith("image/") && imageSrc !== void 0;
918
+ return /* @__PURE__ */ jsx21("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs13(Fragment7, { children: [
871
919
  /* @__PURE__ */ jsx21(
872
920
  "img",
873
921
  {
874
- src: dataUri,
922
+ src: imageSrc,
875
923
  alt: att.name,
876
924
  loading: "lazy",
877
925
  className: "max-w-full rounded-md border border-border"
878
926
  }
879
927
  ),
880
928
  /* @__PURE__ */ jsx21("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
881
- ] }) : /* @__PURE__ */ jsxs13(
882
- "a",
883
- {
884
- href: dataUri,
885
- download: att.name,
886
- className: "text-xs text-link underline underline-offset-2",
887
- children: [
888
- att.name,
889
- " ",
890
- /* @__PURE__ */ jsxs13("span", { className: "text-muted-foreground", children: [
891
- "(",
892
- att.mediaType,
893
- ")"
894
- ] })
895
- ]
896
- }
897
- ) }, `${att.name}-${i}`);
929
+ ] }) : /* @__PURE__ */ jsxs13(Fragment7, { children: [
930
+ att.external ? null : preview(att),
931
+ /* @__PURE__ */ jsxs13(
932
+ "a",
933
+ {
934
+ href,
935
+ download: att.name,
936
+ className: "text-xs text-link underline underline-offset-2",
937
+ children: [
938
+ att.name,
939
+ " ",
940
+ /* @__PURE__ */ jsxs13("span", { className: "text-muted-foreground", children: [
941
+ "(",
942
+ att.mediaType,
943
+ ")"
944
+ ] })
945
+ ]
946
+ }
947
+ )
948
+ ] }) }, `${att.name}-${i}`);
898
949
  }) })
899
950
  );
900
951
  }
@@ -1070,7 +1121,7 @@ function flakinessOf(entries) {
1070
1121
  }
1071
1122
 
1072
1123
  // src/components/ScenarioRunHistory.tsx
1073
- import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
1124
+ import { Fragment as Fragment8, jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
1074
1125
  var MAX_DOTS = 10;
1075
1126
  var DOT_COLOR = {
1076
1127
  passed: "bg-pass",
@@ -1090,7 +1141,7 @@ function ScenarioRunHistory({ scenarioId }) {
1090
1141
  const recent = entries.slice(-MAX_DOTS);
1091
1142
  const flaky = flakinessOf(recent) === "flaky";
1092
1143
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
1093
- return /* @__PURE__ */ jsxs15(Fragment7, { children: [
1144
+ return /* @__PURE__ */ jsxs15(Fragment8, { children: [
1094
1145
  flaky ? /* @__PURE__ */ jsx23(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
1095
1146
  /* @__PURE__ */ jsx23(
1096
1147
  "span",
@@ -1425,9 +1476,9 @@ function ReportScenario({ scenario, hideTitle = false }) {
1425
1476
  }
1426
1477
 
1427
1478
  // src/components/ReportScenarioList.tsx
1428
- import { Fragment as Fragment8, jsx as jsx27 } from "react/jsx-runtime";
1479
+ import { Fragment as Fragment9, jsx as jsx27 } from "react/jsx-runtime";
1429
1480
  function ReportScenarioList({ feature }) {
1430
- return /* @__PURE__ */ jsx27(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx27(ReportScenario, { scenario }, scenario.id)) });
1481
+ return /* @__PURE__ */ jsx27(Fragment9, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx27(ReportScenario, { scenario }, scenario.id)) });
1431
1482
  }
1432
1483
 
1433
1484
  // src/components/ReportFeatureIntro.tsx
@@ -1465,7 +1516,7 @@ function featureKindLabel(kind) {
1465
1516
  }
1466
1517
 
1467
1518
  // src/components/ReportFeature.tsx
1468
- import { Fragment as Fragment9, jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
1519
+ import { Fragment as Fragment10, jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
1469
1520
  function ReportFeature({ feature }) {
1470
1521
  const titleId = `${feature.id}-title`;
1471
1522
  const bodyId = `${feature.id}-body`;
@@ -1525,14 +1576,14 @@ function ReportFeature({ feature }) {
1525
1576
  s.failed,
1526
1577
  " failed"
1527
1578
  ] }),
1528
- s.skipped > 0 ? /* @__PURE__ */ jsxs20(Fragment9, { children: [
1579
+ s.skipped > 0 ? /* @__PURE__ */ jsxs20(Fragment10, { children: [
1529
1580
  /* @__PURE__ */ jsx29("span", { "aria-hidden": true, children: "\xB7" }),
1530
1581
  /* @__PURE__ */ jsxs20("span", { children: [
1531
1582
  s.skipped,
1532
1583
  " skipped"
1533
1584
  ] })
1534
1585
  ] }) : null,
1535
- s.pending > 0 ? /* @__PURE__ */ jsxs20(Fragment9, { children: [
1586
+ s.pending > 0 ? /* @__PURE__ */ jsxs20(Fragment10, { children: [
1536
1587
  /* @__PURE__ */ jsx29("span", { "aria-hidden": true, children: "\xB7" }),
1537
1588
  /* @__PURE__ */ jsxs20("span", { children: [
1538
1589
  s.pending,
@@ -1779,9 +1830,9 @@ function ReportSchemaError({ error }) {
1779
1830
  }
1780
1831
 
1781
1832
  // src/components/ReportShell.tsx
1782
- import { Fragment as Fragment10, jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
1833
+ import { Fragment as Fragment11, jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
1783
1834
  function ReportTitleBlock({ title }) {
1784
- return /* @__PURE__ */ jsxs24(Fragment10, { children: [
1835
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1785
1836
  /* @__PURE__ */ jsx36("h1", { children: title ?? "Story Report" }),
1786
1837
  /* @__PURE__ */ jsx36(ReportSummary, {}),
1787
1838
  /* @__PURE__ */ jsx36(ReportMeta, {})
@@ -1875,7 +1926,7 @@ function Report(props) {
1875
1926
 
1876
1927
  // src/components/doc/MermaidView.tsx
1877
1928
  import { useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
1878
- import { Fragment as Fragment11, jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
1929
+ import { Fragment as Fragment12, jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
1879
1930
  function prefersDark(el) {
1880
1931
  const themed = el?.closest("[data-theme]");
1881
1932
  if (themed?.dataset.theme === "dark") return true;
@@ -1945,7 +1996,7 @@ function MermaidView({ entry, load }) {
1945
1996
  )
1946
1997
  ] });
1947
1998
  }
1948
- return /* @__PURE__ */ jsxs27(Fragment11, { children: [
1999
+ return /* @__PURE__ */ jsxs27(Fragment12, { children: [
1949
2000
  error ? /* @__PURE__ */ jsxs27(
1950
2001
  "p",
1951
2002
  {
@@ -2464,6 +2515,14 @@ var story_report_v1_default = {
2464
2515
  errorMessage: {
2465
2516
  type: "string"
2466
2517
  },
2518
+ expected: {
2519
+ type: "string",
2520
+ description: "Serialized expected value of the failed assertion. Present only when the host framework reports one."
2521
+ },
2522
+ actual: {
2523
+ type: "string",
2524
+ description: "Serialized actual (observed) value of the failed assertion. Present only when the host framework reports one."
2525
+ },
2467
2526
  mode: {
2468
2527
  $ref: "#/$defs/StepMode"
2469
2528
  },
@@ -2528,6 +2587,10 @@ var story_report_v1_default = {
2528
2587
  contentEncoding: {
2529
2588
  type: "string",
2530
2589
  enum: ["BASE64", "IDENTITY"]
2590
+ },
2591
+ external: {
2592
+ const: true,
2593
+ description: "body holds the file's path or URL (file missing or too large to embed)."
2531
2594
  }
2532
2595
  },
2533
2596
  required: ["name", "mediaType", "body", "contentEncoding"],