@testrelic/maestro-analytics 1.2.0-next.52 → 1.2.0-next.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -1,5 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
3
25
 
4
26
  // src/config.ts
5
27
  var import_core2 = require("@testrelic/core");
@@ -1321,8 +1343,8 @@ function discoverFlowFiles(dir) {
1321
1343
  var import_node_fs8 = require("fs");
1322
1344
  var import_node_path7 = require("path");
1323
1345
  var import_node_fs9 = require("fs");
1324
- var LOG_LINE_REGEX = /^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)\s+(\w+)\s+(.+)$/;
1325
- var TIMESTAMP_ONLY_REGEX = /^\[?(\d{2}:\d{2}:\d{2}(?:\.\d+)?)\]?\s+(\w+)\s+(.+)$/;
1346
+ var LOG_LINE_REGEX = /^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)\s+\[?\s*(\w+)\s*\]?\s+(.+)$/;
1347
+ var TIMESTAMP_ONLY_REGEX = /^\[?(\d{2}:\d{2}:\d{2}(?:\.\d+)?)\]?\s+\[?\s*(\w+)\s*\]?\s+(.+)$/;
1326
1348
  function parseLevel(raw) {
1327
1349
  const upper = raw.toUpperCase();
1328
1350
  if (upper === "DEBUG" || upper === "TRACE" || upper === "VERBOSE") return "DEBUG";
@@ -1331,10 +1353,31 @@ function parseLevel(raw) {
1331
1353
  if (upper === "ERROR" || upper === "FATAL" || upper === "SEVERE") return "ERROR";
1332
1354
  return "INFO";
1333
1355
  }
1334
- function parseLogContent(content) {
1356
+ function buildEntryTimestamp(dateAnchor, hhmmss) {
1357
+ const m = /^(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/.exec(hhmmss);
1358
+ if (!m) {
1359
+ return (/* @__PURE__ */ new Date()).toISOString();
1360
+ }
1361
+ const h = Number(m[1]);
1362
+ const mi = Number(m[2]);
1363
+ const s = Number(m[3]);
1364
+ const ms = m[4] ? Number(m[4].padEnd(3, "0")) : 0;
1365
+ const local = new Date(
1366
+ dateAnchor.getFullYear(),
1367
+ dateAnchor.getMonth(),
1368
+ dateAnchor.getDate(),
1369
+ h,
1370
+ mi,
1371
+ s,
1372
+ ms
1373
+ );
1374
+ return local.toISOString();
1375
+ }
1376
+ function parseLogContent(content, defaultDate) {
1335
1377
  const entries = [];
1336
1378
  const lines = content.split("\n");
1337
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1379
+ const anchorDate = defaultDate instanceof Date ? defaultDate : null;
1380
+ const dateAnchorStr = typeof defaultDate === "string" ? defaultDate : defaultDate instanceof Date ? `${defaultDate.getFullYear()}-${String(defaultDate.getMonth() + 1).padStart(2, "0")}-${String(defaultDate.getDate()).padStart(2, "0")}` : (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1338
1381
  for (const line2 of lines) {
1339
1382
  const trimmed = line2.trim();
1340
1383
  if (!trimmed) continue;
@@ -1350,8 +1393,9 @@ function parseLogContent(content) {
1350
1393
  }
1351
1394
  match = TIMESTAMP_ONLY_REGEX.exec(trimmed);
1352
1395
  if (match) {
1396
+ const ts = anchorDate ? buildEntryTimestamp(anchorDate, match[1]) : `${dateAnchorStr}T${match[1]}`;
1353
1397
  entries.push({
1354
- timestamp: `${today}T${match[1]}`,
1398
+ timestamp: ts,
1355
1399
  level: parseLevel(match[2]),
1356
1400
  message: match[3],
1357
1401
  source: null
@@ -1368,10 +1412,10 @@ function parseLogContent(content) {
1368
1412
  }
1369
1413
  return entries;
1370
1414
  }
1371
- function parseLogFile(filePath) {
1415
+ function parseLogFile(filePath, defaultDate) {
1372
1416
  try {
1373
1417
  const content = (0, import_node_fs8.readFileSync)(filePath, "utf-8");
1374
- return parseLogContent(content);
1418
+ return parseLogContent(content, defaultDate);
1375
1419
  } catch {
1376
1420
  return [];
1377
1421
  }
@@ -4563,10 +4607,13 @@ function extractRecordingPath(commands) {
4563
4607
  }
4564
4608
  return null;
4565
4609
  }
4610
+ function normaliseCommandFileName(filePath) {
4611
+ return (0, import_node_path16.basename)(filePath).replace(/^commands[-_]?/i, "").replace(/\.json$/i, "").replace(/^\(/, "").replace(/\)$/, "").toLowerCase();
4612
+ }
4566
4613
  function buildFlowRecordingMap(commandSteps) {
4567
4614
  const map = /* @__PURE__ */ new Map();
4568
4615
  for (const [filePath, commands] of commandSteps) {
4569
- const name = (0, import_node_path16.basename)(filePath).replace(/^commands[-_]?/i, "").replace(/\.json$/i, "").toLowerCase();
4616
+ const name = normaliseCommandFileName(filePath);
4570
4617
  const recPath = extractRecordingPath(commands);
4571
4618
  if (recPath && name) map.set(name, recPath);
4572
4619
  }
@@ -4577,7 +4624,7 @@ function commandsForFlow(commandSteps, flowFile) {
4577
4624
  if (!flowBase || commandSteps.size === 0) {
4578
4625
  return { commands: [], matchedAnyFile: false };
4579
4626
  }
4580
- const stripCmdPrefix = (p) => (0, import_node_path16.basename)(p, (0, import_node_path16.extname)(p)).replace(/^commands[-_]?/i, "").toLowerCase();
4627
+ const stripCmdPrefix = (p) => normaliseCommandFileName(p);
4581
4628
  for (const [cmdFile, cmds] of commandSteps) {
4582
4629
  if (stripCmdPrefix(cmdFile) === flowBase) {
4583
4630
  return { commands: cmds, matchedAnyFile: true };
@@ -4662,7 +4709,13 @@ async function orchestrateReport(input) {
4662
4709
  const logFiles = input.debugOutputDir ? discoverLogFiles(input.debugOutputDir) : artifacts.logPaths;
4663
4710
  const allLogEntries = [];
4664
4711
  for (const logFile of logFiles) {
4665
- const entries = parseLogFile(logFile);
4712
+ let mtimeDate;
4713
+ try {
4714
+ const { statSync: statSync5 } = await import("fs");
4715
+ mtimeDate = statSync5(logFile).mtime;
4716
+ } catch {
4717
+ }
4718
+ const entries = parseLogFile(logFile, mtimeDate);
4666
4719
  if (entries.length > 0) allLogEntries.push(...entries);
4667
4720
  }
4668
4721
  let platform = input.platform ?? "unknown";
@@ -4703,14 +4756,19 @@ async function orchestrateReport(input) {
4703
4756
  const meta = flowMetadataMap.get(name);
4704
4757
  const status = testCase.status === "SUCCESS" ? "passed" : testCase.status === "SKIPPED" ? "skipped" : "failed";
4705
4758
  const durationMs = testCase.time * 1e3;
4706
- const flowStartedAt = startedAt;
4707
- const flowCompletedAt = new Date(new Date(flowStartedAt).getTime() + durationMs).toISOString();
4708
4759
  const flowFile = testCase.classname || name;
4709
4760
  const flowBase = (0, import_node_path16.basename)(flowFile, (0, import_node_path16.extname)(flowFile)).toLowerCase();
4710
4761
  const recordingPath = flowRecordingMap.get(flowBase) ?? null;
4711
4762
  const { commands: flowCmds, matchedAnyFile } = commandsForFlow(commandSteps, flowFile);
4712
4763
  const perFlowCommands = matchedAnyFile ? flowCmds.filter((c) => c.category !== "assertion") : allNonAssertions;
4713
4764
  const perFlowAssertions = matchedAnyFile ? flowCmds.filter((c) => c.category === "assertion") : allAssertions;
4765
+ const allFlowCmds = [...perFlowCommands, ...perFlowAssertions];
4766
+ const earliestCmdMs = allFlowCmds.reduce((min, c) => {
4767
+ const t = Date.parse(c.timestamp);
4768
+ return Number.isFinite(t) && t < min ? t : min;
4769
+ }, Number.POSITIVE_INFINITY);
4770
+ const flowStartedAt = Number.isFinite(earliestCmdMs) ? new Date(earliestCmdMs).toISOString() : startedAt;
4771
+ const flowCompletedAt = new Date(new Date(flowStartedAt).getTime() + durationMs).toISOString();
4714
4772
  flowResults.push({
4715
4773
  flowName: name,
4716
4774
  flowFile,