@testrelic/maestro-analytics 1.0.0-next.14

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/merge.cjs ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';var fs=require('fs'),path=require('path');var x={"2xx":0,"3xx":0,"4xx":0,"5xx":0,error:0};function T(e){let s=0,i=0,n=0,t=0,a=0,c=0,m=0,p=0,l=0,u=e.length,r=0,o={},f=new Set;for(let S of e){f.add(S.url);for(let d of S.tests){switch(s++,d.status){case "passed":i++;break;case "failed":n++;break;case "flaky":t++;break;case "skipped":a++;break;case "timedout":c++;break}if(d.actions)for(let y of d.actions)if(r++,y.category==="assertion")m++,y.status==="passed"?p++:l++;else {let g=y.category;o[g]=(o[g]??0)+1;}}}return {total:s,passed:i,failed:n,flaky:t,skipped:a,timedout:c,totalApiCalls:0,uniqueApiUrls:0,apiCallsByMethod:{},apiCallsByStatusRange:x,apiResponseTime:null,totalAssertions:m,passedAssertions:p,failedAssertions:l,totalNavigations:u,uniqueNavigationUrls:f.size,totalTimelineSteps:e.length,totalActionSteps:r,actionStepsByCategory:o}}function h(e){return "tests"in e&&"visitedAt"in e}function k(e){let s=[],i=[],n="",t="",a="";for(let l of e)try{let u=fs.readFileSync(l,"utf-8"),r=JSON.parse(u);a||(a=r.testRunId),(!n||r.startedAt<n)&&(n=r.startedAt),(!t||r.completedAt&&r.completedAt>t)&&(t=r.completedAt);for(let o of r.timeline)s.push(o),h(o)&&i.push(o);}catch{process.stderr.write(`\u26A0 TestRelic: Unable to read report file: ${l}
2
+ `);}let c=T(i),m=n?new Date(n).getTime():Date.now(),p=t?new Date(t).getTime():Date.now();return {schemaVersion:"1.0.0",testRunId:a||`maestro-merged-${Date.now()}`,startedAt:n||new Date().toISOString(),completedAt:t||new Date().toISOString(),totalDuration:p-m,summary:c,ci:null,metadata:null,timeline:s,shardRunIds:null}}function U(e,s){if(!fs.existsSync(e))throw new Error(`Directory does not exist: ${e}`);let i=fs.readdirSync(e).filter(t=>path.extname(t)===".json"&&t.includes("testrelic")).map(t=>path.join(e,t)),n=k(i);return fs.writeFileSync(s,JSON.stringify(n,null,2),"utf-8"),n}exports.mergeReports=k;exports.mergeReportsFromDirectory=U;//# sourceMappingURL=merge.cjs.map
3
+ //# sourceMappingURL=merge.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/summary-builder.ts","../src/merge.ts"],"names":["EMPTY_STATUS_RANGE","buildSummary","timeline","total","passed","failed","flaky","skipped","timedout","totalAssertions","passedAssertions","failedAssertions","totalNavigations","totalActionSteps","actionCategoryCounts","uniqueUrls","entry","test","action","cat","isTimelineEntry","item","mergeReports","reportPaths","allTimeline","timelineEntries","earliestStart","latestEnd","runId","reportPath","content","readFileSync","report","summary","startMs","endMs","mergeReportsFromDirectory","dirPath","outputPath","existsSync","readdirSync","f","extname","join","merged","writeFileSync"],"mappings":"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","file":"merge.cjs","sourcesContent":["/**\n * Computes Summary stats from TimelineEntry arrays.\n */\n\nimport type { Summary, TimelineEntry } from '@testrelic/core';\n\ntype ApiCallsByStatusRange = Record<'2xx' | '3xx' | '4xx' | '5xx' | 'error', number>;\n\nconst EMPTY_STATUS_RANGE: ApiCallsByStatusRange = {\n '2xx': 0, '3xx': 0, '4xx': 0, '5xx': 0, error: 0,\n};\n\nexport function buildSummary(timeline: readonly TimelineEntry[]): Summary {\n let total = 0;\n let passed = 0;\n let failed = 0;\n let flaky = 0;\n let skipped = 0;\n let timedout = 0;\n let totalAssertions = 0;\n let passedAssertions = 0;\n let failedAssertions = 0;\n const totalNavigations = timeline.length;\n let totalActionSteps = 0;\n const actionCategoryCounts: Record<string, number> = {};\n const uniqueUrls = new Set<string>();\n\n for (const entry of timeline) {\n uniqueUrls.add(entry.url);\n\n for (const test of entry.tests) {\n total++;\n switch (test.status) {\n case 'passed': passed++; break;\n case 'failed': failed++; break;\n case 'flaky': flaky++; break;\n case 'skipped': skipped++; break;\n case 'timedout': timedout++; break;\n }\n\n if (test.actions) {\n for (const action of test.actions) {\n totalActionSteps++;\n if (action.category === 'assertion') {\n totalAssertions++;\n if (action.status === 'passed') passedAssertions++;\n else failedAssertions++;\n } else {\n const cat = action.category;\n actionCategoryCounts[cat] = (actionCategoryCounts[cat] ?? 0) + 1;\n }\n }\n }\n }\n }\n\n return {\n total,\n passed,\n failed,\n flaky,\n skipped,\n timedout,\n totalApiCalls: 0,\n uniqueApiUrls: 0,\n apiCallsByMethod: {},\n apiCallsByStatusRange: EMPTY_STATUS_RANGE,\n apiResponseTime: null,\n totalAssertions,\n passedAssertions,\n failedAssertions,\n totalNavigations,\n uniqueNavigationUrls: uniqueUrls.size,\n totalTimelineSteps: timeline.length,\n totalActionSteps,\n actionStepsByCategory: actionCategoryCounts,\n };\n}\n","/**\n * Merge multiple Maestro report JSON files into a single report.\n */\n\nimport { readFileSync, readdirSync, writeFileSync, existsSync } from 'node:fs';\nimport { join, extname } from 'node:path';\nimport type { TestRunReport, TimelineEntry, TimelineStep } from '@testrelic/core';\nimport { buildSummary } from './summary-builder.js';\n\nfunction isTimelineEntry(item: TimelineEntry | TimelineStep): item is TimelineEntry {\n return 'tests' in item && 'visitedAt' in item;\n}\n\nexport function mergeReports(reportPaths: string[]): TestRunReport {\n const allTimeline: (TimelineEntry | TimelineStep)[] = [];\n const timelineEntries: TimelineEntry[] = [];\n let earliestStart = '';\n let latestEnd = '';\n let runId = '';\n\n for (const reportPath of reportPaths) {\n try {\n const content = readFileSync(reportPath, 'utf-8');\n const report = JSON.parse(content) as TestRunReport;\n\n if (!runId) runId = report.testRunId;\n if (!earliestStart || report.startedAt < earliestStart) earliestStart = report.startedAt;\n if (!latestEnd || (report.completedAt && report.completedAt > latestEnd)) latestEnd = report.completedAt;\n\n for (const item of report.timeline) {\n allTimeline.push(item);\n if (isTimelineEntry(item)) timelineEntries.push(item);\n }\n } catch {\n process.stderr.write(`\\u26A0 TestRelic: Unable to read report file: ${reportPath}\\n`);\n }\n }\n\n const summary = buildSummary(timelineEntries);\n const startMs = earliestStart ? new Date(earliestStart).getTime() : Date.now();\n const endMs = latestEnd ? new Date(latestEnd).getTime() : Date.now();\n\n return {\n schemaVersion: '1.0.0',\n testRunId: runId || `maestro-merged-${Date.now()}`,\n startedAt: earliestStart || new Date().toISOString(),\n completedAt: latestEnd || new Date().toISOString(),\n totalDuration: endMs - startMs,\n summary,\n ci: null,\n metadata: null,\n timeline: allTimeline,\n shardRunIds: null,\n };\n}\n\nexport function mergeReportsFromDirectory(dirPath: string, outputPath: string): TestRunReport {\n if (!existsSync(dirPath)) {\n throw new Error(`Directory does not exist: ${dirPath}`);\n }\n\n const reportPaths = readdirSync(dirPath)\n .filter((f) => extname(f) === '.json' && f.includes('testrelic'))\n .map((f) => join(dirPath, f));\n\n const merged = mergeReports(reportPaths);\n writeFileSync(outputPath, JSON.stringify(merged, null, 2), 'utf-8');\n return merged;\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import { TestRunReport } from '@testrelic/core';
2
+
3
+ /**
4
+ * Merge multiple Maestro report JSON files into a single report.
5
+ */
6
+
7
+ declare function mergeReports(reportPaths: string[]): TestRunReport;
8
+ declare function mergeReportsFromDirectory(dirPath: string, outputPath: string): TestRunReport;
9
+
10
+ export { mergeReports, mergeReportsFromDirectory };
@@ -0,0 +1,10 @@
1
+ import { TestRunReport } from '@testrelic/core';
2
+
3
+ /**
4
+ * Merge multiple Maestro report JSON files into a single report.
5
+ */
6
+
7
+ declare function mergeReports(reportPaths: string[]): TestRunReport;
8
+ declare function mergeReportsFromDirectory(dirPath: string, outputPath: string): TestRunReport;
9
+
10
+ export { mergeReports, mergeReportsFromDirectory };
package/dist/merge.js ADDED
@@ -0,0 +1,3 @@
1
+ import {readFileSync,existsSync,readdirSync,writeFileSync}from'fs';import {extname,join}from'path';var x={"2xx":0,"3xx":0,"4xx":0,"5xx":0,error:0};function T(e){let s=0,i=0,n=0,t=0,a=0,c=0,m=0,p=0,l=0,u=e.length,r=0,o={},f=new Set;for(let S of e){f.add(S.url);for(let d of S.tests){switch(s++,d.status){case "passed":i++;break;case "failed":n++;break;case "flaky":t++;break;case "skipped":a++;break;case "timedout":c++;break}if(d.actions)for(let y of d.actions)if(r++,y.category==="assertion")m++,y.status==="passed"?p++:l++;else {let g=y.category;o[g]=(o[g]??0)+1;}}}return {total:s,passed:i,failed:n,flaky:t,skipped:a,timedout:c,totalApiCalls:0,uniqueApiUrls:0,apiCallsByMethod:{},apiCallsByStatusRange:x,apiResponseTime:null,totalAssertions:m,passedAssertions:p,failedAssertions:l,totalNavigations:u,uniqueNavigationUrls:f.size,totalTimelineSteps:e.length,totalActionSteps:r,actionStepsByCategory:o}}function h(e){return "tests"in e&&"visitedAt"in e}function k(e){let s=[],i=[],n="",t="",a="";for(let l of e)try{let u=readFileSync(l,"utf-8"),r=JSON.parse(u);a||(a=r.testRunId),(!n||r.startedAt<n)&&(n=r.startedAt),(!t||r.completedAt&&r.completedAt>t)&&(t=r.completedAt);for(let o of r.timeline)s.push(o),h(o)&&i.push(o);}catch{process.stderr.write(`\u26A0 TestRelic: Unable to read report file: ${l}
2
+ `);}let c=T(i),m=n?new Date(n).getTime():Date.now(),p=t?new Date(t).getTime():Date.now();return {schemaVersion:"1.0.0",testRunId:a||`maestro-merged-${Date.now()}`,startedAt:n||new Date().toISOString(),completedAt:t||new Date().toISOString(),totalDuration:p-m,summary:c,ci:null,metadata:null,timeline:s,shardRunIds:null}}function U(e,s){if(!existsSync(e))throw new Error(`Directory does not exist: ${e}`);let i=readdirSync(e).filter(t=>extname(t)===".json"&&t.includes("testrelic")).map(t=>join(e,t)),n=k(i);return writeFileSync(s,JSON.stringify(n,null,2),"utf-8"),n}export{k as mergeReports,U as mergeReportsFromDirectory};//# sourceMappingURL=merge.js.map
3
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/summary-builder.ts","../src/merge.ts"],"names":["EMPTY_STATUS_RANGE","buildSummary","timeline","total","passed","failed","flaky","skipped","timedout","totalAssertions","passedAssertions","failedAssertions","totalNavigations","totalActionSteps","actionCategoryCounts","uniqueUrls","entry","test","action","cat","isTimelineEntry","item","mergeReports","reportPaths","allTimeline","timelineEntries","earliestStart","latestEnd","runId","reportPath","content","readFileSync","report","summary","startMs","endMs","mergeReportsFromDirectory","dirPath","outputPath","existsSync","readdirSync","f","extname","join","merged","writeFileSync"],"mappings":"mGAQA,IAAMA,CAAAA,CAA4C,CAChD,KAAA,CAAO,CAAA,CAAG,KAAA,CAAO,CAAA,CAAG,KAAA,CAAO,CAAA,CAAG,KAAA,CAAO,CAAA,CAAG,KAAA,CAAO,CACjD,CAAA,CAEO,SAASC,CAAAA,CAAaC,CAAAA,CAA6C,CACxE,IAAIC,CAAAA,CAAQ,CAAA,CACRC,CAAAA,CAAS,CAAA,CACTC,CAAAA,CAAS,CAAA,CACTC,CAAAA,CAAQ,CAAA,CACRC,CAAAA,CAAU,CAAA,CACVC,CAAAA,CAAW,CAAA,CACXC,EAAkB,CAAA,CAClBC,CAAAA,CAAmB,CAAA,CACnBC,CAAAA,CAAmB,CAAA,CACjBC,CAAAA,CAAmBV,CAAAA,CAAS,MAAA,CAC9BW,CAAAA,CAAmB,CAAA,CACjBC,CAAAA,CAA+C,EAAC,CAChDC,CAAAA,CAAa,IAAI,GAAA,CAEvB,QAAWC,CAAAA,IAASd,CAAAA,CAAU,CAC5Ba,CAAAA,CAAW,GAAA,CAAIC,CAAAA,CAAM,GAAG,CAAA,CAExB,IAAA,IAAWC,CAAAA,IAAQD,CAAAA,CAAM,KAAA,CAAO,CAE9B,OADAb,CAAAA,EAAAA,CACQc,CAAAA,CAAK,QACX,KAAK,QAAA,CAAUb,CAAAA,EAAAA,CAAU,MACzB,KAAK,QAAA,CAAUC,CAAAA,EAAAA,CAAU,MACzB,KAAK,OAAA,CAASC,CAAAA,EAAAA,CAAS,MACvB,KAAK,SAAA,CAAWC,CAAAA,EAAAA,CAAW,MAC3B,KAAK,UAAA,CAAYC,CAAAA,EAAAA,CAAY,KAC/B,CAEA,GAAIS,CAAAA,CAAK,OAAA,CACP,IAAA,IAAWC,CAAAA,IAAUD,CAAAA,CAAK,OAAA,CAExB,GADAJ,CAAAA,EAAAA,CACIK,CAAAA,CAAO,QAAA,GAAa,YACtBT,CAAAA,EAAAA,CACIS,CAAAA,CAAO,MAAA,GAAW,QAAA,CAAUR,CAAAA,EAAAA,CAC3BC,CAAAA,EAAAA,CAAAA,KACA,CACL,IAAMQ,CAAAA,CAAMD,CAAAA,CAAO,QAAA,CACnBJ,CAAAA,CAAqBK,CAAG,CAAA,CAAA,CAAKL,CAAAA,CAAqBK,CAAG,GAAK,CAAA,EAAK,EACjE,CAGN,CACF,CAEA,OAAO,CACL,KAAA,CAAAhB,CAAAA,CACA,MAAA,CAAAC,CAAAA,CACA,MAAA,CAAAC,CAAAA,CACA,KAAA,CAAAC,CAAAA,CACA,OAAA,CAAAC,EACA,QAAA,CAAAC,CAAAA,CACA,aAAA,CAAe,CAAA,CACf,aAAA,CAAe,CAAA,CACf,gBAAA,CAAkB,EAAC,CACnB,qBAAA,CAAuBR,CAAAA,CACvB,eAAA,CAAiB,IAAA,CACjB,eAAA,CAAAS,CAAAA,CACA,gBAAA,CAAAC,EACA,gBAAA,CAAAC,CAAAA,CACA,gBAAA,CAAAC,CAAAA,CACA,oBAAA,CAAsBG,CAAAA,CAAW,IAAA,CACjC,kBAAA,CAAoBb,CAAAA,CAAS,MAAA,CAC7B,gBAAA,CAAAW,CAAAA,CACA,qBAAA,CAAuBC,CACzB,CACF,CCpEA,SAASM,CAAAA,CAAgBC,CAAAA,CAA2D,CAClF,OAAO,OAAA,GAAWA,CAAAA,EAAQ,WAAA,GAAeA,CAC3C,CAEO,SAASC,CAAAA,CAAaC,CAAAA,CAAsC,CACjE,IAAMC,CAAAA,CAAgD,GAChDC,CAAAA,CAAmC,EAAC,CACtCC,CAAAA,CAAgB,EAAA,CAChBC,CAAAA,CAAY,EAAA,CACZC,CAAAA,CAAQ,EAAA,CAEZ,IAAA,IAAWC,CAAAA,IAAcN,CAAAA,CACvB,GAAI,CACF,IAAMO,CAAAA,CAAUC,aAAaF,CAAAA,CAAY,OAAO,CAAA,CAC1CG,CAAAA,CAAS,IAAA,CAAK,KAAA,CAAMF,CAAO,CAAA,CAE5BF,CAAAA,GAAOA,CAAAA,CAAQI,CAAAA,CAAO,SAAA,CAAA,CAAA,CACvB,CAACN,CAAAA,EAAiBM,CAAAA,CAAO,SAAA,CAAYN,KAAeA,CAAAA,CAAgBM,CAAAA,CAAO,SAAA,CAAA,CAAA,CAC3E,CAACL,CAAAA,EAAcK,CAAAA,CAAO,WAAA,EAAeA,CAAAA,CAAO,WAAA,CAAcL,CAAAA,IAAYA,CAAAA,CAAYK,CAAAA,CAAO,WAAA,CAAA,CAE7F,IAAA,IAAWX,CAAAA,IAAQW,CAAAA,CAAO,SACxBR,CAAAA,CAAY,IAAA,CAAKH,CAAI,CAAA,CACjBD,CAAAA,CAAgBC,CAAI,CAAA,EAAGI,CAAAA,CAAgB,IAAA,CAAKJ,CAAI,EAExD,CAAA,KAAQ,CACN,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,iDAAiDQ,CAAU;AAAA,CAAI,EACtF,CAGF,IAAMI,CAAAA,CAAUhC,CAAAA,CAAawB,CAAe,CAAA,CACtCS,CAAAA,CAAUR,CAAAA,CAAgB,IAAI,IAAA,CAAKA,CAAa,CAAA,CAAE,OAAA,EAAQ,CAAI,IAAA,CAAK,GAAA,EAAI,CACvES,CAAAA,CAAQR,CAAAA,CAAY,IAAI,IAAA,CAAKA,CAAS,CAAA,CAAE,OAAA,EAAQ,CAAI,IAAA,CAAK,GAAA,EAAI,CAEnE,OAAO,CACL,aAAA,CAAe,OAAA,CACf,SAAA,CAAWC,CAAAA,EAAS,CAAA,eAAA,EAAkB,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,CAChD,SAAA,CAAWF,CAAAA,EAAiB,IAAI,IAAA,EAAK,CAAE,WAAA,EAAY,CACnD,WAAA,CAAaC,CAAAA,EAAa,IAAI,IAAA,EAAK,CAAE,WAAA,EAAY,CACjD,aAAA,CAAeQ,CAAAA,CAAQD,CAAAA,CACvB,OAAA,CAAAD,CAAAA,CACA,EAAA,CAAI,IAAA,CACJ,QAAA,CAAU,IAAA,CACV,QAAA,CAAUT,CAAAA,CACV,WAAA,CAAa,IACf,CACF,CAEO,SAASY,CAAAA,CAA0BC,CAAAA,CAAiBC,CAAAA,CAAmC,CAC5F,GAAI,CAACC,UAAAA,CAAWF,CAAO,CAAA,CACrB,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6BA,CAAO,CAAA,CAAE,CAAA,CAGxD,IAAMd,CAAAA,CAAciB,WAAAA,CAAYH,CAAO,CAAA,CACpC,MAAA,CAAQI,CAAAA,EAAMC,OAAAA,CAAQD,CAAC,CAAA,GAAM,OAAA,EAAWA,CAAAA,CAAE,QAAA,CAAS,WAAW,CAAC,CAAA,CAC/D,GAAA,CAAKA,CAAAA,EAAME,IAAAA,CAAKN,CAAAA,CAASI,CAAC,CAAC,CAAA,CAExBG,CAAAA,CAAStB,CAAAA,CAAaC,CAAW,CAAA,CACvC,OAAAsB,aAAAA,CAAcP,CAAAA,CAAY,IAAA,CAAK,SAAA,CAAUM,CAAAA,CAAQ,IAAA,CAAM,CAAC,CAAA,CAAG,OAAO,CAAA,CAC3DA,CACT","file":"merge.js","sourcesContent":["/**\n * Computes Summary stats from TimelineEntry arrays.\n */\n\nimport type { Summary, TimelineEntry } from '@testrelic/core';\n\ntype ApiCallsByStatusRange = Record<'2xx' | '3xx' | '4xx' | '5xx' | 'error', number>;\n\nconst EMPTY_STATUS_RANGE: ApiCallsByStatusRange = {\n '2xx': 0, '3xx': 0, '4xx': 0, '5xx': 0, error: 0,\n};\n\nexport function buildSummary(timeline: readonly TimelineEntry[]): Summary {\n let total = 0;\n let passed = 0;\n let failed = 0;\n let flaky = 0;\n let skipped = 0;\n let timedout = 0;\n let totalAssertions = 0;\n let passedAssertions = 0;\n let failedAssertions = 0;\n const totalNavigations = timeline.length;\n let totalActionSteps = 0;\n const actionCategoryCounts: Record<string, number> = {};\n const uniqueUrls = new Set<string>();\n\n for (const entry of timeline) {\n uniqueUrls.add(entry.url);\n\n for (const test of entry.tests) {\n total++;\n switch (test.status) {\n case 'passed': passed++; break;\n case 'failed': failed++; break;\n case 'flaky': flaky++; break;\n case 'skipped': skipped++; break;\n case 'timedout': timedout++; break;\n }\n\n if (test.actions) {\n for (const action of test.actions) {\n totalActionSteps++;\n if (action.category === 'assertion') {\n totalAssertions++;\n if (action.status === 'passed') passedAssertions++;\n else failedAssertions++;\n } else {\n const cat = action.category;\n actionCategoryCounts[cat] = (actionCategoryCounts[cat] ?? 0) + 1;\n }\n }\n }\n }\n }\n\n return {\n total,\n passed,\n failed,\n flaky,\n skipped,\n timedout,\n totalApiCalls: 0,\n uniqueApiUrls: 0,\n apiCallsByMethod: {},\n apiCallsByStatusRange: EMPTY_STATUS_RANGE,\n apiResponseTime: null,\n totalAssertions,\n passedAssertions,\n failedAssertions,\n totalNavigations,\n uniqueNavigationUrls: uniqueUrls.size,\n totalTimelineSteps: timeline.length,\n totalActionSteps,\n actionStepsByCategory: actionCategoryCounts,\n };\n}\n","/**\n * Merge multiple Maestro report JSON files into a single report.\n */\n\nimport { readFileSync, readdirSync, writeFileSync, existsSync } from 'node:fs';\nimport { join, extname } from 'node:path';\nimport type { TestRunReport, TimelineEntry, TimelineStep } from '@testrelic/core';\nimport { buildSummary } from './summary-builder.js';\n\nfunction isTimelineEntry(item: TimelineEntry | TimelineStep): item is TimelineEntry {\n return 'tests' in item && 'visitedAt' in item;\n}\n\nexport function mergeReports(reportPaths: string[]): TestRunReport {\n const allTimeline: (TimelineEntry | TimelineStep)[] = [];\n const timelineEntries: TimelineEntry[] = [];\n let earliestStart = '';\n let latestEnd = '';\n let runId = '';\n\n for (const reportPath of reportPaths) {\n try {\n const content = readFileSync(reportPath, 'utf-8');\n const report = JSON.parse(content) as TestRunReport;\n\n if (!runId) runId = report.testRunId;\n if (!earliestStart || report.startedAt < earliestStart) earliestStart = report.startedAt;\n if (!latestEnd || (report.completedAt && report.completedAt > latestEnd)) latestEnd = report.completedAt;\n\n for (const item of report.timeline) {\n allTimeline.push(item);\n if (isTimelineEntry(item)) timelineEntries.push(item);\n }\n } catch {\n process.stderr.write(`\\u26A0 TestRelic: Unable to read report file: ${reportPath}\\n`);\n }\n }\n\n const summary = buildSummary(timelineEntries);\n const startMs = earliestStart ? new Date(earliestStart).getTime() : Date.now();\n const endMs = latestEnd ? new Date(latestEnd).getTime() : Date.now();\n\n return {\n schemaVersion: '1.0.0',\n testRunId: runId || `maestro-merged-${Date.now()}`,\n startedAt: earliestStart || new Date().toISOString(),\n completedAt: latestEnd || new Date().toISOString(),\n totalDuration: endMs - startMs,\n summary,\n ci: null,\n metadata: null,\n timeline: allTimeline,\n shardRunIds: null,\n };\n}\n\nexport function mergeReportsFromDirectory(dirPath: string, outputPath: string): TestRunReport {\n if (!existsSync(dirPath)) {\n throw new Error(`Directory does not exist: ${dirPath}`);\n }\n\n const reportPaths = readdirSync(dirPath)\n .filter((f) => extname(f) === '.json' && f.includes('testrelic'))\n .map((f) => join(dirPath, f));\n\n const merged = mergeReports(reportPaths);\n writeFileSync(outputPath, JSON.stringify(merged, null, 2), 'utf-8');\n return merged;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@testrelic/maestro-analytics",
3
+ "version": "1.0.0-next.14",
4
+ "description": "Maestro mobile testing analytics — JUnit/artifact parsing, step-level timing, AI defect aggregation, visual regression tracking, and interactive HTML reports",
5
+ "keywords": [
6
+ "maestro",
7
+ "mobile-testing",
8
+ "test-analytics",
9
+ "android",
10
+ "ios",
11
+ "html-report",
12
+ "test-results",
13
+ "yaml-flows",
14
+ "junit",
15
+ "visual-regression",
16
+ "test-automation",
17
+ "maestro-reporter",
18
+ "observability"
19
+ ],
20
+ "author": "TestRelic AI <hello@testrelic.ai>",
21
+ "type": "module",
22
+ "main": "./dist/index.cjs",
23
+ "module": "./dist/index.js",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "import": {
28
+ "types": "./dist/index.d.ts",
29
+ "default": "./dist/index.js"
30
+ },
31
+ "require": {
32
+ "types": "./dist/index.d.cts",
33
+ "default": "./dist/index.cjs"
34
+ }
35
+ },
36
+ "./merge": {
37
+ "import": {
38
+ "types": "./dist/merge.d.ts",
39
+ "default": "./dist/merge.js"
40
+ },
41
+ "require": {
42
+ "types": "./dist/merge.d.cts",
43
+ "default": "./dist/merge.cjs"
44
+ }
45
+ },
46
+ "./package.json": "./package.json"
47
+ },
48
+ "bin": {
49
+ "testrelic-maestro": "./dist/cli.cjs"
50
+ },
51
+ "files": [
52
+ "dist",
53
+ "README.md"
54
+ ],
55
+ "dependencies": {
56
+ "fast-xml-parser": "^4.5.0",
57
+ "yaml": "^2.7.0",
58
+ "@testrelic/core": "2.4.11-next.14"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^20.0.0",
62
+ "tsup": "^8.0.0",
63
+ "typescript": "^5.5.0",
64
+ "vitest": "^2.0.0"
65
+ },
66
+ "engines": {
67
+ "node": ">=18"
68
+ },
69
+ "license": "MIT",
70
+ "homepage": "https://testrelic.ai",
71
+ "publishConfig": {
72
+ "registry": "https://registry.npmjs.org",
73
+ "access": "public"
74
+ },
75
+ "scripts": {
76
+ "build": "tsup",
77
+ "test": "vitest run",
78
+ "test:watch": "vitest",
79
+ "typecheck": "tsc --noEmit"
80
+ }
81
+ }