@midscene/core 1.12.5 → 1.12.6-beta-20260909034232.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.
Files changed (43) hide show
  1. package/dist/es/agent/agent.mjs +42 -1
  2. package/dist/es/agent/agent.mjs.map +1 -1
  3. package/dist/es/agent/report-file-name.mjs +12 -0
  4. package/dist/es/agent/report-file-name.mjs.map +1 -0
  5. package/dist/es/agent/utils.mjs +4 -10
  6. package/dist/es/agent/utils.mjs.map +1 -1
  7. package/dist/es/ai-model/service-caller/index.mjs +21 -36
  8. package/dist/es/ai-model/service-caller/index.mjs.map +1 -1
  9. package/dist/es/index.mjs +3 -2
  10. package/dist/es/index.mjs.map +1 -1
  11. package/dist/es/report-html-template.mjs +1 -1
  12. package/dist/es/report.mjs +181 -4
  13. package/dist/es/report.mjs.map +1 -1
  14. package/dist/es/test-run-report.mjs +4 -0
  15. package/dist/es/test-run-report.mjs.map +1 -0
  16. package/dist/es/utils.mjs +1 -1
  17. package/dist/es/yaml/player.mjs +6 -6
  18. package/dist/es/yaml/player.mjs.map +1 -1
  19. package/dist/lib/agent/agent.js +41 -0
  20. package/dist/lib/agent/agent.js.map +1 -1
  21. package/dist/lib/agent/report-file-name.js +56 -0
  22. package/dist/lib/agent/report-file-name.js.map +1 -0
  23. package/dist/lib/agent/utils.js +3 -19
  24. package/dist/lib/agent/utils.js.map +1 -1
  25. package/dist/lib/ai-model/service-caller/index.js +21 -36
  26. package/dist/lib/ai-model/service-caller/index.js.map +1 -1
  27. package/dist/lib/index.js +10 -3
  28. package/dist/lib/index.js.map +1 -1
  29. package/dist/lib/report-html-template.js +1 -1
  30. package/dist/lib/report.js +183 -3
  31. package/dist/lib/report.js.map +1 -1
  32. package/dist/lib/test-run-report.js +38 -0
  33. package/dist/lib/test-run-report.js.map +1 -0
  34. package/dist/lib/utils.js +1 -1
  35. package/dist/lib/yaml/player.js +1 -1
  36. package/dist/lib/yaml/player.js.map +1 -1
  37. package/dist/types/agent/agent.d.ts +6 -0
  38. package/dist/types/agent/report-file-name.d.ts +1 -0
  39. package/dist/types/agent/utils.d.ts +1 -2
  40. package/dist/types/index.d.ts +3 -1
  41. package/dist/types/report.d.ts +11 -0
  42. package/dist/types/test-run-report.d.ts +167 -0
  43. package/package.json +2 -2
@@ -24,21 +24,24 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
+ collectDedupedExecutions: ()=>collectDedupedExecutions,
27
28
  splitReportHtmlByExecution: ()=>splitReportHtmlByExecution,
28
29
  ReportMergingTool: ()=>ReportMergingTool,
29
30
  isDirectoryModeReport: ()=>isDirectoryModeReport,
30
31
  dedupeExecutionsKeepLatest: ()=>dedupeExecutionsKeepLatest,
31
32
  removeReportArtifact: ()=>removeReportArtifact,
32
- collectDedupedExecutions: ()=>collectDedupedExecutions
33
+ TestRunReportAssembler: ()=>TestRunReportAssembler
33
34
  });
34
35
  const external_node_fs_namespaceObject = require("node:fs");
35
36
  const external_node_path_namespaceObject = require("node:path");
36
37
  const common_namespaceObject = require("@midscene/shared/common");
37
38
  const utils_namespaceObject = require("@midscene/shared/utils");
38
- const index_js_namespaceObject = require("./agent/index.js");
39
+ const report_file_name_js_namespaceObject = require("./agent/report-file-name.js");
39
40
  const html_utils_js_namespaceObject = require("./dump/html-utils.js");
40
41
  const image_reference_js_namespaceObject = require("./dump/image-reference.js");
41
42
  const screenshot_store_js_namespaceObject = require("./dump/screenshot-store.js");
43
+ const external_report_stats_js_namespaceObject = require("./report-stats.js");
44
+ const external_test_run_report_js_namespaceObject = require("./test-run-report.js");
42
45
  const external_types_js_namespaceObject = require("./types.js");
43
46
  const external_utils_js_namespaceObject = require("./utils.js");
44
47
  function _define_property(obj, key, value) {
@@ -175,7 +178,7 @@ class ReportMergingTool {
175
178
  });
176
179
  const isDirModeByIndex = this.reportInfos.map((info)=>Boolean(info.reportFilePath && isDirectoryModeReport(info.reportFilePath)));
177
180
  const hasDirectoryModeReport = isDirModeByIndex.some(Boolean);
178
- const resolvedName = 'AUTO' === reportFileName ? (0, index_js_namespaceObject.getReportFileName)('merged-report') : reportFileName;
181
+ const resolvedName = 'AUTO' === reportFileName ? (0, report_file_name_js_namespaceObject.getReportFileName)('merged-report') : reportFileName;
179
182
  const outputFilePath = hasDirectoryModeReport ? external_node_path_namespaceObject.resolve(targetDir, resolvedName, 'index.html') : external_node_path_namespaceObject.resolve(targetDir, `${resolvedName}.html`);
180
183
  if ('AUTO' !== reportFileName && (0, external_node_fs_namespaceObject.existsSync)(outputFilePath)) {
181
184
  if (!overwrite) throw new Error(`Report file already exists: ${outputFilePath}\nSet overwrite to true to overwrite this file.`);
@@ -271,6 +274,181 @@ class ReportMergingTool {
271
274
  _define_property(this, "reportInfos", []);
272
275
  }
273
276
  }
277
+ const emptyTestRunReportMetrics = ()=>({
278
+ modelCallCount: 0,
279
+ modelTimeMs: 0,
280
+ promptTokens: 0,
281
+ cachedInputTokens: 0,
282
+ completionTokens: 0,
283
+ totalTokens: 0
284
+ });
285
+ const validateTestRunReportFileName = (fileName)=>{
286
+ if (!fileName || '.' === fileName || '..' === fileName || external_node_path_namespaceObject.basename(fileName) !== fileName || fileName.endsWith('.html')) throw new Error(`Midscene Test reportFileName must be one path segment without an extension: ${fileName}`);
287
+ };
288
+ const uniqueTestRunReportSources = (sources)=>{
289
+ const unique = new Map();
290
+ const scopeBySourcePath = new Map();
291
+ for (const source of sources){
292
+ const scopeId = source.scopeId.trim();
293
+ const sourcePath = external_node_path_namespaceObject.resolve(source.sourcePath);
294
+ if (!scopeId) throw new Error('Midscene Test report source scopeId must not be empty.');
295
+ const previousScope = scopeBySourcePath.get(sourcePath);
296
+ if (previousScope && previousScope !== scopeId) throw new Error(`Agent report source is shared by multiple test scopes (${previousScope}, ${scopeId}): ${sourcePath}`);
297
+ scopeBySourcePath.set(sourcePath, scopeId);
298
+ unique.set(`${scopeId}\u0000${sourcePath}`, {
299
+ scopeId,
300
+ sourcePath
301
+ });
302
+ }
303
+ return [
304
+ ...unique.values()
305
+ ];
306
+ };
307
+ const prepareTestRunReportSources = (sources)=>{
308
+ const prepared = [];
309
+ const metrics = emptyTestRunReportMetrics();
310
+ const ownerByScopedExecution = new Map();
311
+ for (const [sourceIndex, source] of uniqueTestRunReportSources(sources).entries()){
312
+ if (!(0, external_node_fs_namespaceObject.existsSync)(source.sourcePath)) throw new Error(`Agent report does not exist: ${source.sourcePath}`);
313
+ const sourceVersion = peekReportSdkVersion(source.sourcePath);
314
+ const currentVersion = (0, external_utils_js_namespaceObject.getVersion)();
315
+ if (sourceVersion && currentVersion && sourceVersion !== currentVersion && !warnedMismatchedVersions.has(sourceVersion)) {
316
+ warnedMismatchedVersions.add(sourceVersion);
317
+ (0, utils_namespaceObject.logMsg)(`[@midscene/core] TestRunReportAssembler version mismatch: source report was written by @midscene/core@${sourceVersion} but the assembler is @midscene/core@${currentVersion}. Align the workspace package versions before generating the Midscene Test report.`);
318
+ }
319
+ const reportId = `runner-report-${sourceIndex + 1}`;
320
+ const { baseDump, executions } = collectDedupedExecutions(source.sourcePath);
321
+ const executionIds = [];
322
+ for (const execution of executions){
323
+ if (!execution.id) continue;
324
+ const scopedExecution = `${source.scopeId}\u0000${execution.id}`;
325
+ const previousOwner = ownerByScopedExecution.get(scopedExecution);
326
+ if (previousOwner && previousOwner !== reportId) throw new Error(`Agent execution ${execution.id} is present in multiple reports for test scope ${source.scopeId}: ${previousOwner}, ${reportId}`);
327
+ ownerByScopedExecution.set(scopedExecution, reportId);
328
+ executionIds.push(execution.id);
329
+ }
330
+ const dump = new external_types_js_namespaceObject.ReportActionDump({
331
+ sdkVersion: baseDump.sdkVersion,
332
+ groupName: baseDump.groupName,
333
+ groupDescription: baseDump.groupDescription,
334
+ modelBriefs: baseDump.modelBriefs,
335
+ deviceType: baseDump.deviceType,
336
+ executions
337
+ });
338
+ const sourceMetrics = (0, external_report_stats_js_namespaceObject.collectReportSummary)(dump);
339
+ metrics.modelCallCount += sourceMetrics.timing.modelCallCount;
340
+ metrics.modelTimeMs += sourceMetrics.timing.modelCallTimeMs;
341
+ metrics.promptTokens += sourceMetrics.tokens.promptTokens;
342
+ metrics.cachedInputTokens += sourceMetrics.tokens.cachedInputTokens;
343
+ metrics.completionTokens += sourceMetrics.tokens.completionTokens;
344
+ metrics.totalTokens += sourceMetrics.tokens.totalTokens;
345
+ prepared.push({
346
+ reportId,
347
+ scopeId: source.scopeId,
348
+ sourcePath: source.sourcePath,
349
+ executionIds,
350
+ dump,
351
+ directoryMode: isDirectoryModeReport(source.sourcePath)
352
+ });
353
+ }
354
+ return {
355
+ sources: prepared,
356
+ metrics
357
+ };
358
+ };
359
+ const runnerDumpScript = (dump)=>{
360
+ const closeTag = "<\/script>";
361
+ return '<script type="' + external_test_run_report_js_namespaceObject.TEST_RUN_REPORT_SCRIPT_TYPE + '">\n' + (0, utils_namespaceObject.escapeScriptTag)(JSON.stringify(dump)) + '\n' + closeTag + '\n';
362
+ };
363
+ class TestRunReportAssembler {
364
+ assemble(options) {
365
+ validateTestRunReportFileName(options.reportFileName);
366
+ const outputDir = external_node_path_namespaceObject.resolve(options.outputDir);
367
+ (0, external_node_fs_namespaceObject.mkdirSync)(outputDir, {
368
+ recursive: true
369
+ });
370
+ const prepared = prepareTestRunReportSources(options.sources);
371
+ const index = {
372
+ sources: prepared.sources.map(({ reportId, scopeId, sourcePath, executionIds })=>({
373
+ reportId,
374
+ scopeId,
375
+ sourcePath,
376
+ executionIds
377
+ })),
378
+ metrics: prepared.metrics
379
+ };
380
+ const runnerDump = options.buildRunnerDump(index);
381
+ if (1 !== runnerDump.schemaVersion || 'test-runner' !== runnerDump.kind) throw new Error('buildRunnerDump must return a Midscene Test report dump with schemaVersion 1 and kind "test-runner".');
382
+ JSON.stringify(runnerDump);
383
+ const directoryMode = prepared.sources.some((source)=>source.directoryMode);
384
+ const finalArtifactPath = external_node_path_namespaceObject.join(outputDir, options.reportFileName);
385
+ const directoryReportPath = external_node_path_namespaceObject.join(finalArtifactPath, 'index.html');
386
+ const standaloneReportPath = `${finalArtifactPath}.html`;
387
+ const finalReportPath = directoryMode ? directoryReportPath : standaloneReportPath;
388
+ const existingArtifacts = [
389
+ finalArtifactPath,
390
+ standaloneReportPath
391
+ ].filter(external_node_fs_namespaceObject.existsSync);
392
+ if (existingArtifacts.length > 0 && !options.overwrite) throw new Error(`Report artifact already exists: ${existingArtifacts[0]}\nSet overwrite to true to overwrite this report.`);
393
+ const temporaryRoot = (0, external_node_fs_namespaceObject.mkdtempSync)(external_node_path_namespaceObject.join(outputDir, '.test-run-report-'));
394
+ const temporaryArtifactPath = external_node_path_namespaceObject.join(temporaryRoot, options.reportFileName);
395
+ const temporaryReportPath = directoryMode ? external_node_path_namespaceObject.join(temporaryArtifactPath, 'index.html') : `${temporaryArtifactPath}.html`;
396
+ try {
397
+ if (directoryMode) (0, external_node_fs_namespaceObject.mkdirSync)(temporaryArtifactPath, {
398
+ recursive: true
399
+ });
400
+ const htmlEndTag = '</html>';
401
+ const template = (0, external_utils_js_namespaceObject.getReportTpl)();
402
+ const htmlEndIndex = template.lastIndexOf(htmlEndTag);
403
+ (0, external_node_fs_namespaceObject.appendFileSync)(temporaryReportPath, -1 === htmlEndIndex ? template : template.slice(0, htmlEndIndex));
404
+ if (directoryMode) (0, external_node_fs_namespaceObject.appendFileSync)(temporaryReportPath, (0, html_utils_js_namespaceObject.getBaseUrlFixScript)());
405
+ const agentReports = [];
406
+ for (const source of prepared.sources){
407
+ if (source.directoryMode) {
408
+ const screenshotsDir = external_node_path_namespaceObject.join(external_node_path_namespaceObject.dirname(source.sourcePath), 'screenshots');
409
+ if ((0, external_node_fs_namespaceObject.existsSync)(screenshotsDir)) {
410
+ const targetScreenshotsDir = external_node_path_namespaceObject.join(external_node_path_namespaceObject.dirname(temporaryReportPath), 'screenshots');
411
+ (0, external_node_fs_namespaceObject.mkdirSync)(targetScreenshotsDir, {
412
+ recursive: true
413
+ });
414
+ for (const file of (0, external_node_fs_namespaceObject.readdirSync)(screenshotsDir))(0, external_node_fs_namespaceObject.copyFileSync)(external_node_path_namespaceObject.join(screenshotsDir, file), external_node_path_namespaceObject.join(targetScreenshotsDir, file));
415
+ }
416
+ } else (0, html_utils_js_namespaceObject.streamImageScriptsToFile)(source.sourcePath, temporaryReportPath);
417
+ agentReports.push(source.dump);
418
+ (0, external_node_fs_namespaceObject.appendFileSync)(temporaryReportPath, `${(0, external_utils_js_namespaceObject.reportHTMLContent)({
419
+ dumpString: source.dump.serialize(),
420
+ attributes: {
421
+ 'data-group-id': source.reportId,
422
+ 'data-report-id': source.reportId,
423
+ 'data-runner-scope-id': source.scopeId,
424
+ [html_utils_js_namespaceObject.DATA_SCREENSHOT_MODE_ATTR]: directoryMode ? 'directory' : 'inline'
425
+ }
426
+ }, void 0, void 0, false)}\n`);
427
+ }
428
+ (0, external_node_fs_namespaceObject.appendFileSync)(temporaryReportPath, runnerDumpScript(runnerDump));
429
+ const agentComment = mergedAgentReportComment(agentReports);
430
+ if (agentComment) (0, external_node_fs_namespaceObject.appendFileSync)(temporaryReportPath, agentComment);
431
+ (0, external_node_fs_namespaceObject.appendFileSync)(temporaryReportPath, `${htmlEndTag}\n`);
432
+ if ((0, external_node_fs_namespaceObject.existsSync)(finalArtifactPath)) (0, external_node_fs_namespaceObject.rmSync)(finalArtifactPath, {
433
+ recursive: true,
434
+ force: true
435
+ });
436
+ if ((0, external_node_fs_namespaceObject.existsSync)(standaloneReportPath)) (0, external_node_fs_namespaceObject.unlinkSync)(standaloneReportPath);
437
+ (0, external_node_fs_namespaceObject.renameSync)(directoryMode ? temporaryArtifactPath : temporaryReportPath, directoryMode ? finalArtifactPath : standaloneReportPath);
438
+ (0, external_node_fs_namespaceObject.rmSync)(temporaryRoot, {
439
+ recursive: true,
440
+ force: true
441
+ });
442
+ return finalReportPath;
443
+ } catch (error) {
444
+ (0, external_node_fs_namespaceObject.rmSync)(temporaryRoot, {
445
+ recursive: true,
446
+ force: true
447
+ });
448
+ throw error;
449
+ }
450
+ }
451
+ }
274
452
  function collectDedupedExecutions(htmlPath) {
275
453
  let baseDump = null;
276
454
  let executionSerial = 0;
@@ -373,6 +551,7 @@ function splitReportHtmlByExecution(options) {
373
551
  };
374
552
  }
