executable-stories-formatters 0.7.9 → 0.7.11

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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
2
  import "fs";
3
- import * as path7 from "path";
3
+ import * as path8 from "path";
4
4
  import * as fsPromises from "fs/promises";
5
5
 
6
6
  // src/converters/acl/status.ts
@@ -653,6 +653,10 @@ ${doc.markdown}`,
653
653
  }
654
654
  };
655
655
 
656
+ // src/formatters/html/renderers/index.ts
657
+ import * as fs2 from "fs";
658
+ import * as path2 from "path";
659
+
656
660
  // src/formatters/html/template.ts
657
661
  var JS_THEME = `
658
662
  // Theme management
@@ -12963,7 +12967,9 @@ function renderDocMermaid(entry, deps) {
12963
12967
  }
12964
12968
  function renderDocScreenshot(entry, deps) {
12965
12969
  const alt = entry.alt ?? "Screenshot";
12966
- const src = entry.path;
12970
+ const embedEnabled = deps.embedScreenshots ?? true;
12971
+ const isRemote = /^(?:https?:|data:)/i.test(entry.path);
12972
+ const src = embedEnabled && !isRemote && deps.readScreenshot ? deps.readScreenshot(entry.path) ?? entry.path : entry.path;
12967
12973
  return `<div class="doc-screenshot">
12968
12974
  <img src="${deps.escapeHtml(src)}" alt="${deps.escapeHtml(alt)}" class="doc-screenshot-img" />
12969
12975
  ${entry.alt ? `<div class="doc-screenshot-caption">${deps.escapeHtml(entry.alt)}</div>` : ""}
@@ -13550,6 +13556,28 @@ function renderToc(args, deps) {
13550
13556
  }
13551
13557
 
13552
13558
  // src/formatters/html/renderers/index.ts
13559
+ var SCREENSHOT_MIME_BY_EXT = {
13560
+ png: "image/png",
13561
+ jpg: "image/jpeg",
13562
+ jpeg: "image/jpeg",
13563
+ gif: "image/gif",
13564
+ webp: "image/webp",
13565
+ svg: "image/svg+xml",
13566
+ avif: "image/avif",
13567
+ bmp: "image/bmp"
13568
+ };
13569
+ function readScreenshotAsDataUri(filePath) {
13570
+ try {
13571
+ const ext = path2.extname(filePath).slice(1).toLowerCase();
13572
+ const mime = SCREENSHOT_MIME_BY_EXT[ext];
13573
+ if (!mime) return void 0;
13574
+ if (!fs2.existsSync(filePath)) return void 0;
13575
+ const buf = fs2.readFileSync(filePath);
13576
+ return `data:${mime};base64,${buf.toString("base64")}`;
13577
+ } catch {
13578
+ return void 0;
13579
+ }
13580
+ }
13553
13581
  function normalizeOptions(options = {}) {
13554
13582
  return {
13555
13583
  title: options.title ?? "Test Results",
@@ -13573,7 +13601,9 @@ function createHtmlFormatter(options = {}) {
13573
13601
  escapeHtml,
13574
13602
  syntaxHighlighting: opts.syntaxHighlighting,
13575
13603
  markdownEnabled: opts.markdownEnabled,
13576
- mermaidEnabled: opts.mermaidEnabled
13604
+ mermaidEnabled: opts.mermaidEnabled,
13605
+ embedScreenshots: opts.embedScreenshots,
13606
+ readScreenshot: (filePath) => readScreenshotAsDataUri(filePath)
13577
13607
  };
13578
13608
  const renderDocs = (docs, containerClass) => {
13579
13609
  if (!docs || docs.length === 0) return "";
@@ -15002,8 +15032,8 @@ function extractDocAttachments(step) {
15002
15032
  }
15003
15033
  return attachments;
15004
15034
  }
15005
- function guessMediaType(path8) {
15006
- const lower = path8.toLowerCase();
15035
+ function guessMediaType(path9) {
15036
+ const lower = path9.toLowerCase();
15007
15037
  if (lower.endsWith(".png")) return "image/png";
15008
15038
  if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
15009
15039
  if (lower.endsWith(".gif")) return "image/gif";
@@ -16047,8 +16077,8 @@ function selectTestCases(args, deps) {
16047
16077
  }
16048
16078
 
16049
16079
  // src/bundler/bundle-assets.ts
16050
- import * as fs3 from "fs";
16051
- import * as path3 from "path";
16080
+ import * as fs4 from "fs";
16081
+ import * as path4 from "path";
16052
16082
 
16053
16083
  // src/bundler/scan-html-assets.ts
16054
16084
  function scanHtmlAssets(html) {
@@ -16078,21 +16108,21 @@ function isLocalAssetRef(ref) {
16078
16108
  }
16079
16109
 
16080
16110
  // src/bundler/copy-asset.ts
16081
- import * as fs2 from "fs";
16082
- import * as path2 from "path";
16111
+ import * as fs3 from "fs";
16112
+ import * as path3 from "path";
16083
16113
  import * as crypto from "crypto";
16084
16114
  function copyAsset(sourcePath, assetsDir) {
16085
- if (!fs2.existsSync(assetsDir)) {
16086
- fs2.mkdirSync(assetsDir, { recursive: true });
16115
+ if (!fs3.existsSync(assetsDir)) {
16116
+ fs3.mkdirSync(assetsDir, { recursive: true });
16087
16117
  }
16088
- const content = fs2.readFileSync(sourcePath);
16118
+ const content = fs3.readFileSync(sourcePath);
16089
16119
  const hash = crypto.createHash("sha256").update(content).digest("hex").slice(0, 8);
16090
- const ext = path2.extname(sourcePath);
16091
- const baseName = sanitize(path2.basename(sourcePath, ext));
16120
+ const ext = path3.extname(sourcePath);
16121
+ const baseName = sanitize(path3.basename(sourcePath, ext));
16092
16122
  const destName = `${baseName}-${hash}${ext}`;
16093
- const destPath = path2.join(assetsDir, destName);
16094
- if (!fs2.existsSync(destPath)) {
16095
- fs2.copyFileSync(sourcePath, destPath);
16123
+ const destPath = path3.join(assetsDir, destName);
16124
+ if (!fs3.existsSync(destPath)) {
16125
+ fs3.copyFileSync(sourcePath, destPath);
16096
16126
  }
16097
16127
  return `assets/${destName}`;
16098
16128
  }
@@ -16102,15 +16132,15 @@ function sanitize(name) {
16102
16132
 
16103
16133
  // src/bundler/bundle-assets.ts
16104
16134
  function bundleAssets(htmlPath, options = {}) {
16105
- const htmlDir = path3.dirname(htmlPath);
16106
- const assetsDir = path3.join(htmlDir, "assets");
16107
- let html = fs3.readFileSync(htmlPath, "utf8");
16135
+ const htmlDir = path4.dirname(htmlPath);
16136
+ const assetsDir = path4.join(htmlDir, "assets");
16137
+ let html = fs4.readFileSync(htmlPath, "utf8");
16108
16138
  const refs = scanHtmlAssets(html);
16109
16139
  let copiedCount = 0;
16110
16140
  const missing = [];
16111
16141
  for (const ref of refs) {
16112
- const absolutePath = path3.resolve(htmlDir, ref);
16113
- if (!fs3.existsSync(absolutePath)) {
16142
+ const absolutePath = path4.resolve(htmlDir, ref);
16143
+ if (!fs4.existsSync(absolutePath)) {
16114
16144
  missing.push(ref);
16115
16145
  continue;
16116
16146
  }
@@ -16123,7 +16153,7 @@ function bundleAssets(htmlPath, options = {}) {
16123
16153
  `Missing asset${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`
16124
16154
  );
16125
16155
  }
16126
- fs3.writeFileSync(htmlPath, html, "utf8");
16156
+ fs4.writeFileSync(htmlPath, html, "utf8");
16127
16157
  return {
16128
16158
  copiedCount,
16129
16159
  missingCount: missing.length,
@@ -16606,15 +16636,15 @@ function groupBy7(items, keyFn) {
16606
16636
  }
16607
16637
 
16608
16638
  // src/formatters/astro-assets.ts
16609
- import * as fs4 from "fs";
16610
- import * as path4 from "path";
16639
+ import * as fs5 from "fs";
16640
+ import * as path5 from "path";
16611
16641
  var SKIP_PREFIXES = ["http://", "https://", "data:", "#"];
16612
16642
  function isLocalPath(src) {
16613
16643
  const trimmed = src.trim();
16614
16644
  if (SKIP_PREFIXES.some((prefix) => trimmed.startsWith(prefix))) {
16615
16645
  return false;
16616
16646
  }
16617
- return !path4.posix.isAbsolute(trimmed) && !path4.win32.isAbsolute(trimmed);
16647
+ return !path5.posix.isAbsolute(trimmed) && !path5.win32.isAbsolute(trimmed);
16618
16648
  }
16619
16649
  function stripCodeContent(markdown) {
16620
16650
  let result = markdown.replace(/^[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?^[ \t]*\1\s*$/gm, "");
@@ -16708,8 +16738,8 @@ function copyMarkdownAssets(options) {
16708
16738
  const pathMap = /* @__PURE__ */ new Map();
16709
16739
  const missing = [];
16710
16740
  for (const ref of refs) {
16711
- const absPath = path4.resolve(markdownDir, ref);
16712
- if (!fs4.existsSync(absPath)) {
16741
+ const absPath = path5.resolve(markdownDir, ref);
16742
+ if (!fs5.existsSync(absPath)) {
16713
16743
  if (!allowMissing) {
16714
16744
  throw new Error(`Asset not found: ${absPath}`);
16715
16745
  }
@@ -17725,27 +17755,27 @@ function pickleStepArgumentToDocs(ps) {
17725
17755
  }
17726
17756
 
17727
17757
  // src/utils/git-info.ts
17728
- import * as fs5 from "fs";
17729
- import * as path5 from "path";
17758
+ import * as fs6 from "fs";
17759
+ import * as path6 from "path";
17730
17760
  function readGitSha(cwd = process.cwd()) {
17731
17761
  const envSha = process.env.GITHUB_SHA || process.env.GIT_COMMIT || process.env.CI_COMMIT_SHA;
17732
17762
  if (envSha) return envSha;
17733
17763
  const gitDir = findGitDir(cwd);
17734
17764
  if (!gitDir) return void 0;
17735
17765
  try {
17736
- const headPath = path5.join(gitDir, "HEAD");
17737
- const head = fs5.readFileSync(headPath, "utf8").trim();
17766
+ const headPath = path6.join(gitDir, "HEAD");
17767
+ const head = fs6.readFileSync(headPath, "utf8").trim();
17738
17768
  if (!head.startsWith("ref:")) {
17739
17769
  return head;
17740
17770
  }
17741
17771
  const refPath = head.replace("ref:", "").trim();
17742
- const refFile = path5.join(gitDir, refPath);
17743
- if (fs5.existsSync(refFile)) {
17744
- return fs5.readFileSync(refFile, "utf8").trim();
17772
+ const refFile = path6.join(gitDir, refPath);
17773
+ if (fs6.existsSync(refFile)) {
17774
+ return fs6.readFileSync(refFile, "utf8").trim();
17745
17775
  }
17746
- const packedRefs = path5.join(gitDir, "packed-refs");
17747
- if (fs5.existsSync(packedRefs)) {
17748
- const content = fs5.readFileSync(packedRefs, "utf8");
17776
+ const packedRefs = path6.join(gitDir, "packed-refs");
17777
+ if (fs6.existsSync(packedRefs)) {
17778
+ const content = fs6.readFileSync(packedRefs, "utf8");
17749
17779
  for (const line of content.split("\n")) {
17750
17780
  if (!line || line.startsWith("#") || line.startsWith("^")) continue;
17751
17781
  const [sha, ref] = line.split(" ");
@@ -17760,19 +17790,19 @@ function readGitSha(cwd = process.cwd()) {
17760
17790
  function findGitDir(start) {
17761
17791
  let current = start;
17762
17792
  while (true) {
17763
- const candidate = path5.join(current, ".git");
17764
- if (fs5.existsSync(candidate)) {
17765
- const stat = fs5.statSync(candidate);
17793
+ const candidate = path6.join(current, ".git");
17794
+ if (fs6.existsSync(candidate)) {
17795
+ const stat = fs6.statSync(candidate);
17766
17796
  if (stat.isFile()) {
17767
- const content = fs5.readFileSync(candidate, "utf8").trim();
17797
+ const content = fs6.readFileSync(candidate, "utf8").trim();
17768
17798
  const match = content.match(/^gitdir: (.+)$/);
17769
17799
  if (match) {
17770
- return path5.resolve(current, match[1]);
17800
+ return path6.resolve(current, match[1]);
17771
17801
  }
17772
17802
  }
17773
17803
  return candidate;
17774
17804
  }
17775
- const parent = path5.dirname(current);
17805
+ const parent = path6.dirname(current);
17776
17806
  if (parent === current) return void 0;
17777
17807
  current = parent;
17778
17808
  }
@@ -17783,8 +17813,8 @@ function readBranchName(cwd = process.cwd()) {
17783
17813
  const gitDir = findGitDir(cwd);
17784
17814
  if (!gitDir) return void 0;
17785
17815
  try {
17786
- const headPath = path5.join(gitDir, "HEAD");
17787
- const head = fs5.readFileSync(headPath, "utf8").trim();
17816
+ const headPath = path6.join(gitDir, "HEAD");
17817
+ const head = fs6.readFileSync(headPath, "utf8").trim();
17788
17818
  if (head.startsWith("ref:")) {
17789
17819
  const refPath = head.replace("ref:", "").trim();
17790
17820
  const match = refPath.match(/^refs\/heads\/(.+)$/);
@@ -17821,8 +17851,8 @@ function nanosecondsToMs(ns) {
17821
17851
  }
17822
17852
 
17823
17853
  // src/utils/metadata.ts
17824
- import * as fs6 from "fs";
17825
- import * as path6 from "path";
17854
+ import * as fs7 from "fs";
17855
+ import * as path7 from "path";
17826
17856
  var versionCache = /* @__PURE__ */ new Map();
17827
17857
  function readPackageVersion(root) {
17828
17858
  if (versionCache.has(root)) {
@@ -17833,18 +17863,18 @@ function readPackageVersion(root) {
17833
17863
  return version;
17834
17864
  }
17835
17865
  function findPackageVersion(startDir) {
17836
- let current = path6.resolve(startDir);
17866
+ let current = path7.resolve(startDir);
17837
17867
  while (true) {
17838
- const pkgPath = path6.join(current, "package.json");
17868
+ const pkgPath = path7.join(current, "package.json");
17839
17869
  try {
17840
- if (fs6.existsSync(pkgPath)) {
17841
- const raw = fs6.readFileSync(pkgPath, "utf8");
17870
+ if (fs7.existsSync(pkgPath)) {
17871
+ const raw = fs7.readFileSync(pkgPath, "utf8");
17842
17872
  const parsed = JSON.parse(raw);
17843
17873
  return parsed.version;
17844
17874
  }
17845
17875
  } catch {
17846
17876
  }
17847
- const parent = path6.dirname(current);
17877
+ const parent = path7.dirname(current);
17848
17878
  if (parent === current) {
17849
17879
  return void 0;
17850
17880
  }
@@ -18834,11 +18864,11 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
18834
18864
  const ext = FORMAT_EXTENSIONS[format];
18835
18865
  const effectiveName = outputName + (outputNameSuffix ?? "");
18836
18866
  if (mode === "aggregated") {
18837
- return toPosix(path7.join(baseOutputDir, `${effectiveName}${ext}`));
18867
+ return toPosix(path8.join(baseOutputDir, `${effectiveName}${ext}`));
18838
18868
  }
18839
18869
  const normalizedSource = toPosix(sourceFile);
18840
- const dirOfSource = path7.posix.dirname(normalizedSource);
18841
- let baseName = path7.posix.basename(normalizedSource);
18870
+ const dirOfSource = path8.posix.dirname(normalizedSource);
18871
+ let baseName = path8.posix.basename(normalizedSource);
18842
18872
  for (const testExt of TEST_EXTENSIONS) {
18843
18873
  if (baseName.endsWith(testExt)) {
18844
18874
  baseName = baseName.slice(0, -testExt.length);
@@ -18847,9 +18877,9 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
18847
18877
  }
18848
18878
  const fileName = `${baseName}.${effectiveName}${ext}`;
18849
18879
  if (colocatedStyle === "adjacent") {
18850
- return toPosix(path7.posix.join(dirOfSource, fileName));
18880
+ return toPosix(path8.posix.join(dirOfSource, fileName));
18851
18881
  }
18852
- return toPosix(path7.posix.join(baseOutputDir, dirOfSource, fileName));
18882
+ return toPosix(path8.posix.join(baseOutputDir, dirOfSource, fileName));
18853
18883
  }
18854
18884
  function groupTestCasesByOutput(testCases, format, options, logger, outputNameSuffix) {
18855
18885
  const groups = /* @__PURE__ */ new Map();
@@ -19047,8 +19077,8 @@ var ReportGenerator = class {
19047
19077
  if (astroPaths) {
19048
19078
  for (const mdPath of astroPaths) {
19049
19079
  const content = await fsPromises.readFile(mdPath, "utf8");
19050
- const mdDir = path7.dirname(mdPath);
19051
- const assetsDir = path7.resolve(this.options.astro.assetsDir);
19080
+ const mdDir = path8.dirname(mdPath);
19081
+ const assetsDir = path8.resolve(this.options.astro.assetsDir);
19052
19082
  const result = copyMarkdownAssets({
19053
19083
  markdown: content,
19054
19084
  markdownDir: mdDir,
@@ -19079,9 +19109,9 @@ var ReportGenerator = class {
19079
19109
  if (groups.size === 0 && this.options.output.mode === "aggregated") {
19080
19110
  const ext = FORMAT_EXTENSIONS[format];
19081
19111
  const effectiveName = this.options.outputName + (outputNameSuffix ?? "");
19082
- const outputPath = toPosix(path7.join(this.options.outputDir, `${effectiveName}${ext}`));
19112
+ const outputPath = toPosix(path8.join(this.options.outputDir, `${effectiveName}${ext}`));
19083
19113
  const content = await this.formatContent(run, format);
19084
- const dir = path7.dirname(outputPath);
19114
+ const dir = path8.dirname(outputPath);
19085
19115
  await fsPromises.mkdir(dir, { recursive: true });
19086
19116
  await this.deps.writeFile(outputPath, content);
19087
19117
  return [outputPath];
@@ -19093,7 +19123,7 @@ var ReportGenerator = class {
19093
19123
  testCases
19094
19124
  };
19095
19125
  const content = await this.formatContent(groupRun, format);
19096
- const dir = path7.dirname(outputPath);
19126
+ const dir = path8.dirname(outputPath);
19097
19127
  await fsPromises.mkdir(dir, { recursive: true });
19098
19128
  await this.deps.writeFile(outputPath, content);
19099
19129
  writtenPaths.push(outputPath);
@@ -19216,7 +19246,7 @@ async function generateRunComparison(args) {
19216
19246
  await fsPromises.mkdir(outputDir, { recursive: true });
19217
19247
  for (const format of args.formats) {
19218
19248
  const ext = format === "html" ? ".html" : ".md";
19219
- const outputPath = toPosix(path7.join(outputDir, `${outputName}${ext}`));
19249
+ const outputPath = toPosix(path8.join(outputDir, `${outputName}${ext}`));
19220
19250
  const content = format === "html" ? new RunDiffHtmlFormatter({ title: args.title }).format(diff) : new RunDiffMarkdownFormatter({ title: args.title }).format(diff);
19221
19251
  await fsPromises.writeFile(outputPath, content, "utf8");
19222
19252
  files.push(outputPath);