{"version":3,"file":"report.mjs","sources":["../../src/report.ts"],"sourcesContent":["import {\n  appendFileSync,\n  copyFileSync,\n  existsSync,\n  mkdirSync,\n  readdirSync,\n  rmSync,\n  unlinkSync,\n  writeFileSync,\n} from 'node:fs';\nimport * as path from 'node:path';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport { antiEscapeScriptTag, logMsg } from '@midscene/shared/utils';\nimport { getReportFileName } from './agent';\nimport {\n  extractAllDumpScriptsSync,\n  extractLastDumpScriptSync,\n  getBaseUrlFixScript,\n  streamDumpScriptsSync,\n  streamImageScriptsToFile,\n} from './dump/html-utils';\nimport {\n  normalizeScreenshotRef,\n  resolveScreenshotSource,\n} from './dump/screenshot-store';\nimport {\n  type ExecutionDump,\n  type IExecutionDump,\n  ReportActionDump,\n} from './types';\nimport type { ReportFileWithAttributes } from './types';\nimport { getReportTpl, getVersion, reportHTMLContent } from './utils';\n\n/**\n * Check if a report is in directory mode (html-and-external-assets).\n * Directory mode reports: {name}/index.html + {name}/screenshots/\n */\nexport function isDirectoryModeReport(reportFilePath: string): boolean {\n  const reportDir = path.dirname(reportFilePath);\n  return (\n    path.basename(reportFilePath) === 'index.html' &&\n    existsSync(path.join(reportDir, 'screenshots'))\n  );\n}\n\n/**\n * Deduplicate executions by stable id, keeping only the last occurrence.\n * Old-format executions without id are always preserved.\n */\nexport function dedupeExecutionsKeepLatest<T extends Pick<ExecutionDump, 'id'>>(\n  executions: T[],\n): T[] {\n  let noIdCounter = 0;\n  const deduped = new Map<string, T>();\n  for (const exec of executions) {\n    const key = exec.id || `__no_id_${noIdCounter++}`;\n    deduped.set(key, exec);\n  }\n  return Array.from(deduped.values());\n}\n/**\n * Peek at the first `sdkVersion` field embedded in a midscene_web_dump\n * script tag inside the given report file. Returns undefined if no\n * recognizable tag or sdkVersion is present.\n */\nfunction peekReportSdkVersion(reportFilePath: string): string | undefined {\n  try {\n    const dump = extractLastDumpScriptSync(reportFilePath);\n    if (!dump) return undefined;\n    const match = dump.match(/\"sdkVersion\"\\s*:\\s*\"([^\"]+)\"/);\n    return match?.[1];\n  } catch {\n    return undefined;\n  }\n}\n\nconst warnedMismatchedVersions = new Set<string>();\n\nexport class ReportMergingTool {\n  private reportInfos: ReportFileWithAttributes[] = [];\n\n  private createEmptyDumpString(groupName: string, groupDescription?: string) {\n    return new ReportActionDump({\n      sdkVersion: '',\n      groupName,\n      groupDescription,\n      modelBriefs: [],\n      executions: [],\n    }).serialize();\n  }\n\n  public append(reportInfo: ReportFileWithAttributes) {\n    if (reportInfo.reportFilePath) {\n      const sourceVersion = peekReportSdkVersion(reportInfo.reportFilePath);\n      const currentVersion = getVersion();\n      if (\n        sourceVersion &&\n        currentVersion &&\n        sourceVersion !== currentVersion &&\n        !warnedMismatchedVersions.has(sourceVersion)\n      ) {\n        warnedMismatchedVersions.add(sourceVersion);\n        logMsg(\n          `[@midscene/core] ReportMergingTool version mismatch: source report was written by @midscene/core@${sourceVersion} but the merger is @midscene/core@${currentVersion}. This commonly means @midscene/core and the device package (e.g. @midscene/android) resolve to different versions in node_modules. Merged output may silently drop intermediate steps. Align the versions and reinstall (rm -rf node_modules package-lock.json && npm install).`,\n        );\n      }\n    }\n    this.reportInfos.push(reportInfo);\n  }\n  public clear() {\n    this.reportInfos = [];\n  }\n\n  /**\n   * Merge multiple dump script contents (from the same source report)\n   * into a single serialized ReportActionDump string.\n   * If there's only one dump, return it as-is. If multiple, merge\n   * all executions into the first dump's group structure.\n   */\n  private mergeDumpScripts(contents: string[]): string {\n    const unescaped = contents\n      .map((c) => antiEscapeScriptTag(c))\n      .filter((c) => c.length > 0);\n    if (unescaped.length === 0) return '';\n    if (unescaped.length === 1) return unescaped[0];\n\n    // Parse all dumps and collect executions, deduplicating by id (keep last).\n    // Only executions with a stable id are deduped; old-format entries without\n    // id are always kept (they may be distinct despite sharing the same name).\n    const base = ReportActionDump.fromSerializedString(unescaped[0]);\n    const allExecutions = [...base.executions];\n    for (let i = 1; i < unescaped.length; i++) {\n      const other = ReportActionDump.fromSerializedString(unescaped[i]);\n      allExecutions.push(...other.executions);\n    }\n    base.executions = dedupeExecutionsKeepLatest(allExecutions);\n    return base.serialize();\n  }\n\n  public mergeReports(\n    reportFileName: 'AUTO' | string = 'AUTO',\n    opts?: {\n      rmOriginalReports?: boolean;\n      overwrite?: boolean;\n      outputDir?: string;\n    },\n  ): string | null {\n    const {\n      rmOriginalReports = false,\n      overwrite = false,\n      outputDir,\n    } = opts ?? {};\n\n    if (this.reportInfos.length === 0) {\n      logMsg('No reports to merge');\n      return null;\n    }\n\n    const targetDir = outputDir\n      ? path.resolve(outputDir)\n      : getMidsceneRunSubDir('report');\n    if (outputDir) {\n      mkdirSync(targetDir, { recursive: true });\n    }\n\n    // Check if any source report is directory mode\n    const hasDirectoryModeReport = this.reportInfos.some((info) => {\n      const reportFilePath = info.reportFilePath;\n      return Boolean(reportFilePath && isDirectoryModeReport(reportFilePath));\n    });\n\n    const resolvedName =\n      reportFileName === 'AUTO'\n        ? getReportFileName('merged-report')\n        : reportFileName;\n\n    // Directory mode: output as {name}/index.html to keep relative paths working\n    // Inline mode: output as {name}.html (single file)\n    const outputFilePath = hasDirectoryModeReport\n      ? path.resolve(targetDir, resolvedName, 'index.html')\n      : path.resolve(targetDir, `${resolvedName}.html`);\n\n    if (reportFileName !== 'AUTO' && existsSync(outputFilePath)) {\n      if (!overwrite) {\n        throw new Error(\n          `Report file already exists: ${outputFilePath}\\nSet overwrite to true to overwrite this file.`,\n        );\n      }\n      if (hasDirectoryModeReport) {\n        rmSync(path.dirname(outputFilePath), { recursive: true, force: true });\n      } else {\n        unlinkSync(outputFilePath);\n      }\n    }\n\n    if (hasDirectoryModeReport) {\n      mkdirSync(path.dirname(outputFilePath), { recursive: true });\n    }\n\n    logMsg(\n      `Start merging ${this.reportInfos.length} reports...\\nCreating template file...`,\n    );\n\n    try {\n      // Write template without closing </html> tag so we can append\n      // dump scripts before it. The closing tag is added at the end.\n      const htmlEndTag = '</html>';\n      const tpl = getReportTpl();\n      const htmlEndIdx = tpl.lastIndexOf(htmlEndTag);\n      const tplWithoutClose =\n        htmlEndIdx !== -1 ? tpl.slice(0, htmlEndIdx) : tpl;\n      appendFileSync(outputFilePath, tplWithoutClose);\n\n      // For directory-mode output, inject base URL fix script\n      if (hasDirectoryModeReport) {\n        appendFileSync(outputFilePath, getBaseUrlFixScript());\n      }\n\n      // Process all reports one by one\n      for (let i = 0; i < this.reportInfos.length; i++) {\n        const reportInfo = this.reportInfos[i];\n        logMsg(`Processing report ${i + 1}/${this.reportInfos.length}`);\n\n        const { reportAttributes } = reportInfo;\n        let dumpString = this.createEmptyDumpString(\n          reportAttributes.testTitle,\n          reportAttributes.testDescription,\n        );\n        let mergedGroupId = `merged-group-${i}`;\n\n        if (reportInfo.reportFilePath) {\n          if (isDirectoryModeReport(reportInfo.reportFilePath)) {\n            // Directory mode: copy external screenshot files\n            const reportDir = path.dirname(reportInfo.reportFilePath);\n            const screenshotsDir = path.join(reportDir, 'screenshots');\n            const mergedScreenshotsDir = path.join(\n              path.dirname(outputFilePath),\n              'screenshots',\n            );\n            mkdirSync(mergedScreenshotsDir, { recursive: true });\n            for (const file of readdirSync(screenshotsDir)) {\n              const src = path.join(screenshotsDir, file);\n              const dest = path.join(mergedScreenshotsDir, file);\n              copyFileSync(src, dest);\n            }\n          } else {\n            // Inline mode: stream image scripts to output file\n            streamImageScriptsToFile(reportInfo.reportFilePath, outputFilePath);\n          }\n\n          // Extract all dump scripts from the source report.\n          // After the per-execution append refactor, a single source report\n          // may contain multiple <script type=\"midscene_web_dump\"> tags\n          // (one per execution). We merge them into a single ReportActionDump.\n          // Filter by data-group-id to exclude false matches from the template's\n          // bundled JS code, which also references the midscene_web_dump type string.\n          const allDumps = extractAllDumpScriptsSync(\n            reportInfo.reportFilePath,\n          ).filter((d) => d.openTag.includes('data-group-id'));\n          const groupIdMatch = allDumps[0]?.openTag.match(\n            /data-group-id=\"([^\"]+)\"/,\n          );\n          if (groupIdMatch) {\n            mergedGroupId = decodeURIComponent(groupIdMatch[1]);\n          }\n          const extractedDumpString =\n            allDumps.length > 0\n              ? this.mergeDumpScripts(allDumps.map((d) => d.content))\n              : extractLastDumpScriptSync(reportInfo.reportFilePath);\n          if (extractedDumpString) {\n            dumpString = extractedDumpString;\n          }\n        }\n\n        const reportHtmlStr = `${reportHTMLContent(\n          {\n            dumpString,\n            attributes: {\n              'data-group-id': mergedGroupId,\n              playwright_test_duration: reportAttributes.testDuration,\n              playwright_test_status: reportAttributes.testStatus,\n              playwright_test_title: reportAttributes.testTitle,\n              playwright_test_id: reportAttributes.testId,\n              playwright_test_description: reportAttributes.testDescription,\n              is_merged: true,\n            },\n          },\n          undefined,\n          undefined,\n          false,\n        )}\\n`;\n\n        appendFileSync(outputFilePath, reportHtmlStr);\n      }\n\n      // Close the HTML document\n      appendFileSync(outputFilePath, `${htmlEndTag}\\n`);\n\n      logMsg(`Successfully merged new report: ${outputFilePath}`);\n\n      // Remove original reports if needed\n      if (rmOriginalReports) {\n        for (const info of this.reportInfos) {\n          if (!info.reportFilePath) continue;\n          try {\n            if (isDirectoryModeReport(info.reportFilePath)) {\n              // Directory mode: remove the entire report directory\n              const reportDir = path.dirname(info.reportFilePath);\n              rmSync(reportDir, { recursive: true, force: true });\n            } else {\n              unlinkSync(info.reportFilePath);\n            }\n          } catch (error) {\n            logMsg(`Error deleting report ${info.reportFilePath}: ${error}`);\n          }\n        }\n        logMsg(`Removed ${this.reportInfos.length} original reports`);\n      }\n      return outputFilePath;\n    } catch (error) {\n      logMsg(`Error in mergeReports: ${error}`);\n      throw error;\n    }\n  }\n}\n\nexport interface SplitReportHtmlOptions {\n  htmlPath: string;\n  outputDir: string;\n}\n\nexport interface SplitReportHtmlResult {\n  executionJsonFiles: string[];\n  screenshotFiles: string[];\n}\n\nexport interface CollectedReportExecutions {\n  baseDump: ReportActionDump;\n  executions: IExecutionDump[];\n}\n\n/**\n * Collect executions from a report HTML, deduplicating by stable id while\n * keeping only the latest occurrence. Old-format executions without id are\n * always preserved.\n */\nexport function collectDedupedExecutions(\n  htmlPath: string,\n): CollectedReportExecutions {\n  let baseDump: ReportActionDump | null = null;\n  let executionSerial = 0;\n  const latestSerialByExecutionId = new Map<string, number>();\n\n  streamDumpScriptsSync(htmlPath, (dumpScript) => {\n    if (!dumpScript.openTag.includes('data-group-id')) {\n      return false;\n    }\n    const groupedDump = ReportActionDump.fromSerializedString(\n      antiEscapeScriptTag(dumpScript.content),\n    );\n    for (const execution of groupedDump.executions) {\n      executionSerial += 1;\n      if (execution.id) {\n        latestSerialByExecutionId.set(execution.id, executionSerial);\n      }\n    }\n    return false;\n  });\n\n  const executions: IExecutionDump[] = [];\n  executionSerial = 0;\n  streamDumpScriptsSync(htmlPath, (dumpScript) => {\n    if (!dumpScript.openTag.includes('data-group-id')) {\n      return false;\n    }\n\n    const groupedDump = ReportActionDump.fromSerializedString(\n      antiEscapeScriptTag(dumpScript.content),\n    );\n    if (!baseDump) {\n      baseDump = groupedDump;\n    }\n\n    for (const execution of groupedDump.executions) {\n      executionSerial += 1;\n      if (\n        execution.id &&\n        latestSerialByExecutionId.get(execution.id) !== executionSerial\n      ) {\n        continue;\n      }\n      executions.push(execution);\n    }\n\n    return false;\n  });\n\n  if (!baseDump) {\n    throw new Error(`No report dump scripts found in ${htmlPath}`);\n  }\n\n  return {\n    baseDump,\n    executions,\n  };\n}\n\nfunction extensionByMimeType(mimeType: string): 'png' | 'jpeg' {\n  if (mimeType === 'image/png') return 'png';\n  if (mimeType === 'image/jpeg') return 'jpeg';\n  throw new Error(`Unsupported screenshot mime type: ${mimeType}`);\n}\n\nfunction externalizeScreenshotsInExecution(\n  execution: IExecutionDump,\n  opts: {\n    htmlPath: string;\n    screenshotsDir: string;\n    writtenFiles: Set<string>;\n  },\n): void {\n  const visit = (node: unknown): void => {\n    if (Array.isArray(node)) {\n      for (const item of node) {\n        visit(item);\n      }\n      return;\n    }\n\n    if (typeof node !== 'object' || node === null) return;\n\n    const ref = normalizeScreenshotRef(node);\n    if (ref) {\n      const ext = extensionByMimeType(ref.mimeType);\n      const fileName = `${ref.id}.${ext}`;\n      const relativePath = `./screenshots/${fileName}`;\n      const absolutePath = path.join(opts.screenshotsDir, fileName);\n\n      if (!opts.writtenFiles.has(fileName)) {\n        const resolved = resolveScreenshotSource(ref, {\n          reportPath: opts.htmlPath,\n        });\n        if (resolved.type === 'data-uri') {\n          const rawBase64 = resolved.dataUri.replace(\n            /^data:image\\/[a-zA-Z+]+;base64,/,\n            '',\n          );\n          writeFileSync(absolutePath, Buffer.from(rawBase64, 'base64'));\n        } else {\n          copyFileSync(resolved.filePath, absolutePath);\n        }\n        opts.writtenFiles.add(fileName);\n      }\n\n      ref.storage = 'file';\n      ref.path = relativePath;\n      return;\n    }\n\n    for (const value of Object.values(node)) {\n      visit(value);\n    }\n  };\n\n  visit(execution);\n}\n\n/**\n * Reverse parse a Midscene report HTML into per-execution JSON files and\n * externalized screenshots.\n */\nexport function splitReportHtmlByExecution(\n  options: SplitReportHtmlOptions,\n): SplitReportHtmlResult {\n  const { htmlPath, outputDir } = options;\n  const screenshotsDir = path.join(outputDir, 'screenshots');\n\n  mkdirSync(outputDir, { recursive: true });\n  mkdirSync(screenshotsDir, { recursive: true });\n\n  const executionJsonFiles: string[] = [];\n  const writtenScreenshotFiles = new Set<string>();\n  const { baseDump, executions } = collectDedupedExecutions(htmlPath);\n\n  let fileIndex = 0;\n  for (const execution of executions) {\n    fileIndex += 1;\n    externalizeScreenshotsInExecution(execution, {\n      htmlPath,\n      screenshotsDir,\n      writtenFiles: writtenScreenshotFiles,\n    });\n    const singleExecutionDump = new ReportActionDump({\n      sdkVersion: baseDump.sdkVersion,\n      groupName: baseDump.groupName,\n      groupDescription: baseDump.groupDescription,\n      modelBriefs: baseDump.modelBriefs,\n      deviceType: baseDump.deviceType,\n      executions: [execution],\n    });\n\n    const jsonFilePath = path.join(outputDir, `${fileIndex}.execution.json`);\n    writeFileSync(jsonFilePath, singleExecutionDump.serialize(2), 'utf-8');\n    executionJsonFiles.push(jsonFilePath);\n  }\n\n  return {\n    executionJsonFiles,\n    screenshotFiles: Array.from(writtenScreenshotFiles)\n      .sort()\n      .map((fileName) => path.join(screenshotsDir, fileName)),\n  };\n}\n"],"names":["isDirectoryModeReport","reportFilePath","reportDir","path","existsSync","dedupeExecutionsKeepLatest","executions","noIdCounter","deduped","Map","exec","key","Array","peekReportSdkVersion","dump","extractLastDumpScriptSync","match","warnedMismatchedVersions","Set","ReportMergingTool","groupName","groupDescription","ReportActionDump","reportInfo","sourceVersion","currentVersion","getVersion","logMsg","contents","unescaped","c","antiEscapeScriptTag","base","allExecutions","i","other","reportFileName","opts","rmOriginalReports","overwrite","outputDir","targetDir","getMidsceneRunSubDir","mkdirSync","hasDirectoryModeReport","info","Boolean","resolvedName","getReportFileName","outputFilePath","Error","rmSync","unlinkSync","htmlEndTag","tpl","getReportTpl","htmlEndIdx","tplWithoutClose","appendFileSync","getBaseUrlFixScript","reportAttributes","dumpString","mergedGroupId","screenshotsDir","mergedScreenshotsDir","file","readdirSync","src","dest","copyFileSync","streamImageScriptsToFile","allDumps","extractAllDumpScriptsSync","d","groupIdMatch","decodeURIComponent","extractedDumpString","reportHtmlStr","reportHTMLContent","undefined","error","collectDedupedExecutions","htmlPath","baseDump","executionSerial","latestSerialByExecutionId","streamDumpScriptsSync","dumpScript","groupedDump","execution","extensionByMimeType","mimeType","externalizeScreenshotsInExecution","visit","node","item","ref","normalizeScreenshotRef","ext","fileName","relativePath","absolutePath","resolved","resolveScreenshotSource","rawBase64","writeFileSync","Buffer","value","Object","splitReportHtmlByExecution","options","executionJsonFiles","writtenScreenshotFiles","fileIndex","singleExecutionDump","jsonFilePath"],"mappings":"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"}