375
553
  exports.ReportMergingTool = __webpack_exports__.ReportMergingTool;
554
+ exports.TestRunReportAssembler = __webpack_exports__.TestRunReportAssembler;
376
555
  exports.collectDedupedExecutions = __webpack_exports__.collectDedupedExecutions;
377
556
  exports.dedupeExecutionsKeepLatest = __webpack_exports__.dedupeExecutionsKeepLatest;
378
557
  exports.isDirectoryModeReport = __webpack_exports__.isDirectoryModeReport;
@@ -380,6 +559,7 @@ exports.removeReportArtifact = __webpack_exports__.removeReportArtifact;
380
559
  exports.splitReportHtmlByExecution = __webpack_exports__.splitReportHtmlByExecution;
381
560
  for(var __rspack_i in __webpack_exports__)if (-1 === [
382
561
  "ReportMergingTool",
562
+ "TestRunReportAssembler",
383
563
  "collectDedupedExecutions",
384
564
  "dedupeExecutionsKeepLatest",
385
565
  "isDirectoryModeReport",
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/report.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","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 DATA_SCREENSHOT_MODE_ATTR,\n extractAllDumpScriptsSync,\n extractLastDumpScriptSync,\n generateAgentReportComment,\n getBaseUrlFixScript,\n streamDumpScriptsSync,\n streamImageScriptsToFile,\n} from './dump/html-utils';\nimport {\n imageRefFileExtension,\n normalizeStoredImageRef,\n} from './dump/image-reference';\nimport {\n parseBase64ImageDataUrl,\n resolveImageSource,\n} from './dump/screenshot-store';\nimport {\n type ExecutionDump,\n type IExecutionDump,\n ReportActionDump,\n type ScreenshotMode,\n} from './types';\nimport type { ReportFileWithAttributes } from './types';\nimport { getReportTpl, getVersion, reportHTMLContent } from './utils';\n\n/**\n * Read the screenshot storage mode a report declared at generation time.\n *\n * Reports written by current versions stamp `data-screenshot-mode` onto every\n * dump script tag, so we only need to peek at the first real dump script (the\n * template's bundled JS also references the dump type string, hence the\n * `data-group-id` filter) and can stop streaming immediately.\n *\n * Returns undefined for legacy reports that predate the attribute or for\n * unreadable files, letting the caller fall back to a filesystem heuristic.\n */\nconst screenshotModeAttrRegExp = new RegExp(\n `${DATA_SCREENSHOT_MODE_ATTR}=\"(inline|directory)\"`,\n);\n\nfunction readDeclaredScreenshotMode(\n reportFilePath: string,\n): ScreenshotMode | undefined {\n let mode: ScreenshotMode | undefined;\n try {\n streamDumpScriptsSync(reportFilePath, ({ openTag }) => {\n // Skip false matches from the template's bundled JS code.\n if (!openTag.includes('data-group-id')) return false;\n const match = openTag.match(screenshotModeAttrRegExp);\n mode = match?.[1] as ScreenshotMode | undefined;\n return true; // the first real dump script decides the mode\n });\n } catch {\n // Unreadable / non-existent file — let the caller fall back.\n }\n return mode;\n}\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 *\n * The mode is read from the report's own `data-screenshot-mode` metadata, which\n * is authoritative regardless of whether the run happened to capture any\n * screenshots. For legacy reports without the attribute we fall back to the old\n * filesystem heuristic (an `index.html` that has a sibling `screenshots/` dir).\n */\nexport function isDirectoryModeReport(reportFilePath: string): boolean {\n // Directory-mode reports are always written as `{name}/index.html`, so any\n // other filename is inline. Short-circuit before touching the file so the\n // common inline case (`{name}.html`) costs nothing.\n if (path.basename(reportFilePath) !== 'index.html') return false;\n\n const declared = readDeclaredScreenshotMode(reportFilePath);\n if (declared) return declared === 'directory';\n\n // Legacy fallback for reports generated before screenshotMode was embedded.\n return existsSync(path.join(path.dirname(reportFilePath), 'screenshots'));\n}\n\n/**\n * Whether a report lives in its own dedicated directory (`{name}/index.html`)\n * rather than being a single standalone file (`{name}.html`).\n *\n * This is a structural fact about *where the report file sits*, independent of\n * how it stores screenshots: a directory report can keep screenshots external\n * (a `screenshots/` sibling) OR inline them into `index.html`. Deletion needs\n * this — not the screenshot mode — to decide whether to remove the whole\n * directory or just unlink a file, so that an inline-screenshot report nested in\n * its own folder still has the folder removed instead of being orphaned.\n */\nfunction isDirectoryBasedReport(reportFilePath: string): boolean {\n return path.basename(reportFilePath) === 'index.html';\n}\n\n/**\n * Remove a complete report artifact from disk.\n *\n * Standalone reports own only their HTML file, while directory-based reports\n * own the directory containing `index.html`. Callers must decide whether they\n * own the source artifact and should only invoke this after its replacement\n * has been produced successfully.\n *\n * @param reportFilePath Path to the standalone report or directory report's\n * `index.html` entry point.\n * @throws When the owned report artifact cannot be removed.\n */\nexport function removeReportArtifact(reportFilePath: string): void {\n if (isDirectoryBasedReport(reportFilePath)) {\n rmSync(path.dirname(reportFilePath), { recursive: true, force: true });\n return;\n }\n unlinkSync(reportFilePath);\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\nfunction tryParseAgentReportDump(dumpString: string): ReportActionDump | null {\n const trimmed = dumpString.trimStart();\n if (!trimmed.startsWith('{') || !trimmed.includes('\"executions\"')) {\n return null;\n }\n\n try {\n return ReportActionDump.fromSerializedString(trimmed);\n } catch {\n return null;\n }\n}\n\nfunction mergedAgentReportComment(reports: ReportActionDump[]): string {\n if (reports.length === 0) {\n return '';\n }\n if (reports.length === 1) {\n return generateAgentReportComment(reports[0]);\n }\n\n const deviceTypes = Array.from(\n new Set(reports.map((report) => report.deviceType).filter(Boolean)),\n );\n const mergedReport = new ReportActionDump({\n sdkVersion: reports[0].sdkVersion || getVersion(),\n groupName: 'Merged Midscene Report',\n groupDescription: 'Agent-readable summary for merged report HTML',\n modelBriefs: reports.flatMap((report) => report.modelBriefs ?? []),\n deviceType: deviceTypes.length === 1 ? deviceTypes[0] : 'mixed',\n executions: reports.flatMap((report) => report.executions ?? []),\n });\n return generateAgentReportComment(mergedReport);\n}\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 (\n !reportInfo.reportFilePath &&\n reportInfo.reportAttributes.testStatus !== 'skipped'\n ) {\n throw new Error(\n 'reportFilePath is required unless reportAttributes.testStatus is \"skipped\"',\n );\n }\n\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 // Resolve each report's screenshot mode exactly once. isDirectoryModeReport\n // reads the file to find the authoritative metadata, so recomputing it for\n // both the output-path decision and the per-report merge loop would re-scan\n // every report twice.\n const isDirModeByIndex = this.reportInfos.map((info) =>\n Boolean(\n info.reportFilePath && isDirectoryModeReport(info.reportFilePath),\n ),\n );\n const hasDirectoryModeReport = isDirModeByIndex.some(Boolean);\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 const agentReports: ReportActionDump[] = [];\n const writtenInlineImageIds = new Set<string>();\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 (isDirModeByIndex[i]) {\n // Directory mode: copy external screenshot files. A directory-mode\n // report can legitimately have no screenshots/ dir (a run that\n // captured nothing), so only copy when the source dir exists.\n const reportDir = path.dirname(reportInfo.reportFilePath);\n const screenshotsDir = path.join(reportDir, 'screenshots');\n if (existsSync(screenshotsDir)) {\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 }\n } else {\n // Inline mode: stream image scripts to output file\n streamImageScriptsToFile(\n reportInfo.reportFilePath,\n outputFilePath,\n writtenInlineImageIds,\n );\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 agentReport = tryParseAgentReportDump(dumpString);\n if (agentReport) {\n agentReports.push(agentReport);\n }\n\n const reportHtmlStr = `${reportHTMLContent(\n {\n dumpString,\n attributes: {\n 'data-group-id': mergedGroupId,\n [DATA_SCREENSHOT_MODE_ATTR]: hasDirectoryModeReport\n ? 'directory'\n : 'inline',\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 const agentComment = mergedAgentReportComment(agentReports);\n if (agentComment) {\n appendFileSync(outputFilePath, agentComment);\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 let removedReportCount = 0;\n let reportCountWithFilePath = 0;\n for (const info of this.reportInfos) {\n if (!info.reportFilePath) continue;\n reportCountWithFilePath += 1;\n try {\n removeReportArtifact(info.reportFilePath);\n removedReportCount += 1;\n } catch (error) {\n logMsg(`Error deleting report ${info.reportFilePath}: ${error}`);\n }\n }\n logMsg(\n `Removed ${removedReportCount}/${reportCountWithFilePath} original reports`,\n );\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 externalizeImagesInExecution(\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 = normalizeStoredImageRef(node);\n if (ref) {\n const ext = imageRefFileExtension(ref);\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 = resolveImageSource(ref, {\n reportPath: opts.htmlPath,\n });\n if (resolved.type === 'data-uri') {\n const { rawBase64 } = parseBase64ImageDataUrl(resolved.dataUri);\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 externalizeImagesInExecution(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":["__webpack_require__","definition","key","Object","obj","prop","Symbol","screenshotModeAttrRegExp","RegExp","DATA_SCREENSHOT_MODE_ATTR","readDeclaredScreenshotMode","reportFilePath","mode","streamDumpScriptsSync","openTag","match","isDirectoryModeReport","path","declared","existsSync","isDirectoryBasedReport","removeReportArtifact","rmSync","unlinkSync","dedupeExecutionsKeepLatest","executions","noIdCounter","deduped","Map","exec","Array","peekReportSdkVersion","dump","extractLastDumpScriptSync","warnedMismatchedVersions","Set","tryParseAgentReportDump","dumpString","trimmed","ReportActionDump","mergedAgentReportComment","reports","generateAgentReportComment","deviceTypes","report","Boolean","mergedReport","getVersion","ReportMergingTool","groupName","groupDescription","reportInfo","Error","sourceVersion","currentVersion","logMsg","contents","unescaped","c","antiEscapeScriptTag","base","allExecutions","i","other","reportFileName","opts","rmOriginalReports","overwrite","outputDir","targetDir","getMidsceneRunSubDir","mkdirSync","isDirModeByIndex","info","hasDirectoryModeReport","resolvedName","getReportFileName","outputFilePath","htmlEndTag","tpl","getReportTpl","htmlEndIdx","tplWithoutClose","appendFileSync","getBaseUrlFixScript","agentReports","writtenInlineImageIds","reportAttributes","mergedGroupId","reportDir","screenshotsDir","mergedScreenshotsDir","file","readdirSync","src","dest","copyFileSync","streamImageScriptsToFile","allDumps","extractAllDumpScriptsSync","d","groupIdMatch","decodeURIComponent","extractedDumpString","agentReport","reportHtmlStr","reportHTMLContent","undefined","agentComment","removedReportCount","reportCountWithFilePath","error","collectDedupedExecutions","htmlPath","baseDump","executionSerial","latestSerialByExecutionId","dumpScript","groupedDump","execution","externalizeImagesInExecution","visit","node","item","ref","normalizeStoredImageRef","ext","imageRefFileExtension","fileName","relativePath","absolutePath","resolved","resolveImageSource","rawBase64","parseBase64ImageDataUrl","writeFileSync","Buffer","value","splitReportHtmlByExecution","options","executionJsonFiles","writtenScreenshotFiles","fileIndex","singleExecutionDump","jsonFilePath"],"mappings":"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"}
1
+ {"version":3,"file":"report.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/report.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import {\n appendFileSync,\n copyFileSync,\n existsSync,\n mkdirSync,\n mkdtempSync,\n readdirSync,\n renameSync,\n rmSync,\n unlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport * as path from 'node:path';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport {\n antiEscapeScriptTag,\n escapeScriptTag,\n logMsg,\n} from '@midscene/shared/utils';\nimport { getReportFileName } from './agent/report-file-name';\nimport {\n DATA_SCREENSHOT_MODE_ATTR,\n extractAllDumpScriptsSync,\n extractLastDumpScriptSync,\n generateAgentReportComment,\n getBaseUrlFixScript,\n streamDumpScriptsSync,\n streamImageScriptsToFile,\n} from './dump/html-utils';\nimport {\n imageRefFileExtension,\n normalizeStoredImageRef,\n} from './dump/image-reference';\nimport {\n parseBase64ImageDataUrl,\n resolveImageSource,\n} from './dump/screenshot-store';\nimport { collectReportSummary } from './report-stats';\nimport {\n type AssembleTestRunReportOptions,\n type IndexedTestRunReportSource,\n TEST_RUN_REPORT_SCRIPT_TYPE,\n type TestRunReportDump,\n type TestRunReportMetrics,\n type TestRunReportSource,\n type TestRunReportSourceIndex,\n} from './test-run-report';\nimport {\n type ExecutionDump,\n type IExecutionDump,\n ReportActionDump,\n type ScreenshotMode,\n} from './types';\nimport type { ReportFileWithAttributes } from './types';\nimport { getReportTpl, getVersion, reportHTMLContent } from './utils';\n\n/**\n * Read the screenshot storage mode a report declared at generation time.\n *\n * Reports written by current versions stamp `data-screenshot-mode` onto every\n * dump script tag, so we only need to peek at the first real dump script (the\n * template's bundled JS also references the dump type string, hence the\n * `data-group-id` filter) and can stop streaming immediately.\n *\n * Returns undefined for legacy reports that predate the attribute or for\n * unreadable files, letting the caller fall back to a filesystem heuristic.\n */\nconst screenshotModeAttrRegExp = new RegExp(\n `${DATA_SCREENSHOT_MODE_ATTR}=\"(inline|directory)\"`,\n);\n\nfunction readDeclaredScreenshotMode(\n reportFilePath: string,\n): ScreenshotMode | undefined {\n let mode: ScreenshotMode | undefined;\n try {\n streamDumpScriptsSync(reportFilePath, ({ openTag }) => {\n // Skip false matches from the template's bundled JS code.\n if (!openTag.includes('data-group-id')) return false;\n const match = openTag.match(screenshotModeAttrRegExp);\n mode = match?.[1] as ScreenshotMode | undefined;\n return true; // the first real dump script decides the mode\n });\n } catch {\n // Unreadable / non-existent file — let the caller fall back.\n }\n return mode;\n}\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 *\n * The mode is read from the report's own `data-screenshot-mode` metadata, which\n * is authoritative regardless of whether the run happened to capture any\n * screenshots. For legacy reports without the attribute we fall back to the old\n * filesystem heuristic (an `index.html` that has a sibling `screenshots/` dir).\n */\nexport function isDirectoryModeReport(reportFilePath: string): boolean {\n // Directory-mode reports are always written as `{name}/index.html`, so any\n // other filename is inline. Short-circuit before touching the file so the\n // common inline case (`{name}.html`) costs nothing.\n if (path.basename(reportFilePath) !== 'index.html') return false;\n\n const declared = readDeclaredScreenshotMode(reportFilePath);\n if (declared) return declared === 'directory';\n\n // Legacy fallback for reports generated before screenshotMode was embedded.\n return existsSync(path.join(path.dirname(reportFilePath), 'screenshots'));\n}\n\n/**\n * Whether a report lives in its own dedicated directory (`{name}/index.html`)\n * rather than being a single standalone file (`{name}.html`).\n *\n * This is a structural fact about *where the report file sits*, independent of\n * how it stores screenshots: a directory report can keep screenshots external\n * (a `screenshots/` sibling) OR inline them into `index.html`. Deletion needs\n * this — not the screenshot mode — to decide whether to remove the whole\n * directory or just unlink a file, so that an inline-screenshot report nested in\n * its own folder still has the folder removed instead of being orphaned.\n */\nfunction isDirectoryBasedReport(reportFilePath: string): boolean {\n return path.basename(reportFilePath) === 'index.html';\n}\n\n/**\n * Remove a complete report artifact from disk.\n *\n * Standalone reports own only their HTML file, while directory-based reports\n * own the directory containing `index.html`. Callers must decide whether they\n * own the source artifact and should only invoke this after its replacement\n * has been produced successfully.\n *\n * @param reportFilePath Path to the standalone report or directory report's\n * `index.html` entry point.\n * @throws When the owned report artifact cannot be removed.\n */\nexport function removeReportArtifact(reportFilePath: string): void {\n if (isDirectoryBasedReport(reportFilePath)) {\n rmSync(path.dirname(reportFilePath), { recursive: true, force: true });\n return;\n }\n unlinkSync(reportFilePath);\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\nfunction tryParseAgentReportDump(dumpString: string): ReportActionDump | null {\n const trimmed = dumpString.trimStart();\n if (!trimmed.startsWith('{') || !trimmed.includes('\"executions\"')) {\n return null;\n }\n\n try {\n return ReportActionDump.fromSerializedString(trimmed);\n } catch {\n return null;\n }\n}\n\nfunction mergedAgentReportComment(reports: ReportActionDump[]): string {\n if (reports.length === 0) {\n return '';\n }\n if (reports.length === 1) {\n return generateAgentReportComment(reports[0]);\n }\n\n const deviceTypes = Array.from(\n new Set(reports.map((report) => report.deviceType).filter(Boolean)),\n );\n const mergedReport = new ReportActionDump({\n sdkVersion: reports[0].sdkVersion || getVersion(),\n groupName: 'Merged Midscene Report',\n groupDescription: 'Agent-readable summary for merged report HTML',\n modelBriefs: reports.flatMap((report) => report.modelBriefs ?? []),\n deviceType: deviceTypes.length === 1 ? deviceTypes[0] : 'mixed',\n executions: reports.flatMap((report) => report.executions ?? []),\n });\n return generateAgentReportComment(mergedReport);\n}\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 (\n !reportInfo.reportFilePath &&\n reportInfo.reportAttributes.testStatus !== 'skipped'\n ) {\n throw new Error(\n 'reportFilePath is required unless reportAttributes.testStatus is \"skipped\"',\n );\n }\n\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 // Resolve each report's screenshot mode exactly once. isDirectoryModeReport\n // reads the file to find the authoritative metadata, so recomputing it for\n // both the output-path decision and the per-report merge loop would re-scan\n // every report twice.\n const isDirModeByIndex = this.reportInfos.map((info) =>\n Boolean(\n info.reportFilePath && isDirectoryModeReport(info.reportFilePath),\n ),\n );\n const hasDirectoryModeReport = isDirModeByIndex.some(Boolean);\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 const agentReports: ReportActionDump[] = [];\n const writtenInlineImageIds = new Set<string>();\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 (isDirModeByIndex[i]) {\n // Directory mode: copy external screenshot files. A directory-mode\n // report can legitimately have no screenshots/ dir (a run that\n // captured nothing), so only copy when the source dir exists.\n const reportDir = path.dirname(reportInfo.reportFilePath);\n const screenshotsDir = path.join(reportDir, 'screenshots');\n if (existsSync(screenshotsDir)) {\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 }\n } else {\n // Inline mode: stream image scripts to output file\n streamImageScriptsToFile(\n reportInfo.reportFilePath,\n outputFilePath,\n writtenInlineImageIds,\n );\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 agentReport = tryParseAgentReportDump(dumpString);\n if (agentReport) {\n agentReports.push(agentReport);\n }\n\n const reportHtmlStr = `${reportHTMLContent(\n {\n dumpString,\n attributes: {\n 'data-group-id': mergedGroupId,\n [DATA_SCREENSHOT_MODE_ATTR]: hasDirectoryModeReport\n ? 'directory'\n : 'inline',\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 const agentComment = mergedAgentReportComment(agentReports);\n if (agentComment) {\n appendFileSync(outputFilePath, agentComment);\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 let removedReportCount = 0;\n let reportCountWithFilePath = 0;\n for (const info of this.reportInfos) {\n if (!info.reportFilePath) continue;\n reportCountWithFilePath += 1;\n try {\n removeReportArtifact(info.reportFilePath);\n removedReportCount += 1;\n } catch (error) {\n logMsg(`Error deleting report ${info.reportFilePath}: ${error}`);\n }\n }\n logMsg(\n `Removed ${removedReportCount}/${reportCountWithFilePath} original reports`,\n );\n }\n return outputFilePath;\n } catch (error) {\n logMsg(`Error in mergeReports: ${error}`);\n throw error;\n }\n }\n}\n\ninterface PreparedTestRunReportSource extends IndexedTestRunReportSource {\n dump: ReportActionDump;\n directoryMode: boolean;\n}\n\nconst emptyTestRunReportMetrics = (): TestRunReportMetrics => ({\n modelCallCount: 0,\n modelTimeMs: 0,\n promptTokens: 0,\n cachedInputTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n});\n\nconst validateTestRunReportFileName = (fileName: string): void => {\n if (\n !fileName ||\n fileName === '.' ||\n fileName === '..' ||\n path.basename(fileName) !== fileName ||\n fileName.endsWith('.html')\n ) {\n throw new Error(\n `Midscene Test reportFileName must be one path segment without an extension: ${fileName}`,\n );\n }\n};\n\nconst uniqueTestRunReportSources = (\n sources: readonly TestRunReportSource[],\n): TestRunReportSource[] => {\n const unique = new Map<string, TestRunReportSource>();\n const scopeBySourcePath = new Map<string, string>();\n\n for (const source of sources) {\n const scopeId = source.scopeId.trim();\n const sourcePath = path.resolve(source.sourcePath);\n if (!scopeId) {\n throw new Error('Midscene Test report source scopeId must not be empty.');\n }\n\n const previousScope = scopeBySourcePath.get(sourcePath);\n if (previousScope && previousScope !== scopeId) {\n throw new Error(\n `Agent report source is shared by multiple test scopes (${previousScope}, ${scopeId}): ${sourcePath}`,\n );\n }\n scopeBySourcePath.set(sourcePath, scopeId);\n unique.set(`${scopeId}\\u0000${sourcePath}`, { scopeId, sourcePath });\n }\n\n return [...unique.values()];\n};\n\nconst prepareTestRunReportSources = (\n sources: readonly TestRunReportSource[],\n): {\n sources: PreparedTestRunReportSource[];\n metrics: TestRunReportMetrics;\n} => {\n const prepared: PreparedTestRunReportSource[] = [];\n const metrics = emptyTestRunReportMetrics();\n const ownerByScopedExecution = new Map<string, string>();\n\n for (const [sourceIndex, source] of uniqueTestRunReportSources(\n sources,\n ).entries()) {\n if (!existsSync(source.sourcePath)) {\n throw new Error(`Agent report does not exist: ${source.sourcePath}`);\n }\n\n const sourceVersion = peekReportSdkVersion(source.sourcePath);\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] TestRunReportAssembler version mismatch: source report was written by @midscene/core@${sourceVersion} but the assembler is @midscene/core@${currentVersion}. Align the workspace package versions before generating the Midscene Test report.`,\n );\n }\n\n const reportId = `runner-report-${sourceIndex + 1}`;\n const { baseDump, executions } = collectDedupedExecutions(\n source.sourcePath,\n );\n const executionIds: string[] = [];\n for (const execution of executions) {\n if (!execution.id) continue;\n const scopedExecution = `${source.scopeId}\\u0000${execution.id}`;\n const previousOwner = ownerByScopedExecution.get(scopedExecution);\n if (previousOwner && previousOwner !== reportId) {\n throw new Error(\n `Agent execution ${execution.id} is present in multiple reports for test scope ${source.scopeId}: ${previousOwner}, ${reportId}`,\n );\n }\n ownerByScopedExecution.set(scopedExecution, reportId);\n executionIds.push(execution.id);\n }\n\n const dump = new ReportActionDump({\n sdkVersion: baseDump.sdkVersion,\n groupName: baseDump.groupName,\n groupDescription: baseDump.groupDescription,\n modelBriefs: baseDump.modelBriefs,\n deviceType: baseDump.deviceType,\n executions,\n });\n const sourceMetrics = collectReportSummary(dump);\n metrics.modelCallCount += sourceMetrics.timing.modelCallCount;\n metrics.modelTimeMs += sourceMetrics.timing.modelCallTimeMs;\n metrics.promptTokens += sourceMetrics.tokens.promptTokens;\n metrics.cachedInputTokens += sourceMetrics.tokens.cachedInputTokens;\n metrics.completionTokens += sourceMetrics.tokens.completionTokens;\n metrics.totalTokens += sourceMetrics.tokens.totalTokens;\n\n prepared.push({\n reportId,\n scopeId: source.scopeId,\n sourcePath: source.sourcePath,\n executionIds,\n dump,\n directoryMode: isDirectoryModeReport(source.sourcePath),\n });\n }\n\n return { sources: prepared, metrics };\n};\n\nconst runnerDumpScript = (dump: TestRunReportDump): string => {\n const closeTag = '</scr' + 'ipt>';\n return (\n // biome-ignore lint/style/useTemplate: keep the closing script token runtime-built for inline report safety\n '<script type=\"' +\n TEST_RUN_REPORT_SCRIPT_TYPE +\n '\">\\n' +\n escapeScriptTag(JSON.stringify(dump)) +\n '\\n' +\n closeTag +\n '\\n'\n );\n};\n\n/**\n * Build a self-contained Midscene Test report while preserving the existing\n * Agent dump format consumed by the Report App.\n *\n * Test hierarchy and status live in `midscene_test_run_dump`; Agent reports\n * remain independent `midscene_web_dump` groups addressed by `data-report-id`.\n */\nexport class TestRunReportAssembler {\n public assemble(options: AssembleTestRunReportOptions): string {\n validateTestRunReportFileName(options.reportFileName);\n const outputDir = path.resolve(options.outputDir);\n mkdirSync(outputDir, { recursive: true });\n\n const prepared = prepareTestRunReportSources(options.sources);\n const index: TestRunReportSourceIndex = {\n sources: prepared.sources.map(\n ({ reportId, scopeId, sourcePath, executionIds }) => ({\n reportId,\n scopeId,\n sourcePath,\n executionIds,\n }),\n ),\n metrics: prepared.metrics,\n };\n const runnerDump = options.buildRunnerDump(index);\n if (runnerDump.schemaVersion !== 1 || runnerDump.kind !== 'test-runner') {\n throw new Error(\n 'buildRunnerDump must return a Midscene Test report dump with schemaVersion 1 and kind \"test-runner\".',\n );\n }\n // Validate serializability before creating any output artifact.\n JSON.stringify(runnerDump);\n\n const directoryMode = prepared.sources.some(\n (source) => source.directoryMode,\n );\n const finalArtifactPath = path.join(outputDir, options.reportFileName);\n const directoryReportPath = path.join(finalArtifactPath, 'index.html');\n const standaloneReportPath = `${finalArtifactPath}.html`;\n const finalReportPath = directoryMode\n ? directoryReportPath\n : standaloneReportPath;\n const existingArtifacts = [finalArtifactPath, standaloneReportPath].filter(\n existsSync,\n );\n if (existingArtifacts.length > 0 && !options.overwrite) {\n throw new Error(\n `Report artifact already exists: ${existingArtifacts[0]}\\nSet overwrite to true to overwrite this report.`,\n );\n }\n\n const temporaryRoot = mkdtempSync(\n path.join(outputDir, '.test-run-report-'),\n );\n const temporaryArtifactPath = path.join(\n temporaryRoot,\n options.reportFileName,\n );\n const temporaryReportPath = directoryMode\n ? path.join(temporaryArtifactPath, 'index.html')\n : `${temporaryArtifactPath}.html`;\n\n try {\n if (directoryMode) {\n mkdirSync(temporaryArtifactPath, { recursive: true });\n }\n\n const htmlEndTag = '</html>';\n const template = getReportTpl();\n const htmlEndIndex = template.lastIndexOf(htmlEndTag);\n appendFileSync(\n temporaryReportPath,\n htmlEndIndex === -1 ? template : template.slice(0, htmlEndIndex),\n );\n if (directoryMode) {\n appendFileSync(temporaryReportPath, getBaseUrlFixScript());\n }\n\n const agentReports: ReportActionDump[] = [];\n for (const source of prepared.sources) {\n if (source.directoryMode) {\n const screenshotsDir = path.join(\n path.dirname(source.sourcePath),\n 'screenshots',\n );\n if (existsSync(screenshotsDir)) {\n const targetScreenshotsDir = path.join(\n path.dirname(temporaryReportPath),\n 'screenshots',\n );\n mkdirSync(targetScreenshotsDir, { recursive: true });\n for (const file of readdirSync(screenshotsDir)) {\n copyFileSync(\n path.join(screenshotsDir, file),\n path.join(targetScreenshotsDir, file),\n );\n }\n }\n } else {\n streamImageScriptsToFile(source.sourcePath, temporaryReportPath);\n }\n\n agentReports.push(source.dump);\n appendFileSync(\n temporaryReportPath,\n `${reportHTMLContent(\n {\n dumpString: source.dump.serialize(),\n attributes: {\n 'data-group-id': source.reportId,\n 'data-report-id': source.reportId,\n 'data-runner-scope-id': source.scopeId,\n [DATA_SCREENSHOT_MODE_ATTR]: directoryMode\n ? 'directory'\n : 'inline',\n },\n },\n undefined,\n undefined,\n false,\n )}\\n`,\n );\n }\n\n appendFileSync(temporaryReportPath, runnerDumpScript(runnerDump));\n const agentComment = mergedAgentReportComment(agentReports);\n if (agentComment) {\n appendFileSync(temporaryReportPath, agentComment);\n }\n appendFileSync(temporaryReportPath, `${htmlEndTag}\\n`);\n\n if (existsSync(finalArtifactPath)) {\n rmSync(finalArtifactPath, { recursive: true, force: true });\n }\n if (existsSync(standaloneReportPath)) {\n unlinkSync(standaloneReportPath);\n }\n renameSync(\n directoryMode ? temporaryArtifactPath : temporaryReportPath,\n directoryMode ? finalArtifactPath : standaloneReportPath,\n );\n rmSync(temporaryRoot, { recursive: true, force: true });\n return finalReportPath;\n } catch (error) {\n rmSync(temporaryRoot, { recursive: true, force: true });\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 externalizeImagesInExecution(\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 = normalizeStoredImageRef(node);\n if (ref) {\n const ext = imageRefFileExtension(ref);\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 = resolveImageSource(ref, {\n reportPath: opts.htmlPath,\n });\n if (resolved.type === 'data-uri') {\n const { rawBase64 } = parseBase64ImageDataUrl(resolved.dataUri);\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 externalizeImagesInExecution(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":["__webpack_require__","definition","key","Object","obj","prop","Symbol","screenshotModeAttrRegExp","RegExp","DATA_SCREENSHOT_MODE_ATTR","readDeclaredScreenshotMode","reportFilePath","mode","streamDumpScriptsSync","openTag","match","isDirectoryModeReport","path","declared","existsSync","isDirectoryBasedReport","removeReportArtifact","rmSync","unlinkSync","dedupeExecutionsKeepLatest","executions","noIdCounter","deduped","Map","exec","Array","peekReportSdkVersion","dump","extractLastDumpScriptSync","warnedMismatchedVersions","Set","tryParseAgentReportDump","dumpString","trimmed","ReportActionDump","mergedAgentReportComment","reports","generateAgentReportComment","deviceTypes","report","Boolean","mergedReport","getVersion","ReportMergingTool","groupName","groupDescription","reportInfo","Error","sourceVersion","currentVersion","logMsg","contents","unescaped","c","antiEscapeScriptTag","base","allExecutions","i","other","reportFileName","opts","rmOriginalReports","overwrite","outputDir","targetDir","getMidsceneRunSubDir","mkdirSync","isDirModeByIndex","info","hasDirectoryModeReport","resolvedName","getReportFileName","outputFilePath","htmlEndTag","tpl","getReportTpl","htmlEndIdx","tplWithoutClose","appendFileSync","getBaseUrlFixScript","agentReports","writtenInlineImageIds","reportAttributes","mergedGroupId","reportDir","screenshotsDir","mergedScreenshotsDir","file","readdirSync","src","dest","copyFileSync","streamImageScriptsToFile","allDumps","extractAllDumpScriptsSync","d","groupIdMatch","decodeURIComponent","extractedDumpString","agentReport","reportHtmlStr","reportHTMLContent","undefined","agentComment","removedReportCount","reportCountWithFilePath","error","emptyTestRunReportMetrics","validateTestRunReportFileName","fileName","uniqueTestRunReportSources","sources","unique","scopeBySourcePath","source","scopeId","sourcePath","previousScope","prepareTestRunReportSources","prepared","metrics","ownerByScopedExecution","sourceIndex","reportId","baseDump","collectDedupedExecutions","executionIds","execution","scopedExecution","previousOwner","sourceMetrics","collectReportSummary","runnerDumpScript","closeTag","TEST_RUN_REPORT_SCRIPT_TYPE","escapeScriptTag","JSON","TestRunReportAssembler","options","index","runnerDump","directoryMode","finalArtifactPath","directoryReportPath","standaloneReportPath","finalReportPath","existingArtifacts","temporaryRoot","mkdtempSync","temporaryArtifactPath","temporaryReportPath","template","htmlEndIndex","targetScreenshotsDir","renameSync","htmlPath","executionSerial","latestSerialByExecutionId","dumpScript","groupedDump","externalizeImagesInExecution","visit","node","item","ref","normalizeStoredImageRef","ext","imageRefFileExtension","relativePath","absolutePath","resolved","resolveImageSource","rawBase64","parseBase64ImageDataUrl","writeFileSync","Buffer","value","splitReportHtmlByExecution","executionJsonFiles","writtenScreenshotFiles","fileIndex","singleExecutionDump","jsonFilePath"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC6DA,MAAMI,2BAA2B,IAAIC,OACnC,GAAGC,8BAAAA,yBAAyBA,CAAC,qBAAqB,CAAC;AAGrD,SAASC,2BACPC,cAAsB;IAEtB,IAAIC;IACJ,IAAI;QACFC,IAAAA,8BAAAA,qBAAAA,AAAAA,EAAsBF,gBAAgB,CAAC,EAAEG,OAAO,EAAE;YAEhD,IAAI,CAACA,QAAQ,QAAQ,CAAC,kBAAkB,OAAO;YAC/C,MAAMC,QAAQD,QAAQ,KAAK,CAACP;YAC5BK,OAAOG,OAAO,CAAC,EAAE;YACjB,OAAO;QACT;IACF,EAAE,OAAM,CAER;IACA,OAAOH;AACT;AAWO,SAASI,sBAAsBL,cAAsB;IAI1D,IAAIM,AAAkC,iBAAlCA,mCAAAA,QAAa,CAACN,iBAAkC,OAAO;IAE3D,MAAMO,WAAWR,2BAA2BC;IAC5C,IAAIO,UAAU,OAAOA,AAAa,gBAAbA;IAGrB,OAAOC,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWF,mCAAAA,IAAS,CAACA,mCAAAA,OAAY,CAACN,iBAAiB;AAC5D;AAaA,SAASS,uBAAuBT,cAAsB;IACpD,OAAOM,AAAkC,iBAAlCA,mCAAAA,QAAa,CAACN;AACvB;AAcO,SAASU,qBAAqBV,cAAsB;IACzD,IAAIS,uBAAuBT,iBAAiB,YAC1CW,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,EAAOL,mCAAAA,OAAY,CAACN,iBAAiB;QAAE,WAAW;QAAM,OAAO;IAAK;IAGtEY,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWZ;AACb;AAMO,SAASa,2BACdC,UAAe;IAEf,IAAIC,cAAc;IAClB,MAAMC,UAAU,IAAIC;IACpB,KAAK,MAAMC,QAAQJ,WAAY;QAC7B,MAAMvB,MAAM2B,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAEH,eAAe;QACjDC,QAAQ,GAAG,CAACzB,KAAK2B;IACnB;IACA,OAAOC,MAAM,IAAI,CAACH,QAAQ,MAAM;AAClC;AAMA,SAASI,qBAAqBpB,cAAsB;IAClD,IAAI;QACF,MAAMqB,OAAOC,AAAAA,IAAAA,8BAAAA,yBAAAA,AAAAA,EAA0BtB;QACvC,IAAI,CAACqB,MAAM;QACX,MAAMjB,QAAQiB,KAAK,KAAK,CAAC;QACzB,OAAOjB,OAAO,CAAC,EAAE;IACnB,EAAE,OAAM;QACN;IACF;AACF;AAEA,MAAMmB,2BAA2B,IAAIC;AAErC,SAASC,wBAAwBC,UAAkB;IACjD,MAAMC,UAAUD,WAAW,SAAS;IACpC,IAAI,CAACC,QAAQ,UAAU,CAAC,QAAQ,CAACA,QAAQ,QAAQ,CAAC,iBAChD,OAAO;IAGT,IAAI;QACF,OAAOC,kCAAAA,gBAAAA,CAAAA,oBAAqC,CAACD;IAC/C,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAASE,yBAAyBC,OAA2B;IAC3D,IAAIA,AAAmB,MAAnBA,QAAQ,MAAM,EAChB,OAAO;IAET,IAAIA,AAAmB,MAAnBA,QAAQ,MAAM,EAChB,OAAOC,AAAAA,IAAAA,8BAAAA,0BAAAA,AAAAA,EAA2BD,OAAO,CAAC,EAAE;IAG9C,MAAME,cAAcb,MAAM,IAAI,CAC5B,IAAIK,IAAIM,QAAQ,GAAG,CAAC,CAACG,SAAWA,OAAO,UAAU,EAAE,MAAM,CAACC;IAE5D,MAAMC,eAAe,IAAIP,kCAAAA,gBAAgBA,CAAC;QACxC,YAAYE,OAAO,CAAC,EAAE,CAAC,UAAU,IAAIM,AAAAA,IAAAA,kCAAAA,UAAAA,AAAAA;QACrC,WAAW;QACX,kBAAkB;QAClB,aAAaN,QAAQ,OAAO,CAAC,CAACG,SAAWA,OAAO,WAAW,IAAI,EAAE;QACjE,YAAYD,AAAuB,MAAvBA,YAAY,MAAM,GAASA,WAAW,CAAC,EAAE,GAAG;QACxD,YAAYF,QAAQ,OAAO,CAAC,CAACG,SAAWA,OAAO,UAAU,IAAI,EAAE;IACjE;IACA,OAAOF,AAAAA,IAAAA,8BAAAA,0BAAAA,AAAAA,EAA2BI;AACpC;AAEO,MAAME;IAGH,sBAAsBC,SAAiB,EAAEC,gBAAyB,EAAE;QAC1E,OAAO,IAAIX,kCAAAA,gBAAgBA,CAAC;YAC1B,YAAY;YACZU;YACAC;YACA,aAAa,EAAE;YACf,YAAY,EAAE;QAChB,GAAG,SAAS;IACd;IAEO,OAAOC,UAAoC,EAAE;QAClD,IACE,CAACA,WAAW,cAAc,IAC1BA,AAA2C,cAA3CA,WAAW,gBAAgB,CAAC,UAAU,EAEtC,MAAM,IAAIC,MACR;QAIJ,IAAID,WAAW,cAAc,EAAE;YAC7B,MAAME,gBAAgBtB,qBAAqBoB,WAAW,cAAc;YACpE,MAAMG,iBAAiBP,AAAAA,IAAAA,kCAAAA,UAAAA,AAAAA;YACvB,IACEM,iBACAC,kBACAD,kBAAkBC,kBAClB,CAACpB,yBAAyB,GAAG,CAACmB,gBAC9B;gBACAnB,yBAAyB,GAAG,CAACmB;gBAC7BE,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAAC,iGAAiG,EAAEF,cAAc,kCAAkC,EAAEC,eAAe,gRAAgR,CAAC;YAE1b;QACF;QACA,IAAI,CAAC,WAAW,CAAC,IAAI,CAACH;IACxB;IACO,QAAQ;QACb,IAAI,CAAC,WAAW,GAAG,EAAE;IACvB;IAQQ,iBAAiBK,QAAkB,EAAU;QACnD,MAAMC,YAAYD,SACf,GAAG,CAAC,CAACE,IAAMC,AAAAA,IAAAA,sBAAAA,mBAAAA,AAAAA,EAAoBD,IAC/B,MAAM,CAAC,CAACA,IAAMA,EAAE,MAAM,GAAG;QAC5B,IAAID,AAAqB,MAArBA,UAAU,MAAM,EAAQ,OAAO;QACnC,IAAIA,AAAqB,MAArBA,UAAU,MAAM,EAAQ,OAAOA,SAAS,CAAC,EAAE;QAK/C,MAAMG,OAAOrB,kCAAAA,gBAAAA,CAAAA,oBAAqC,CAACkB,SAAS,CAAC,EAAE;QAC/D,MAAMI,gBAAgB;eAAID,KAAK,UAAU;SAAC;QAC1C,IAAK,IAAIE,IAAI,GAAGA,IAAIL,UAAU,MAAM,EAAEK,IAAK;YACzC,MAAMC,QAAQxB,kCAAAA,gBAAAA,CAAAA,oBAAqC,CAACkB,SAAS,CAACK,EAAE;YAChED,cAAc,IAAI,IAAIE,MAAM,UAAU;QACxC;QACAH,KAAK,UAAU,GAAGpC,2BAA2BqC;QAC7C,OAAOD,KAAK,SAAS;IACvB;IAEO,aACLI,iBAAkC,MAAM,EACxCC,IAIC,EACc;QACf,MAAM,EACJC,oBAAoB,KAAK,EACzBC,YAAY,KAAK,EACjBC,SAAS,EACV,GAAGH,QAAQ,CAAC;QAEb,IAAI,AAA4B,MAA5B,IAAI,CAAC,WAAW,CAAC,MAAM,EAAQ;YACjCV,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO;YACP,OAAO;QACT;QAEA,MAAMc,YAAYD,YACdnD,mCAAAA,OAAY,CAACmD,aACbE,AAAAA,IAAAA,uBAAAA,oBAAAA,AAAAA,EAAqB;QACzB,IAAIF,WACFG,AAAAA,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUF,WAAW;YAAE,WAAW;QAAK;QAOzC,MAAMG,mBAAmB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAACC,OAC7C5B,QACE4B,KAAK,cAAc,IAAIzD,sBAAsByD,KAAK,cAAc;QAGpE,MAAMC,yBAAyBF,iBAAiB,IAAI,CAAC3B;QAErD,MAAM8B,eACJX,AAAmB,WAAnBA,iBACIY,AAAAA,IAAAA,oCAAAA,iBAAAA,AAAAA,EAAkB,mBAClBZ;QAIN,MAAMa,iBAAiBH,yBACnBzD,mCAAAA,OAAY,CAACoD,WAAWM,cAAc,gBACtC1D,mCAAAA,OAAY,CAACoD,WAAW,GAAGM,aAAa,KAAK,CAAC;QAElD,IAAIX,AAAmB,WAAnBA,kBAA6B7C,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAW0D,iBAAiB;YAC3D,IAAI,CAACV,WACH,MAAM,IAAIf,MACR,CAAC,4BAA4B,EAAEyB,eAAe,+CAA+C,CAAC;YAGlG,IAAIH,wBACFpD,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,EAAOL,mCAAAA,OAAY,CAAC4D,iBAAiB;gBAAE,WAAW;gBAAM,OAAO;YAAK;iBAEpEtD,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWsD;QAEf;QAEA,IAAIH,wBACFH,AAAAA,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUtD,mCAAAA,OAAY,CAAC4D,iBAAiB;YAAE,WAAW;QAAK;QAG5DtB,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAAC,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,sCAAsC,CAAC;QAGlF,IAAI;YAGF,MAAMuB,aAAa;YACnB,MAAMC,MAAMC,AAAAA,IAAAA,kCAAAA,YAAAA,AAAAA;YACZ,MAAMC,aAAaF,IAAI,WAAW,CAACD;YACnC,MAAMI,kBACJD,AAAe,OAAfA,aAAoBF,IAAI,KAAK,CAAC,GAAGE,cAAcF;YACjDI,IAAAA,iCAAAA,cAAAA,AAAAA,EAAeN,gBAAgBK;YAG/B,IAAIR,wBACFS,AAAAA,IAAAA,iCAAAA,cAAAA,AAAAA,EAAeN,gBAAgBO,AAAAA,IAAAA,8BAAAA,mBAAAA,AAAAA;YAGjC,MAAMC,eAAmC,EAAE;YAC3C,MAAMC,wBAAwB,IAAInD;YAGlC,IAAK,IAAI2B,IAAI,GAAGA,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAEA,IAAK;gBAChD,MAAMX,aAAa,IAAI,CAAC,WAAW,CAACW,EAAE;gBACtCP,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO,CAAC,kBAAkB,EAAEO,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE;gBAE9D,MAAM,EAAEyB,gBAAgB,EAAE,GAAGpC;gBAC7B,IAAId,aAAa,IAAI,CAAC,qBAAqB,CACzCkD,iBAAiB,SAAS,EAC1BA,iBAAiB,eAAe;gBAElC,IAAIC,gBAAgB,CAAC,aAAa,EAAE1B,GAAG;gBAEvC,IAAIX,WAAW,cAAc,EAAE;oBAC7B,IAAIqB,gBAAgB,CAACV,EAAE,EAAE;wBAIvB,MAAM2B,YAAYxE,mCAAAA,OAAY,CAACkC,WAAW,cAAc;wBACxD,MAAMuC,iBAAiBzE,mCAAAA,IAAS,CAACwE,WAAW;wBAC5C,IAAItE,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWuE,iBAAiB;4BAC9B,MAAMC,uBAAuB1E,mCAAAA,IAAS,CACpCA,mCAAAA,OAAY,CAAC4D,iBACb;4BAEFN,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUoB,sBAAsB;gCAAE,WAAW;4BAAK;4BAClD,KAAK,MAAMC,QAAQC,AAAAA,IAAAA,iCAAAA,WAAAA,AAAAA,EAAYH,gBAAiB;gCAC9C,MAAMI,MAAM7E,mCAAAA,IAAS,CAACyE,gBAAgBE;gCACtC,MAAMG,OAAO9E,mCAAAA,IAAS,CAAC0E,sBAAsBC;gCAC7CI,IAAAA,iCAAAA,YAAAA,AAAAA,EAAaF,KAAKC;4BACpB;wBACF;oBACF,OAEEE,AAAAA,IAAAA,8BAAAA,wBAAAA,AAAAA,EACE9C,WAAW,cAAc,EACzB0B,gBACAS;oBAUJ,MAAMY,WAAWC,AAAAA,IAAAA,8BAAAA,yBAAAA,AAAAA,EACfhD,WAAW,cAAc,EACzB,MAAM,CAAC,CAACiD,IAAMA,EAAE,OAAO,CAAC,QAAQ,CAAC;oBACnC,MAAMC,eAAeH,QAAQ,CAAC,EAAE,EAAE,QAAQ,MACxC;oBAEF,IAAIG,cACFb,gBAAgBc,mBAAmBD,YAAY,CAAC,EAAE;oBAEpD,MAAME,sBACJL,SAAS,MAAM,GAAG,IACd,IAAI,CAAC,gBAAgB,CAACA,SAAS,GAAG,CAAC,CAACE,IAAMA,EAAE,OAAO,KACnDnE,AAAAA,IAAAA,8BAAAA,yBAAAA,AAAAA,EAA0BkB,WAAW,cAAc;oBACzD,IAAIoD,qBACFlE,aAAakE;gBAEjB;gBAEA,MAAMC,cAAcpE,wBAAwBC;gBAC5C,IAAImE,aACFnB,aAAa,IAAI,CAACmB;gBAGpB,MAAMC,gBAAgB,GAAGC,AAAAA,IAAAA,kCAAAA,iBAAAA,AAAAA,EACvB;oBACErE;oBACA,YAAY;wBACV,iBAAiBmD;wBACjB,CAAC/E,8BAAAA,yBAAyBA,CAAC,EAAEiE,yBACzB,cACA;wBACJ,0BAA0Ba,iBAAiB,YAAY;wBACvD,wBAAwBA,iBAAiB,UAAU;wBACnD,uBAAuBA,iBAAiB,SAAS;wBACjD,oBAAoBA,iBAAiB,MAAM;wBAC3C,6BAA6BA,iBAAiB,eAAe;wBAC7D,WAAW;oBACb;gBACF,GACAoB,QACAA,QACA,OACA,EAAE,CAAC;gBAELxB,IAAAA,iCAAAA,cAAAA,AAAAA,EAAeN,gBAAgB4B;YACjC;YAEA,MAAMG,eAAepE,yBAAyB6C;YAC9C,IAAIuB,cACFzB,AAAAA,IAAAA,iCAAAA,cAAAA,AAAAA,EAAeN,gBAAgB+B;YAIjCzB,IAAAA,iCAAAA,cAAAA,AAAAA,EAAeN,gBAAgB,GAAGC,WAAW,EAAE,CAAC;YAEhDvB,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO,CAAC,gCAAgC,EAAEsB,gBAAgB;YAG1D,IAAIX,mBAAmB;gBACrB,IAAI2C,qBAAqB;gBACzB,IAAIC,0BAA0B;gBAC9B,KAAK,MAAMrC,QAAQ,IAAI,CAAC,WAAW,CACjC,IAAKA,KAAK,cAAc;oBACxBqC,2BAA2B;oBAC3B,IAAI;wBACFzF,qBAAqBoD,KAAK,cAAc;wBACxCoC,sBAAsB;oBACxB,EAAE,OAAOE,OAAO;wBACdxD,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO,CAAC,sBAAsB,EAAEkB,KAAK,cAAc,CAAC,EAAE,EAAEsC,OAAO;oBACjE;;gBAEFxD,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAAC,QAAQ,EAAEsD,mBAAmB,CAAC,EAAEC,wBAAwB,iBAAiB,CAAC;YAE/E;YACA,OAAOjC;QACT,EAAE,OAAOkC,OAAO;YACdxD,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO,CAAC,uBAAuB,EAAEwD,OAAO;YACxC,MAAMA;QACR;IACF;;QA1RA,uBAAQ,eAA0C,EAAE;;AA2RtD;AAOA,MAAMC,4BAA4B,IAA6B;QAC7D,gBAAgB;QAChB,aAAa;QACb,cAAc;QACd,mBAAmB;QACnB,kBAAkB;QAClB,aAAa;IACf;AAEA,MAAMC,gCAAgC,CAACC;IACrC,IACE,CAACA,YACDA,AAAa,QAAbA,YACAA,AAAa,SAAbA,YACAjG,mCAAAA,QAAa,CAACiG,cAAcA,YAC5BA,SAAS,QAAQ,CAAC,UAElB,MAAM,IAAI9D,MACR,CAAC,4EAA4E,EAAE8D,UAAU;AAG/F;AAEA,MAAMC,6BAA6B,CACjCC;IAEA,MAAMC,SAAS,IAAIzF;IACnB,MAAM0F,oBAAoB,IAAI1F;IAE9B,KAAK,MAAM2F,UAAUH,QAAS;QAC5B,MAAMI,UAAUD,OAAO,OAAO,CAAC,IAAI;QACnC,MAAME,aAAaxG,mCAAAA,OAAY,CAACsG,OAAO,UAAU;QACjD,IAAI,CAACC,SACH,MAAM,IAAIpE,MAAM;QAGlB,MAAMsE,gBAAgBJ,kBAAkB,GAAG,CAACG;QAC5C,IAAIC,iBAAiBA,kBAAkBF,SACrC,MAAM,IAAIpE,MACR,CAAC,uDAAuD,EAAEsE,cAAc,EAAE,EAAEF,QAAQ,GAAG,EAAEC,YAAY;QAGzGH,kBAAkB,GAAG,CAACG,YAAYD;QAClCH,OAAO,GAAG,CAAC,GAAGG,QAAQ,MAAM,EAAEC,YAAY,EAAE;YAAED;YAASC;QAAW;IACpE;IAEA,OAAO;WAAIJ,OAAO,MAAM;KAAG;AAC7B;AAEA,MAAMM,8BAA8B,CAClCP;IAKA,MAAMQ,WAA0C,EAAE;IAClD,MAAMC,UAAUb;IAChB,MAAMc,yBAAyB,IAAIlG;IAEnC,KAAK,MAAM,CAACmG,aAAaR,OAAO,IAAIJ,2BAClCC,SACA,OAAO,GAAI;QACX,IAAI,CAACjG,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWoG,OAAO,UAAU,GAC/B,MAAM,IAAInE,MAAM,CAAC,6BAA6B,EAAEmE,OAAO,UAAU,EAAE;QAGrE,MAAMlE,gBAAgBtB,qBAAqBwF,OAAO,UAAU;QAC5D,MAAMjE,iBAAiBP,AAAAA,IAAAA,kCAAAA,UAAAA,AAAAA;QACvB,IACEM,iBACAC,kBACAD,kBAAkBC,kBAClB,CAACpB,yBAAyB,GAAG,CAACmB,gBAC9B;YACAnB,yBAAyB,GAAG,CAACmB;YAC7BE,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAAC,sGAAsG,EAAEF,cAAc,qCAAqC,EAAEC,eAAe,kFAAkF,CAAC;QAEpQ;QAEA,MAAM0E,WAAW,CAAC,cAAc,EAAED,cAAc,GAAG;QACnD,MAAM,EAAEE,QAAQ,EAAExG,UAAU,EAAE,GAAGyG,yBAC/BX,OAAO,UAAU;QAEnB,MAAMY,eAAyB,EAAE;QACjC,KAAK,MAAMC,aAAa3G,WAAY;YAClC,IAAI,CAAC2G,UAAU,EAAE,EAAE;YACnB,MAAMC,kBAAkB,GAAGd,OAAO,OAAO,CAAC,MAAM,EAAEa,UAAU,EAAE,EAAE;YAChE,MAAME,gBAAgBR,uBAAuB,GAAG,CAACO;YACjD,IAAIC,iBAAiBA,kBAAkBN,UACrC,MAAM,IAAI5E,MACR,CAAC,gBAAgB,EAAEgF,UAAU,EAAE,CAAC,+CAA+C,EAAEb,OAAO,OAAO,CAAC,EAAE,EAAEe,cAAc,EAAE,EAAEN,UAAU;YAGpIF,uBAAuB,GAAG,CAACO,iBAAiBL;YAC5CG,aAAa,IAAI,CAACC,UAAU,EAAE;QAChC;QAEA,MAAMpG,OAAO,IAAIO,kCAAAA,gBAAgBA,CAAC;YAChC,YAAY0F,SAAS,UAAU;YAC/B,WAAWA,SAAS,SAAS;YAC7B,kBAAkBA,SAAS,gBAAgB;YAC3C,aAAaA,SAAS,WAAW;YACjC,YAAYA,SAAS,UAAU;YAC/BxG;QACF;QACA,MAAM8G,gBAAgBC,AAAAA,IAAAA,yCAAAA,oBAAAA,AAAAA,EAAqBxG;QAC3C6F,QAAQ,cAAc,IAAIU,cAAc,MAAM,CAAC,cAAc;QAC7DV,QAAQ,WAAW,IAAIU,cAAc,MAAM,CAAC,eAAe;QAC3DV,QAAQ,YAAY,IAAIU,cAAc,MAAM,CAAC,YAAY;QACzDV,QAAQ,iBAAiB,IAAIU,cAAc,MAAM,CAAC,iBAAiB;QACnEV,QAAQ,gBAAgB,IAAIU,cAAc,MAAM,CAAC,gBAAgB;QACjEV,QAAQ,WAAW,IAAIU,cAAc,MAAM,CAAC,WAAW;QAEvDX,SAAS,IAAI,CAAC;YACZI;YACA,SAAST,OAAO,OAAO;YACvB,YAAYA,OAAO,UAAU;YAC7BY;YACAnG;YACA,eAAehB,sBAAsBuG,OAAO,UAAU;QACxD;IACF;IAEA,OAAO;QAAE,SAASK;QAAUC;IAAQ;AACtC;AAEA,MAAMY,mBAAmB,CAACzG;IACxB,MAAM0G,WAAW;IACjB,OAEE,mBACAC,4CAAAA,2BAA2BA,GAC3B,SACAC,AAAAA,IAAAA,sBAAAA,eAAAA,AAAAA,EAAgBC,KAAK,SAAS,CAAC7G,SAC/B,OACA0G,WACA;AAEJ;AASO,MAAMI;IACJ,SAASC,OAAqC,EAAU;QAC7D9B,8BAA8B8B,QAAQ,cAAc;QACpD,MAAM3E,YAAYnD,mCAAAA,OAAY,CAAC8H,QAAQ,SAAS;QAChDxE,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUH,WAAW;YAAE,WAAW;QAAK;QAEvC,MAAMwD,WAAWD,4BAA4BoB,QAAQ,OAAO;QAC5D,MAAMC,QAAkC;YACtC,SAASpB,SAAS,OAAO,CAAC,GAAG,CAC3B,CAAC,EAAEI,QAAQ,EAAER,OAAO,EAAEC,UAAU,EAAEU,YAAY,EAAE,GAAM;oBACpDH;oBACAR;oBACAC;oBACAU;gBACF;YAEF,SAASP,SAAS,OAAO;QAC3B;QACA,MAAMqB,aAAaF,QAAQ,eAAe,CAACC;QAC3C,IAAIC,AAA6B,MAA7BA,WAAW,aAAa,IAAUA,AAAoB,kBAApBA,WAAW,IAAI,EACnD,MAAM,IAAI7F,MACR;QAIJyF,KAAK,SAAS,CAACI;QAEf,MAAMC,gBAAgBtB,SAAS,OAAO,CAAC,IAAI,CACzC,CAACL,SAAWA,OAAO,aAAa;QAElC,MAAM4B,oBAAoBlI,mCAAAA,IAAS,CAACmD,WAAW2E,QAAQ,cAAc;QACrE,MAAMK,sBAAsBnI,mCAAAA,IAAS,CAACkI,mBAAmB;QACzD,MAAME,uBAAuB,GAAGF,kBAAkB,KAAK,CAAC;QACxD,MAAMG,kBAAkBJ,gBACpBE,sBACAC;QACJ,MAAME,oBAAoB;YAACJ;YAAmBE;SAAqB,CAAC,MAAM,CACxElI,iCAAAA,UAAUA;QAEZ,IAAIoI,kBAAkB,MAAM,GAAG,KAAK,CAACR,QAAQ,SAAS,EACpD,MAAM,IAAI3F,MACR,CAAC,gCAAgC,EAAEmG,iBAAiB,CAAC,EAAE,CAAC,iDAAiD,CAAC;QAI9G,MAAMC,gBAAgBC,AAAAA,IAAAA,iCAAAA,WAAAA,AAAAA,EACpBxI,mCAAAA,IAAS,CAACmD,WAAW;QAEvB,MAAMsF,wBAAwBzI,mCAAAA,IAAS,CACrCuI,eACAT,QAAQ,cAAc;QAExB,MAAMY,sBAAsBT,gBACxBjI,mCAAAA,IAAS,CAACyI,uBAAuB,gBACjC,GAAGA,sBAAsB,KAAK,CAAC;QAEnC,IAAI;YACF,IAAIR,eACF3E,AAAAA,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUmF,uBAAuB;gBAAE,WAAW;YAAK;YAGrD,MAAM5E,aAAa;YACnB,MAAM8E,WAAW5E,AAAAA,IAAAA,kCAAAA,YAAAA,AAAAA;YACjB,MAAM6E,eAAeD,SAAS,WAAW,CAAC9E;YAC1CK,IAAAA,iCAAAA,cAAAA,AAAAA,EACEwE,qBACAE,AAAiB,OAAjBA,eAAsBD,WAAWA,SAAS,KAAK,CAAC,GAAGC;YAErD,IAAIX,eACF/D,AAAAA,IAAAA,iCAAAA,cAAAA,AAAAA,EAAewE,qBAAqBvE,AAAAA,IAAAA,8BAAAA,mBAAAA,AAAAA;YAGtC,MAAMC,eAAmC,EAAE;YAC3C,KAAK,MAAMkC,UAAUK,SAAS,OAAO,CAAE;gBACrC,IAAIL,OAAO,aAAa,EAAE;oBACxB,MAAM7B,iBAAiBzE,mCAAAA,IAAS,CAC9BA,mCAAAA,OAAY,CAACsG,OAAO,UAAU,GAC9B;oBAEF,IAAIpG,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWuE,iBAAiB;wBAC9B,MAAMoE,uBAAuB7I,mCAAAA,IAAS,CACpCA,mCAAAA,OAAY,CAAC0I,sBACb;wBAEFpF,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUuF,sBAAsB;4BAAE,WAAW;wBAAK;wBAClD,KAAK,MAAMlE,QAAQC,AAAAA,IAAAA,iCAAAA,WAAAA,AAAAA,EAAYH,gBAC7BM,AAAAA,IAAAA,iCAAAA,YAAAA,AAAAA,EACE/E,mCAAAA,IAAS,CAACyE,gBAAgBE,OAC1B3E,mCAAAA,IAAS,CAAC6I,sBAAsBlE;oBAGtC;gBACF,OACEK,AAAAA,IAAAA,8BAAAA,wBAAAA,AAAAA,EAAyBsB,OAAO,UAAU,EAAEoC;gBAG9CtE,aAAa,IAAI,CAACkC,OAAO,IAAI;gBAC7BpC,IAAAA,iCAAAA,cAAAA,AAAAA,EACEwE,qBACA,GAAGjD,AAAAA,IAAAA,kCAAAA,iBAAAA,AAAAA,EACD;oBACE,YAAYa,OAAO,IAAI,CAAC,SAAS;oBACjC,YAAY;wBACV,iBAAiBA,OAAO,QAAQ;wBAChC,kBAAkBA,OAAO,QAAQ;wBACjC,wBAAwBA,OAAO,OAAO;wBACtC,CAAC9G,8BAAAA,yBAAyBA,CAAC,EAAEyI,gBACzB,cACA;oBACN;gBACF,GACAvC,QACAA,QACA,OACA,EAAE,CAAC;YAET;YAEAxB,IAAAA,iCAAAA,cAAAA,AAAAA,EAAewE,qBAAqBlB,iBAAiBQ;YACrD,MAAMrC,eAAepE,yBAAyB6C;YAC9C,IAAIuB,cACFzB,AAAAA,IAAAA,iCAAAA,cAAAA,AAAAA,EAAewE,qBAAqB/C;YAEtCzB,IAAAA,iCAAAA,cAAAA,AAAAA,EAAewE,qBAAqB,GAAG7E,WAAW,EAAE,CAAC;YAErD,IAAI3D,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWgI,oBACb7H,AAAAA,IAAAA,iCAAAA,MAAAA,AAAAA,EAAO6H,mBAAmB;gBAAE,WAAW;gBAAM,OAAO;YAAK;YAE3D,IAAIhI,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWkI,uBACb9H,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAW8H;YAEbU,IAAAA,iCAAAA,UAAAA,AAAAA,EACEb,gBAAgBQ,wBAAwBC,qBACxCT,gBAAgBC,oBAAoBE;YAEtC/H,IAAAA,iCAAAA,MAAAA,AAAAA,EAAOkI,eAAe;gBAAE,WAAW;gBAAM,OAAO;YAAK;YACrD,OAAOF;QACT,EAAE,OAAOvC,OAAO;YACdzF,IAAAA,iCAAAA,MAAAA,AAAAA,EAAOkI,eAAe;gBAAE,WAAW;gBAAM,OAAO;YAAK;YACrD,MAAMzC;QACR;IACF;AACF;AAsBO,SAASmB,yBACd8B,QAAgB;IAEhB,IAAI/B,WAAoC;IACxC,IAAIgC,kBAAkB;IACtB,MAAMC,4BAA4B,IAAItI;IAEtCf,IAAAA,8BAAAA,qBAAAA,AAAAA,EAAsBmJ,UAAU,CAACG;QAC/B,IAAI,CAACA,WAAW,OAAO,CAAC,QAAQ,CAAC,kBAC/B,OAAO;QAET,MAAMC,cAAc7H,kCAAAA,gBAAAA,CAAAA,oBAAqC,CACvDoB,AAAAA,IAAAA,sBAAAA,mBAAAA,AAAAA,EAAoBwG,WAAW,OAAO;QAExC,KAAK,MAAM/B,aAAagC,YAAY,UAAU,CAAE;YAC9CH,mBAAmB;YACnB,IAAI7B,UAAU,EAAE,EACd8B,0BAA0B,GAAG,CAAC9B,UAAU,EAAE,EAAE6B;QAEhD;QACA,OAAO;IACT;IAEA,MAAMxI,aAA+B,EAAE;IACvCwI,kBAAkB;IAClBpJ,IAAAA,8BAAAA,qBAAAA,AAAAA,EAAsBmJ,UAAU,CAACG;QAC/B,IAAI,CAACA,WAAW,OAAO,CAAC,QAAQ,CAAC,kBAC/B,OAAO;QAGT,MAAMC,cAAc7H,kCAAAA,gBAAAA,CAAAA,oBAAqC,CACvDoB,AAAAA,IAAAA,sBAAAA,mBAAAA,AAAAA,EAAoBwG,WAAW,OAAO;QAExC,IAAI,CAAClC,UACHA,WAAWmC;QAGb,KAAK,MAAMhC,aAAagC,YAAY,UAAU,CAAE;YAC9CH,mBAAmB;YACnB,IACE7B,CAAAA,UAAU,EAAE,IACZ8B,0BAA0B,GAAG,CAAC9B,UAAU,EAAE,MAAM6B,iBAIlDxI,WAAW,IAAI,CAAC2G;QAClB;QAEA,OAAO;IACT;IAEA,IAAI,CAACH,UACH,MAAM,IAAI7E,MAAM,CAAC,gCAAgC,EAAE4G,UAAU;IAG/D,OAAO;QACL/B;QACAxG;IACF;AACF;AAEA,SAAS4I,6BACPjC,SAAyB,EACzBnE,IAIC;IAED,MAAMqG,QAAQ,CAACC;QACb,IAAIzI,MAAM,OAAO,CAACyI,OAAO;YACvB,KAAK,MAAMC,QAAQD,KACjBD,MAAME;YAER;QACF;QAEA,IAAI,AAAgB,YAAhB,OAAOD,QAAqBA,AAAS,SAATA,MAAe;QAE/C,MAAME,MAAMC,AAAAA,IAAAA,mCAAAA,uBAAAA,AAAAA,EAAwBH;QACpC,IAAIE,KAAK;YACP,MAAME,MAAMC,AAAAA,IAAAA,mCAAAA,qBAAAA,AAAAA,EAAsBH;YAClC,MAAMvD,WAAW,GAAGuD,IAAI,EAAE,CAAC,CAAC,EAAEE,KAAK;YACnC,MAAME,eAAe,CAAC,cAAc,EAAE3D,UAAU;YAChD,MAAM4D,eAAe7J,mCAAAA,IAAS,CAACgD,KAAK,cAAc,EAAEiD;YAEpD,IAAI,CAACjD,KAAK,YAAY,CAAC,GAAG,CAACiD,WAAW;gBACpC,MAAM6D,WAAWC,AAAAA,IAAAA,oCAAAA,kBAAAA,AAAAA,EAAmBP,KAAK;oBACvC,YAAYxG,KAAK,QAAQ;gBAC3B;gBACA,IAAI8G,AAAkB,eAAlBA,SAAS,IAAI,EAAiB;oBAChC,MAAM,EAAEE,SAAS,EAAE,GAAGC,AAAAA,IAAAA,oCAAAA,uBAAAA,AAAAA,EAAwBH,SAAS,OAAO;oBAC9DI,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcL,cAAcM,OAAO,IAAI,CAACH,WAAW;gBACrD,OACEjF,AAAAA,IAAAA,iCAAAA,YAAAA,AAAAA,EAAa+E,SAAS,QAAQ,EAAED;gBAElC7G,KAAK,YAAY,CAAC,GAAG,CAACiD;YACxB;YAEAuD,IAAI,OAAO,GAAG;YACdA,IAAI,IAAI,GAAGI;YACX;QACF;QAEA,KAAK,MAAMQ,SAASlL,OAAO,MAAM,CAACoK,MAChCD,MAAMe;IAEV;IAEAf,MAAMlC;AACR;AAMO,SAASkD,2BACdvC,OAA+B;IAE/B,MAAM,EAAEiB,QAAQ,EAAE5F,SAAS,EAAE,GAAG2E;IAChC,MAAMrD,iBAAiBzE,mCAAAA,IAAS,CAACmD,WAAW;IAE5CG,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUH,WAAW;QAAE,WAAW;IAAK;IACvCG,IAAAA,iCAAAA,SAAAA,AAAAA,EAAUmB,gBAAgB;QAAE,WAAW;IAAK;IAE5C,MAAM6F,qBAA+B,EAAE;IACvC,MAAMC,yBAAyB,IAAIrJ;IACnC,MAAM,EAAE8F,QAAQ,EAAExG,UAAU,EAAE,GAAGyG,yBAAyB8B;IAE1D,IAAIyB,YAAY;IAChB,KAAK,MAAMrD,aAAa3G,WAAY;QAClCgK,aAAa;QACbpB,6BAA6BjC,WAAW;YACtC4B;YACAtE;YACA,cAAc8F;QAChB;QACA,MAAME,sBAAsB,IAAInJ,kCAAAA,gBAAgBA,CAAC;YAC/C,YAAY0F,SAAS,UAAU;YAC/B,WAAWA,SAAS,SAAS;YAC7B,kBAAkBA,SAAS,gBAAgB;YAC3C,aAAaA,SAAS,WAAW;YACjC,YAAYA,SAAS,UAAU;YAC/B,YAAY;gBAACG;aAAU;QACzB;QAEA,MAAMuD,eAAe1K,mCAAAA,IAAS,CAACmD,WAAW,GAAGqH,UAAU,eAAe,CAAC;QACvEN,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcQ,cAAcD,oBAAoB,SAAS,CAAC,IAAI;QAC9DH,mBAAmB,IAAI,CAACI;IAC1B;IAEA,OAAO;QACLJ;QACA,iBAAiBzJ,MAAM,IAAI,CAAC0J,wBACzB,IAAI,GACJ,GAAG,CAAC,CAACtE,WAAajG,mCAAAA,IAAS,CAACyE,gBAAgBwB;IACjD;AACF"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ TEST_RUN_REPORT_SCRIPT_TYPE: ()=>TEST_RUN_REPORT_SCRIPT_TYPE
28
+ });
29
+ const TEST_RUN_REPORT_SCRIPT_TYPE = 'midscene_test_run_dump';
30
+ exports.TEST_RUN_REPORT_SCRIPT_TYPE = __webpack_exports__.TEST_RUN_REPORT_SCRIPT_TYPE;
31
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
32
+ "TEST_RUN_REPORT_SCRIPT_TYPE"
33
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
34
+ Object.defineProperty(exports, '__esModule', {
35
+ value: true
36
+ });
37
+
38
+ //# sourceMappingURL=test-run-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-run-report.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/test-run-report.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","export const TEST_RUN_REPORT_SCRIPT_TYPE = 'midscene_test_run_dump';\n\nexport type TestRunReportRunStatus = 'success' | 'failed';\nexport type TestRunReportCaseStatus = TestRunReportRunStatus | 'not-run';\nexport type TestRunReportStepPhase =\n | 'beforeAll'\n | 'beforeEach'\n | 'steps'\n | 'afterEach'\n | 'afterAll';\n\n/**\n * A JSON-safe value prepared for display in a Midscene Test report.\n *\n * Paths use JSONPath-like notation rooted at `$`. The path arrays are kept\n * beside the value so the UI never presents redacted or truncated data as if\n * it were complete.\n */\nexport interface TestRunReportValue {\n value: unknown;\n truncatedPaths?: string[];\n redactedPaths?: string[];\n}\n\nexport interface TestRunReportError {\n name: string;\n message: string;\n code?: string;\n details?: TestRunReportValue;\n}\n\nexport interface TestRunReportDiagnostic {\n level: 'warning' | 'error';\n code:\n | 'agent-detail-unresolved'\n | 'agent-detail-unavailable'\n | 'large-report'\n | 'source-without-executions';\n message: string;\n scopeId?: string;\n executionId?: string;\n sourcePaths?: string[];\n}\n\nexport interface TestRunReportMetrics {\n modelCallCount: number;\n modelTimeMs: number;\n promptTokens: number;\n cachedInputTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\nexport interface TestRunReportAgentDetail {\n reportId: string;\n executionId: string;\n}\n\nexport interface TestRunReportStep {\n id: string;\n phase: TestRunReportStepPhase;\n stepIndex: number;\n node: string;\n title?: string;\n status: TestRunReportRunStatus;\n continuedAfterError: boolean;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n input?: TestRunReportValue;\n output?: {\n summary?: string;\n data?: TestRunReportValue;\n };\n error?: TestRunReportError;\n agentDetails?: TestRunReportAgentDetail[];\n agentDetailDiagnostic?: string;\n}\n\nexport interface TestRunReportAttempt {\n attemptId: string;\n attemptIndex: number;\n status: TestRunReportRunStatus;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n beforeEach: TestRunReportStep[];\n steps: TestRunReportStep[];\n afterEach: TestRunReportStep[];\n teardownErrors?: TestRunReportError[];\n /** Report groups available for scope-level fallback browsing. */\n scopeReportIds?: string[];\n}\n\nexport interface TestRunReportCase {\n caseId: string;\n name: string;\n caseIndex: number;\n status: TestRunReportCaseStatus;\n notRunReason?: string;\n attempts: TestRunReportAttempt[];\n}\n\nexport interface TestRunReportDocument {\n documentId: string;\n sourcePath: string;\n status: TestRunReportRunStatus;\n startedAt?: string;\n endedAt?: string;\n durationMs?: number;\n beforeAll: TestRunReportStep[];\n cases: TestRunReportCase[];\n afterAll: TestRunReportStep[];\n teardownErrors?: TestRunReportError[];\n /** Report groups available for scope-level fallback browsing. */\n scopeReportIds?: string[];\n}\n\nexport interface TestRunReportCollectionError {\n sourcePath: string;\n error: TestRunReportError;\n}\n\nexport interface TestRunReportProjectLifecycle {\n status: TestRunReportRunStatus;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n setupError?: TestRunReportError;\n teardownErrors?: TestRunReportError[];\n}\n\nexport interface TestRunReportProject {\n projectId: string;\n name: string;\n platform: 'web' | 'android' | 'ios' | 'computer' | 'harmony';\n status: TestRunReportRunStatus;\n retry: number;\n lifecycle?: TestRunReportProjectLifecycle;\n documents: TestRunReportDocument[];\n collectionErrors: TestRunReportCollectionError[];\n}\n\nexport interface TestRunReportSummary {\n total: number;\n passed: number;\n failed: number;\n notRun: number;\n filtered: number;\n collectionErrors: number;\n documentFailures: number;\n projectFailures: number;\n}\n\nexport interface TestRunReportDump {\n schemaVersion: 1;\n kind: 'test-runner';\n runId: string;\n status: TestRunReportRunStatus;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n summary: TestRunReportSummary;\n metrics: TestRunReportMetrics;\n projects: TestRunReportProject[];\n diagnostics?: TestRunReportDiagnostic[];\n}\n\nexport interface TestRunReportSource {\n /** Runner Attempt runId or Document documentRunId. */\n scopeId: string;\n /** Absolute path to a finalized Midscene Agent report. */\n sourcePath: string;\n}\n\nexport interface IndexedTestRunReportSource {\n reportId: string;\n scopeId: string;\n sourcePath: string;\n executionIds: string[];\n}\n\nexport interface TestRunReportSourceIndex {\n sources: IndexedTestRunReportSource[];\n metrics: TestRunReportMetrics;\n}\n\nexport interface AssembleTestRunReportOptions {\n outputDir: string;\n /** File or directory name without an extension. */\n reportFileName: string;\n sources: readonly TestRunReportSource[];\n buildRunnerDump(index: TestRunReportSourceIndex): TestRunReportDump;\n overwrite?: boolean;\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","TEST_RUN_REPORT_SCRIPT_TYPE"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;ACNO,MAAMI,8BAA8B"}
package/dist/lib/utils.js CHANGED
@@ -228,7 +228,7 @@ function stringifyDumpData(data, indents) {
228
228
  return JSON.stringify(data, replacerForPageObject, indents);
229
229
  }
230
230
  function getVersion() {
231
- return "1.12.5";
231
+ return "1.12.6-beta-20260909034232.0";
232
232
  }
233
233
  function debugLog(...message) {
234
234
  const debugMode = process.env[env_namespaceObject.MIDSCENE_DEBUG_MODE];
@@ -230,7 +230,7 @@ class ScriptPlayer {
230
230
  let msNumber = ms;
231
231
  if ('string' == typeof ms) msNumber = Number.parseInt(ms, 10);
232
232
  (0, utils_namespaceObject.assert)(msNumber && msNumber > 0, `ms for sleep must be greater than 0, but got ${ms}`);
233
- await new Promise((resolve)=>setTimeout(resolve, msNumber));
233
+ await agent.sleep(msNumber);
234
234
  } else if ("javascript" in flowItem) {
235
235
  const evaluateJavaScriptTask = flowItem;
236
236
  const result = await agent.evaluateJavaScript(evaluateJavaScriptTask.javascript);