@testrelic/maestro-analytics 1.3.0-next.73 → 1.3.0-next.77
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 +15 -13
- package/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -7
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -389,6 +389,9 @@ declare function printConsoleSummary(summary: Summary, outputPath: string, htmlR
|
|
|
389
389
|
|
|
390
390
|
/**
|
|
391
391
|
* Open a file path in the user's default browser.
|
|
392
|
+
*
|
|
393
|
+
* Uses `execFile` with an argv array (no shell) so a report path containing
|
|
394
|
+
* shell metacharacters can never be interpreted as a command.
|
|
392
395
|
*/
|
|
393
396
|
declare function openInBrowser(filePath: string): void;
|
|
394
397
|
|
package/dist/index.d.ts
CHANGED
|
@@ -389,6 +389,9 @@ declare function printConsoleSummary(summary: Summary, outputPath: string, htmlR
|
|
|
389
389
|
|
|
390
390
|
/**
|
|
391
391
|
* Open a file path in the user's default browser.
|
|
392
|
+
*
|
|
393
|
+
* Uses `execFile` with an argv array (no shell) so a report path containing
|
|
394
|
+
* shell metacharacters can never be interpreted as a command.
|
|
392
395
|
*/
|
|
393
396
|
declare function openInBrowser(filePath: string): void;
|
|
394
397
|
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {isValidEndpointUrl,isValidCloudConfig,createError,ErrorCode,isValidQueueEntry}from'@testrelic/core';import {existsSync,statSync,readFileSync,readdirSync,mkdirSync,writeFileSync,renameSync,unlinkSync,createReadStream}from'fs';import {resolve,join,dirname,basename,extname}from'path';import {XMLParser}from'fast-xml-parser';import {parseDocument}from'yaml';import {
|
|
1
|
+
import {isValidEndpointUrl,isValidCloudConfig,createError,ErrorCode,isValidQueueEntry}from'@testrelic/core';import {existsSync,statSync,readFileSync,readdirSync,mkdirSync,writeFileSync,renameSync,unlinkSync,createReadStream}from'fs';import {resolve,join,dirname,basename,extname}from'path';import {XMLParser}from'fast-xml-parser';import {parseDocument}from'yaml';import {execFile,spawn,execSync,spawnSync}from'child_process';import {tmpdir}from'os';import {createHash,randomUUID,randomBytes}from'crypto';import {fileURLToPath}from'url';import {gzipSync}from'zlib';import {Readable}from'stream';var bt=".testrelic",Lr="testrelic-config.json",Dr=".testrelic",Nr=5,Or=new Set(["__proto__","constructor","prototype"]),me=Object.freeze({apiKey:null,endpoint:"https://platform.testrelic.ai/api/v1",uploadStrategy:"batch",timeout:3e4,projectName:null,queueMaxAge:6048e5,queueDirectory:`${bt}/queue`,uploadArtifacts:true,artifactMaxSizeMb:50}),Ur={s:1e3,m:60*1e3,h:3600*1e3,d:1440*60*1e3};function ye(e){let t=resolve(e);for(let r=0;r<=Nr;r++){let n=join(t,bt,Lr);if(existsSync(n))try{if(statSync(n).isFile())return n}catch{}let o=join(t,Dr);if(existsSync(o))try{if(statSync(o).isFile())return process.stderr.write(`[testrelic] Deprecation: config file ".testrelic" has moved to ".testrelic/testrelic-config.json". Please migrate your config file to the new location.
|
|
2
2
|
`),o}catch{}let s=dirname(t);if(s===t)break;t=s;}return null}function be(e){try{let t=readFileSync(e,"utf-8"),r=JSON.parse(t);return typeof r!="object"||r===null||Array.isArray(r)||!xt(r)?null:r}catch{return null}}function xt(e){for(let t of Object.keys(e)){if(Or.has(t))return false;let r=e[t];if(typeof r=="object"&&r!==null&&!Array.isArray(r)&&!xt(r))return false}return true}function K(e){let t=/^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(e);if(t)return process.env[t[1]]??null;let r=/^\$([A-Za-z_][A-Za-z0-9_]*)$/.exec(e);return r?process.env[r[1]]??null:e}function Y(e){let t=Object.create(null);for(let r of Object.keys(e)){let n=e[r];typeof n=="string"&&n.startsWith("$")?t[r]=K(n):typeof n=="object"&&n!==null&&!Array.isArray(n)?t[r]=Y(n):t[r]=n;}return t}function he(e){let t=/^(\d+)\s*([smhd])$/.exec(e.trim());if(!t)return null;let r=parseInt(t[1],10),n=t[2],o=Ur[n];return !o||r<=0?null:r*o}function xe(e,t){let r=Object.create(null);if(Object.assign(r,me),e){let l=e.cloud;l&&typeof l=="object"&&(typeof l.endpoint=="string"&&(r.endpoint=l.endpoint),typeof l.upload=="string"&&(r.uploadStrategy=l.upload),typeof l.timeout=="number"&&(r.timeout=l.timeout),typeof l.apiKey=="string"&&l.apiKey.length>0&&(r.apiKey=l.apiKey));let c=e["testrelic-repo"]??e.project;c&&typeof c=="object"&&typeof c.name=="string"&&(r.projectName=c.name);let d=e.queue;if(d&&typeof d=="object"){if(typeof d.maxAge=="string"){let u=he(d.maxAge);u!==null&&(r.queueMaxAge=u);}typeof d.directory=="string"&&(r.queueDirectory=d.directory);}}if(t){if(typeof t.apiKey=="string"&&t.apiKey.length>0){let l=t.apiKey.startsWith("$")?K(t.apiKey):t.apiKey;l&&(r.apiKey=l);}if(typeof t.endpoint=="string"){let l=t.endpoint.startsWith("$")?K(t.endpoint):t.endpoint;l&&(r.endpoint=l);}if(typeof t.upload=="string"&&(r.uploadStrategy=t.upload),typeof t.timeout=="number"&&(r.timeout=t.timeout),typeof t.projectName=="string"&&(r.projectName=t.projectName),typeof t.queueMaxAge=="string"){let l=he(t.queueMaxAge);l!==null&&(r.queueMaxAge=l);}typeof t.queueDirectory=="string"&&(r.queueDirectory=t.queueDirectory),typeof t.uploadArtifacts=="boolean"&&(r.uploadArtifacts=t.uploadArtifacts),typeof t.artifactMaxSizeMb=="number"&&(r.artifactMaxSizeMb=t.artifactMaxSizeMb);}let n=process.env.TESTRELIC_API_KEY;n&&n.length>0&&(r.apiKey=n);let o=process.env.TESTRELIC_CLOUD_ENDPOINT;o&&isValidEndpointUrl(o)&&(r.endpoint=o);let s=process.env.TESTRELIC_UPLOAD_STRATEGY;s&&["batch","realtime","both"].includes(s)&&(r.uploadStrategy=s);let i=process.env.TESTRELIC_CLOUD_TIMEOUT;if(i){let l=parseInt(i,10);!isNaN(l)&&l>=1e3&&l<=12e4&&(r.timeout=l);}let a=Object.freeze(r);return isValidCloudConfig(a)?a:me}var Br=["authorization","cookie","set-cookie","x-api-key"],jr=["password","secret","token","apiKey","api_key"],zr=1024*1024;function qr(e){let t=e??{},r=process.env.TESTRELIC_CAPTURE_NETWORK==="1"||process.env.TESTRELIC_CAPTURE_NETWORK?.toLowerCase()==="true";return Object.freeze({enabled:t.enabled??r??false,proxyPort:t.proxyPort??(process.env.TESTRELIC_PROXY_PORT?Number.parseInt(process.env.TESTRELIC_PROXY_PORT,10):8080),proxyHost:t.proxyHost??process.env.TESTRELIC_PROXY_HOST??"127.0.0.1",harPath:t.harPath??process.env.TESTRELIC_HAR_PATH??null,outputDir:t.outputDir??null,skipCertInstall:t.skipCertInstall??false,includeUrls:Object.freeze(t.includeUrls?[...t.includeUrls]:[]),excludeUrls:Object.freeze(t.excludeUrls?[...t.excludeUrls]:[]),redactHeaders:Object.freeze(t.redactHeaders?[...t.redactHeaders]:[...Br]),redactBodyFields:Object.freeze(t.redactBodyFields?[...t.redactBodyFields]:[...jr]),maxBodyBytes:t.maxBodyBytes??zr})}var Gr=new Set(["__proto__","constructor","prototype"]);function wt(e){if(typeof e!="object"||e===null)return false;for(let t of Object.keys(e))if(Gr.has(t))return true;return false}function Vr(e){if(typeof e!="object"||e===null||wt(e))return false;let t=e;return !(t.outputPath!==void 0&&typeof t.outputPath!="string"||t.htmlReportPath!==void 0&&typeof t.htmlReportPath!="string"||t.openReport!==void 0&&typeof t.openReport!="boolean"||t.includeScreenshots!==void 0&&typeof t.includeScreenshots!="boolean"||t.includeVideo!==void 0&&typeof t.includeVideo!="boolean"||t.includeAiAnalysis!==void 0&&typeof t.includeAiAnalysis!="boolean"||t.includeLogs!==void 0&&typeof t.includeLogs!="boolean"||t.includeFlowMetadata!==void 0&&typeof t.includeFlowMetadata!="boolean"||t.quiet!==void 0&&typeof t.quiet!="boolean"||t.metadata!==void 0&&t.metadata!==null&&(typeof t.metadata!="object"||wt(t.metadata)))}function Jr(e){if(e!==void 0&&!Vr(e))throw createError(ErrorCode.CONFIG_INVALID,"Invalid Maestro reporter configuration");let t=Object.create(null),r=e?.outputPath??"./test-results/testrelic-maestro.json";return t.outputPath=r,t.htmlReportPath=e?.htmlReportPath??r.replace(/\.json$/,".html"),t.openReport=e?.openReport??true,t.includeScreenshots=e?.includeScreenshots??true,t.includeVideo=e?.includeVideo??true,t.includeAiAnalysis=e?.includeAiAnalysis??true,t.includeLogs=e?.includeLogs??true,t.includeFlowMetadata=e?.includeFlowMetadata??true,t.flowsDir=e?.flowsDir??null,t.testRunId=e?.testRunId??null,t.metadata=e?.metadata??null,t.quiet=e?.quiet??false,t.reportMode=e?.reportMode??"batch",t.cloud=Wr(e?.cloud??null),t.network=qr(e?.network),Object.freeze(t)}function Wr(e){let t=ye(process.cwd()),r=t?be(t):null,n=r?Y(r):null,o=xe(n,e??void 0);return o.apiKey?o:null}var Xr=new XMLParser({ignoreAttributes:false,attributeNamePrefix:"@_",allowBooleanAttributes:true,parseAttributeValue:true,trimValues:true});function X(e){return e==null?[]:Array.isArray(e)?e:[e]}function kt(e){return !e||typeof e!="object"?[]:X(e.property).map(n=>({name:String(n["@_name"]??""),value:String(n["@_value"]??"")}))}function Qr(e){let t=String(e["@_name"]??"unnamed"),r=String(e["@_classname"]??t),n=Number(e["@_time"]??0),o=e["@_id"]!=null?String(e["@_id"]):null,s=String(e["@_status"]??"").toUpperCase(),i=e.failure,a=e.error,l=e.skipped!==void 0,c="SUCCESS";return i?c="FAILURE":a?c="ERROR":l?c="SKIPPED":s==="FAILURE"||s==="FAILED"?c="FAILURE":s==="ERROR"?c="ERROR":s==="SKIPPED"&&(c="SKIPPED"),{id:o,name:t,classname:r,time:n,status:c,failureMessage:i?String(i["@_message"]??i["#text"]??""):null,failureType:i?String(i["@_type"]??""):null,errorMessage:a?String(a["@_message"]??a["#text"]??""):null,errorType:a?String(a["@_type"]??""):null,properties:kt(e.properties)}}function vt(e){let t=String(e["@_name"]??"Test Suite"),r=e["@_device"]!=null?String(e["@_device"]):null,n=Number(e["@_tests"]??0),o=Number(e["@_failures"]??0),s=Number(e["@_errors"]??0),i=Number(e["@_skipped"]??0),a=Number(e["@_time"]??0),c=X(e.testcase).map(Qr);return {name:t,device:r,tests:n,failures:o,errors:s,skipped:i,time:a,testCases:c,properties:kt(e.properties)}}function Ct(e){let t=Xr.parse(e),r=[];if(t.testsuites){let l=t.testsuites;r=X(l.testsuite).map(vt);}else t.testsuite&&(r=X(t.testsuite).map(vt));let n=0,o=0,s=0,i=0,a=0;for(let l of r)n+=l.tests,o+=l.failures,s+=l.errors,i+=l.skipped,a+=l.time;return {testSuites:r,totalTests:n,totalFailures:o,totalErrors:s,totalSkipped:i,totalTime:a}}function we(e){let t=readFileSync(e,"utf-8");return Ct(t)}var on=new Set(["tapOn","doubleTapOn","longPressOn","inputText","eraseText","pasteText","swipe","scroll","scrollUntilVisible","hideKeyboard","pressKey","setClipboard","copyTextFrom"]),sn=new Set(["assertVisible","assertNotVisible","assertTrue","assertScreenshot","assertNoDefectsWithAI","assertWithAI","assertCondition"]),an=new Set(["launchApp","killApp","stopApp","clearState","openLink","back","clearKeychain"]),ln=new Set(["setAirplaneMode","toggleAirplaneMode","setLocation","setOrientation","setPermissions","addMedia","travel"]),cn=new Set(["takeScreenshot","startRecording","stopRecording"]),dn=new Set(["runScript","evalScript"]),un=new Set(["runFlow","repeat","retry","waitForAnimationToEnd","extendedWaitUntil"]),pn=new Set(["assertWithAI","assertNoDefectsWithAI","extractTextWithAI"]),fn=new Set(["inputText","pasteText"]),gn=200,mn=400;function Mt(e){return pn.has(e)?"ai":sn.has(e)?"assertion":on.has(e)?"interaction":an.has(e)?"navigation":ln.has(e)?"device":cn.has(e)?"media":dn.has(e)?"script":un.has(e)?"flow_control":"other"}var hn={tapOnElement:"tapOn",assertCondition:"assertVisible",backPress:"back",applyConfiguration:"applyConfiguration",defineVariables:"defineVariables"};function Rt(e){let t=e.replace(/Command$/,"");return hn[t]??t}var yn=new Set(["metadata","command","commandName","name","status","duration","durationMs","timestamp","time","error","errorMessage","selector","commands","subSteps","children","sequenceNumber"]);function bn(e){for(let t of Object.keys(e)){if(yn.has(t))continue;let r=e[t];if(r&&typeof r=="object"&&!Array.isArray(r))return t}}function St(e){if(e.selector&&typeof e.selector=="object"){let t=e.selector;if(typeof t.textRegex=="string")return t.textRegex;if(typeof t.text=="string")return t.text;if(typeof t.id=="string")return `#${t.id}`}if(e.condition&&typeof e.condition=="object"){let t=e.condition,r=t.visible??t.notVisible;if(r){if(typeof r.textRegex=="string")return r.textRegex;if(typeof r.text=="string")return r.text}}if(typeof e.path=="string")return e.path}function Tt(e,t){return e.length<=t?e:`${e.slice(0,t)}\u2026`}function xn(e){return e.length===0?"":`[REDACTED ${e.length} chars]`}function At(e){if(!e||typeof e!="object")return;let t=e;if(typeof t.x=="number"&&typeof t.y=="number")return `${t.x},${t.y}`}function It(e,t){let r={};switch(e){case "inputText":case "pasteText":{let n=t.text??t.value;typeof n=="string"&&(r.text=fn.has(e)?xn(n):n);break}case "swipe":case "scroll":case "scrollUntilVisible":{typeof t.direction=="string"&&(r.direction=t.direction);let n=At(t.start??t.startRelative),o=At(t.end??t.endRelative);n&&(r.start=n),o&&(r.end=o),typeof t.duration=="number"&&(r.swipeDurationMs=t.duration),typeof t.timeout=="number"&&(r.timeoutMs=t.timeout);break}case "setLocation":{typeof t.latitude=="number"&&(r.latitude=t.latitude),typeof t.longitude=="number"&&(r.longitude=t.longitude);break}case "pressKey":case "back":{typeof t.key=="string"?r.key=t.key:typeof t.code=="string"&&(r.key=t.code);break}case "setOrientation":{typeof t.orientation=="string"&&(r.orientation=t.orientation);break}case "setAirplaneMode":case "toggleAirplaneMode":{(typeof t.value=="string"||typeof t.value=="boolean")&&(r.value=t.value);break}case "setPermissions":{t.permissions&&typeof t.permissions=="object"&&(r.permissions=t.permissions);break}case "addMedia":{Array.isArray(t.mediaPaths)?r.mediaPaths=t.mediaPaths:typeof t.path=="string"&&(r.mediaPaths=[t.path]);break}case "launchApp":case "killApp":case "stopApp":case "clearState":{let n=t.appId??t.packageName??t.bundleId;typeof n=="string"&&(r.appId=n),t.arguments&&(r.arguments=t.arguments);break}case "openLink":{typeof t.url=="string"?r.url=t.url:typeof t.link=="string"&&(r.url=t.link);break}case "runScript":case "evalScript":{typeof t.path=="string"&&(r.path=t.path);let n=t.script??t.scriptString;typeof n=="string"&&(r.script=Tt(n,gn)),typeof t.sourceDescription=="string"&&(r.sourceDescription=t.sourceDescription);break}case "assertWithAI":case "assertNoDefectsWithAI":case "extractTextWithAI":{let n=t.assertion??t.prompt??t.question;typeof n=="string"&&(r.prompt=Tt(n,mn));break}case "extendedWaitUntil":case "waitForAnimationToEnd":{typeof t.timeout=="number"&&(r.timeoutMs=t.timeout);break}case "repeat":case "retry":{typeof t.times=="number"&&(r.times=t.times),typeof t.maxRetries=="number"&&(r.maxRetries=t.maxRetries),typeof t.condition=="object"&&t.condition&&(r.condition=t.condition);break}case "runFlow":{typeof t.file=="string"&&(r.file=t.file),typeof t.flowId=="string"&&(r.flowId=t.flowId);break}default:for(let n of ["text","value","url"]){let o=t[n];if(typeof o=="string"||typeof o=="number"||typeof o=="boolean"){r[n]=o;break}}}return Object.keys(r).length>0?r:void 0}function ve(e,t,r){let n=[e.commands,t.commands,t.subSteps,t.children];for(let o of n)if(Array.isArray(o)&&o.length>0)return o.map((s,i)=>ke(s,i,r));return []}function ke(e,t,r){let n,o,s,i=[];if(typeof e.command=="object"&&e.command!==null&&!Array.isArray(e.command)){let y=e.command,h=Object.keys(y)[0]??`step-${t}`;n=Rt(h);let g=y[h]??{};o=St(g),s=It(n,g),i=ve(g,e,r);}else {let y=bn(e);if(y){n=Rt(y);let h=e[y]??{};o=St(h),s=It(n,h),i=ve(h,e,r);}else n=e.command??e.commandName??e.name??`step-${t}`,o=e.selector??void 0,i=ve({},e,r);}let a=e.metadata??{},l=wn(a.status??e.status),c=a.duration??e.duration??e.durationMs??0,d=typeof a.sequenceNumber=="number"?a.sequenceNumber:void 0,u;typeof a.timestamp=="number"?u=new Date(a.timestamp).toISOString():u=e.timestamp??e.time??r;let p=e.error??e.errorMessage??void 0;return {command:n,category:Mt(n),status:l,duration:c,timestamp:u,...o?{selector:o}:{},...p?{error:p}:{},...s?{details:s}:{},...d!==void 0?{sequenceNumber:d}:{},...i.length>0?{children:i}:{}}}function wn(e){if(!e)return "completed";let t=e.toLowerCase();return t==="failed"||t==="error"?"failed":t==="skipped"?"skipped":"completed"}function Et(e,t){let r=t??new Date().toISOString();try{let n=JSON.parse(e);if(Array.isArray(n))return n.map((o,s)=>ke(o,s,r));if(typeof n=="object"&&n!==null){let o=n,s=o.commands??o.steps??o.data;if(Array.isArray(s))return s.map((i,a)=>ke(i,a,r))}return []}catch{return []}}function Ce(e,t){try{let r=readFileSync(e,"utf-8");return Et(r,t)}catch{return []}}function Re(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>basename(t).startsWith("commands")&&t.endsWith(".json")).map(t=>join(e,t))}catch{return []}}function Tn(e){let t=[];for(let r of e)if(typeof r=="object"&&r!==null){let n=r;if(typeof n.runFlow=="string")t.push(n.runFlow);else if(typeof n.runFlow=="object"&&n.runFlow!==null){let o=n.runFlow;typeof o.file=="string"&&t.push(o.file);}}return t}function Pt(e){if(!e)return [];let t=[],r=Array.isArray(e)?e:[e];for(let n of r)if(typeof n=="string")t.push(n);else if(typeof n=="object"&&n!==null){let o=n;if(typeof o.runFlow=="string")t.push(o.runFlow);else if(typeof o.runFlow=="object"&&o.runFlow!==null){let s=o.runFlow;typeof s.file=="string"&&t.push(s.file);}typeof o.runScript=="string"&&t.push(o.runScript);}return t}function _t(e,t){let r=e.split(/^---\s*$/m,2),n=r[0]??"",o=r[1]??"",s={};try{let b=parseDocument(n).toJS();typeof b=="object"&&b!==null&&!Array.isArray(b)&&(s=b);}catch{}let i=[];if(o.trim())try{let b=parseDocument(o).toJS();Array.isArray(b)&&(i=b);}catch{}let a=typeof s.appId=="string"?s.appId:null,l=typeof s.name=="string"?s.name:null,c=[];if(Array.isArray(s.tags))for(let g of s.tags)typeof g=="string"&&c.push(g);let d={};if(typeof s.env=="object"&&s.env!==null&&!Array.isArray(s.env))for(let[g,b]of Object.entries(s.env))d[g]=String(b);let u={};if(typeof s.properties=="object"&&s.properties!==null&&!Array.isArray(s.properties))for(let[g,b]of Object.entries(s.properties))u[g]=String(b);let p=Pt(s.onFlowStart),y=Pt(s.onFlowComplete),h=Tn(i);return {appId:a,name:l,tags:c,env:d,properties:u,onFlowStart:p,onFlowComplete:y,subflowRefs:h,filePath:t}}function Se(e){let t=readFileSync(e,"utf-8");return _t(t,e)}function Te(e){if(!existsSync(e))return [];let t=[];function r(n){try{let o=readdirSync(n,{withFileTypes:!0});for(let s of o){let i=join(n,s.name);if(s.isDirectory())r(i);else if(s.isFile()){let a=extname(s.name).toLowerCase();(a===".yaml"||a===".yml")&&t.push(i);}}}catch{}}return r(e),t}var Pn=/^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)\s+\[?\s*(\w+)\s*\]?\s+(.+)$/,_n=/^\[?(\d{2}:\d{2}:\d{2}(?:\.\d+)?)\]?\s+\[?\s*(\w+)\s*\]?\s+(.+)$/;function Lt(e){let t=e.toUpperCase();return t==="DEBUG"||t==="TRACE"||t==="VERBOSE"?"DEBUG":t==="INFO"?"INFO":t==="WARN"||t==="WARNING"?"WARN":t==="ERROR"||t==="FATAL"||t==="SEVERE"?"ERROR":"INFO"}function Ln(e,t){let r=/^(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/.exec(t);if(!r)return new Date().toISOString();let n=Number(r[1]),o=Number(r[2]),s=Number(r[3]),i=r[4]?Number(r[4].padEnd(3,"0")):0;return new Date(e.getFullYear(),e.getMonth(),e.getDate(),n,o,s,i).toISOString()}function Dt(e,t){let r=[],n=e.split(`
|
|
3
3
|
`),o=t instanceof Date?t:null,s=typeof t=="string"?t:t instanceof Date?`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`:new Date().toISOString().split("T")[0];for(let i of n){let a=i.trim();if(!a)continue;let l=Pn.exec(a);if(l){r.push({timestamp:l[1],level:Lt(l[2]),message:l[3],source:null});continue}if(l=_n.exec(a),l){let c=o?Ln(o,l[1]):`${s}T${l[1]}`;r.push({timestamp:c,level:Lt(l[2]),message:l[3],source:null});continue}if(r.length>0){let c=r[r.length-1];r[r.length-1]={...c,message:c.message+`
|
|
4
4
|
`+a};}}return r}function Ae(e,t){try{let r=readFileSync(e,"utf-8");return Dt(r,t)}catch{return []}}function Ie(e){for(let t of e){let r=t.message.toLowerCase();if(r.includes("android")||r.includes("adb")||r.includes("uiautomator")||r.includes("emulator"))return "android";if(r.includes("ios")||r.includes("xcuitest")||r.includes("simulator")||r.includes("xctest"))return "ios";if(r.includes("web driver")||r.includes("chrome")||r.includes("chromium"))return "web"}return "unknown"}function Me(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>basename(t)==="maestro.log"||t.endsWith(".log")).map(t=>join(e,t))}catch{return []}}var Bn=/(?:defect|issue|bug|error|warning|problem)/i,jn=/(?:critical|severe|major|blocker)/i,zn=/(?:warning|moderate|minor)/i,Ee=/(?:cut[\s-]?off|overlap|truncat|misalign|overflow|clip|obscur|hidden\s+text|broken\s+layout)/i,Q=/(?:spelling|typo|misspell|grammar)/i,Z=/(?:i18n|internationali[sz]ation|locali[sz]ation|untranslated|missing\s+translation)/i,Le=/(?:layout|spacing|padding|margin|alignment|centering|position)/i,De=/(?:accessib|a11y|contrast|screen\s*reader|alt\s*text|aria)/i;function Fe(e){return Q.test(e)?"spelling":Z.test(e)?"i18n":De.test(e)?"accessibility":Le.test(e)?"layout":"ui"}function Pe(e){return jn.test(e)?"critical":zn.test(e)?"warning":"info"}function _e(e){return e.replace(/<[^>]*>/g," ").replace(/\s+/g," ").trim()}function qn(e){let t=[],r=_e(e),n=/<li[^>]*>([\s\S]*?)<\/li>/gi,o;for(;(o=n.exec(e))!==null;){let s=o[1],i=_e(s);!i||i.length<5||(Bn.test(i)||Ee.test(i)||Q.test(i)||Z.test(i))&&t.push({type:Fe(i),severity:Pe(i),description:i,location:null,screenshot:null});}if(t.length===0){let s=/<p[^>]*>([\s\S]*?)<\/p>/gi;for(;(o=s.exec(e))!==null;){let i=_e(o[1]);!i||i.length<10||(Ee.test(i)||Q.test(i)||Z.test(i)||Le.test(i)||De.test(i))&&t.push({type:Fe(i),severity:Pe(i),description:i,location:null,screenshot:null});}}if(t.length===0&&r.length>20){let s=r.split(/[.!?]+/).filter(i=>i.trim().length>10);for(let i of s){let a=i.trim();(Ee.test(a)||Q.test(a)||Z.test(a)||Le.test(a)||De.test(a))&&t.push({type:Fe(a),severity:Pe(a),description:a,location:null,screenshot:null});}}return t}function Nt(e){let t=qn(e);return {defects:t,totalDefects:t.length,hasIssues:t.length>0,rawHtml:e}}function Ne(e){try{let t=readFileSync(e,"utf-8");return Nt(t)}catch{return {defects:[],totalDefects:0,hasIssues:false,rawHtml:null}}}function Oe(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>{let r=basename(t).toLowerCase();return extname(t).toLowerCase()===".html"&&(r.includes("insight")||r.includes("ai")||r.includes("analysis"))}).map(t=>join(e,t))}catch{return []}}var Yn=new Set([".png",".jpg",".jpeg",".webp"]),Xn=new Set([".mp4",".webm",".mov"]);function Ot(e){let t=[];if(!existsSync(e))return t;function r(n){try{let o=readdirSync(n,{withFileTypes:!0});for(let s of o){let i=join(n,s.name);s.isDirectory()?r(i):s.isFile()&&t.push(i);}}catch{}}return r(e),t}function Ue(e,t){let r=[],n=[],o=[],s=[],i=[],a=null,l=[];e&&l.push(...Ot(e)),t&&l.push(...Ot(t));let c=new Set;for(let d of l){if(c.has(d))continue;c.add(d);let u=basename(d).toLowerCase(),p=extname(d).toLowerCase();if(Yn.has(p)){r.push(d);continue}if(Xn.has(p)){n.push(d);continue}if(u==="maestro.log"||p===".log"&&u.includes("maestro")){o.push(d);continue}if(u.startsWith("commands")&&p===".json"){s.push(d);continue}if(p===".html"&&(u.includes("insight")||u.includes("ai")||u.includes("analysis"))){i.push(d);continue}if(p===".xml"&&(u.includes("report")||u.includes("junit"))){a||(a=d);continue}}return {screenshotPaths:r,videoPaths:n,logPaths:o,commandJsonPaths:s,aiReportPaths:i,junitReportPath:a}}function Qn(e){return {screenshots:e.screenshotPaths.length,videos:e.videoPaths.length,logs:e.logPaths.length,commandFiles:e.commandJsonPaths.length,aiReports:e.aiReportPaths.length,junitReport:e.junitReportPath?1:0}}function Zn(e){switch(e){case "interaction":return "ui_action";case "assertion":return "assertion";case "ai":return "assertion";case "navigation":return "navigation";case "device":return "custom_step";case "media":return "custom_step";case "script":return "custom_step";case "flow_control":return "custom_step";case "recording":return "custom_step";default:return "custom_step"}}function eo(e){let t=e.details;if(t)switch(e.command){case "inputText":case "pasteText":if(typeof t.text=="string")return `${e.command} \u2192 ${t.text}`;break;case "swipe":case "scroll":case "scrollUntilVisible":if(typeof t.direction=="string")return `${e.command} ${t.direction}`;break;case "setLocation":if(typeof t.latitude=="number"&&typeof t.longitude=="number")return `setLocation ${t.latitude},${t.longitude}`;break;case "pressKey":if(typeof t.key=="string")return `pressKey ${t.key}`;break;case "setOrientation":if(typeof t.orientation=="string")return `setOrientation ${t.orientation}`;break;case "launchApp":case "killApp":case "stopApp":case "clearState":if(typeof t.appId=="string")return `${e.command} ${t.appId}`;break;case "openLink":if(typeof t.url=="string")return `openLink ${t.url}`;break;case "runScript":case "evalScript":if(typeof t.path=="string")return `${e.command} ${t.path}`;if(typeof t.sourceDescription=="string")return `${e.command} ${t.sourceDescription}`;if(typeof t.script=="string")return `${e.command} ${t.script}`;break;case "assertWithAI":case "assertNoDefectsWithAI":case "extractTextWithAI":if(typeof t.prompt=="string")return `${e.command} \u2192 ${t.prompt}`;break;case "retry":if(typeof t.maxRetries=="number")return `retry \xD7 ${t.maxRetries}`;break;case "repeat":if(typeof t.times=="number")return `repeat \xD7 ${t.times}`;break;case "runFlow":if(typeof t.file=="string")return `runFlow ${t.file}`;break}return e.selector?`${e.command} \u2192 ${e.selector}`:e.command}function He(e,t){let r=Date.parse(e.timestamp),n=Number.isFinite(r)&&Number.isFinite(t)?Math.max(0,(r-t)/1e3):null,o=(e.children??[]).map(s=>He(s,t));return {title:eo(e),category:Zn(e.category),status:e.status==="failed"?"failed":"passed",duration:e.duration,timestamp:e.timestamp,videoOffset:n,error:e.error??null,children:o}}function to(e,t){let r=Date.parse(e.timestamp),n=Date.parse(t.timestamp);return Number.isFinite(r)&&Number.isFinite(n)&&r!==n?r-n:0}function ro(e,t){let r=Date.parse(e.startedAt),n=[...e.commands].sort((l,c)=>{let d=Date.parse(l.timestamp),u=Date.parse(c.timestamp);if(Number.isFinite(d)&&Number.isFinite(u)&&d!==u)return d-u;let p=l.sequenceNumber??0,y=c.sequenceNumber??0;return p-y}),o=[...e.assertions].sort((l,c)=>{let d=Date.parse(l.timestamp),u=Date.parse(c.timestamp);if(Number.isFinite(d)&&Number.isFinite(u)&&d!==u)return d-u;let p=l.sequenceNumber??0,y=c.sequenceNumber??0;return p-y}),s=[...n.map(l=>He(l,r)),...o.map(l=>He(l,r))];s.sort(to);let i=e.screenshotPaths.length>0||e.videoPath?{screenshot:e.screenshotPaths[0]??void 0,video:e.videoPath??void 0}:null,a=[...e.tags];return e.platform!=="unknown"&&!a.includes(e.platform)&&a.push(e.platform),{title:e.flowName,status:e.status,duration:e.duration,startedAt:e.startedAt,completedAt:e.completedAt,retryCount:0,tags:a,failure:e.failureMessage?{message:e.failureMessage,line:null,code:null,stack:null}:null,testId:`${e.flowFile}::${e.flowName}`,filePath:e.flowFile,suiteName:e.appId??"maestro-suite",testType:"mobile",isFlaky:false,retryStatus:null,expectedStatus:"passed",actualStatus:e.status,artifacts:i,networkRequests:null,apiCalls:t.length>0?[...t]:null,apiAssertions:null,actions:s.length>0?s:null,consoleLogs:null}}function Ut(e,t){let r=`${e.flowFile}::${e.flowName}`,n=t?.get(r)??[],o=ro(e,n);return {url:e.appId??"maestro-flow",navigationType:"page_load",visitedAt:e.startedAt,duration:e.duration,specFile:e.flowFile,domContentLoadedAt:null,networkIdleAt:null,networkStats:null,tests:[o]}}function $e(e,t){return e.map(r=>Ut(r,t))}var Ht={"2xx":0,"3xx":0,"4xx":0,"5xx":0,error:0};function no(e){return e===null?"error":e>=200&&e<300?"2xx":e>=300&&e<400?"3xx":e>=400&&e<500?"4xx":e>=500&&e<600?"5xx":"error"}function Be(e,t){if(e.length===0)return null;let r=Math.min(e.length-1,Math.floor(t/100*e.length));return e[r]}function oo(e){if(e.length===0)return {totalApiCalls:0,uniqueApiUrls:0,apiCallsByMethod:{},apiCallsByStatusRange:{...Ht},apiResponseTime:null};let t={},r={...Ht},n=new Set,o=[];for(let i of e)t[i.method]=(t[i.method]??0)+1,r[no(i.responseStatusCode)]+=1,n.add(i.url),Number.isFinite(i.responseTimeMs)&&i.responseTimeMs>0&&o.push(i.responseTimeMs);o.sort((i,a)=>i-a);let s=o.length>0?{p50:Be(o,50)??0,p95:Be(o,95)??0,p99:Be(o,99)??0,avg:o.reduce((i,a)=>i+a,0)/o.length,min:o[0],max:o[o.length-1]}:null;return {totalApiCalls:e.length,uniqueApiUrls:n.size,apiCallsByMethod:t,apiCallsByStatusRange:r,apiResponseTime:s}}function G(e){let t=0,r=0,n=0,o=0,s=0,i=0,a=0,l=0,c=0,d=e.length,u=0,p={},y=new Set,h=[];for(let b of e){y.add(b.url);for(let x of b.tests){switch(t++,x.status){case "passed":r++;break;case "failed":n++;break;case "flaky":o++;break;case "skipped":s++;break;case "timedout":i++;break}if(x.actions)for(let T of x.actions)if(u++,T.category==="assertion")a++,T.status==="passed"?l++:c++;else {let R=T.category;p[R]=(p[R]??0)+1;}x.apiCalls&&x.apiCalls.length>0&&h.push(...x.apiCalls);}}let g=oo(h);return {total:t,passed:r,failed:n,flaky:o,skipped:s,timedout:i,...g,totalAssertions:a,passedAssertions:l,failedAssertions:c,totalNavigations:d,uniqueNavigationUrls:y.size,totalTimelineSteps:e.length,totalActionSteps:u,actionStepsByCategory:p}}var $t=`
|
|
@@ -1231,9 +1231,9 @@ document.addEventListener('keydown',function(e){
|
|
|
1231
1231
|
`}function qe(e,t,r,n,o){if(n||e.total===0)return;let s=`\u250C${"\u2500".repeat(62)}\u2510
|
|
1232
1232
|
`,i=`\u2514${"\u2500".repeat(62)}\u2518
|
|
1233
1233
|
`,a=O(""),l=s;l+=O("TestRelic AI - Maestro Test Report"),l+=a;let c=[];if(e.passed>0&&c.push(`${e.passed} \u2713`),e.failed>0&&c.push(`${e.failed} \u2717`),e.flaky>0&&c.push(`${e.flaky} \u26A0`),e.skipped>0&&c.push(`${e.skipped} skipped`),e.timedout>0&&c.push(`${e.timedout} timedout`),l+=O(`Flows: ${e.total} total (${c.join(" ")})`),e.totalAssertions>0&&(l+=O(`Assertions: ${e.totalAssertions} total (${e.passedAssertions} \u2713 ${e.failedAssertions} \u2717)`)),e.totalActionSteps>0){let d=[],u=e.actionStepsByCategory;u.ui_action&&d.push(`${u.ui_action} UI`),u.navigation&&d.push(`${u.navigation} nav`),u.custom_step&&d.push(`${u.custom_step} custom`);let p=d.length>0?` (${d.join(" ")})`:"";l+=O(`Steps: ${e.totalActionSteps} total${p}`);}if(o&&o.length>0){let d=o.filter(h=>h.severity==="critical").length,u=o.filter(h=>h.severity==="warning").length,p=o.filter(h=>h.severity==="info").length,y=[];d>0&&y.push(`${d} critical`),u>0&&y.push(`${u} warning`),p>0&&y.push(`${p} info`),l+=O(`AI Defects: ${o.length} found (${y.join(" ")})`);}l+=O(`Report: ${r}`),l+=O(`Data: ${t}`),l+=i,l+=`For more information visit us at https://docs.testrelic.ai
|
|
1234
|
-
`,process.stderr.write(l);}function Ge(e){let t=process.platform,r;t==="darwin"?r
|
|
1235
|
-
`),null;let o=vo(e.outputDir??t.outputDir??void 0),s=join(o,"network.jsonl"),i=["--listen-host",t.proxyHost,"--listen-port",String(t.proxyPort),"-s",n,"--set",`testrelic_output=${s}`,"--set",`testrelic_redact_headers=${t.redactHeaders.join(",")}`,"--set",`testrelic_redact_body_fields=${t.redactBodyFields.join(",")}`,"--set",`testrelic_max_body_bytes=${t.maxBodyBytes}`,"--set","console_eventlog_verbosity=warn","--set","termlog_verbosity=warn"],a;try{a=spawn("mitmdump",i,{stdio:["ignore","pipe","pipe"]
|
|
1236
|
-
`),null}a.stdout?.on("data",c=>{r&&process.stderr.write(`[mitmdump] ${c.toString("utf-8")}`);}),a.stderr?.on("data",c=>{r&&process.stderr.write(`[mitmdump] ${c.toString("utf-8")}`);}),await new Promise(c=>setTimeout(c,750));let l=()=>new Promise(c=>{if(a.killed||a.exitCode!==null){c();return}let d=false,u=()=>{d||(d=true,c());};a.once("close",u),a.once("exit",u);try{a.kill("SIGINT");}catch{try{a.kill();}catch{}}setTimeout(()=>{if(!d){try{a.kill("SIGKILL");}catch{}u();}},4e3);});return {outputPath:s,outputDir:o,host:t.proxyHost,port:t.proxyPort,stop:l}}var $={teardown:async()=>{}};function er(e){let t=spawnSync(e,["--version"],{
|
|
1234
|
+
`,process.stderr.write(l);}function Ge(e){let t=process.platform,r,n;t==="darwin"?(r="open",n=[e]):t==="win32"?(r="cmd",n=["/c","start","",e]):(r="xdg-open",n=[e]),execFile(r,n,()=>{});}function wo(){let e=[];try{let r=dirname(fileURLToPath(import.meta.url));e.push(join(r,"proxy-addon","testrelic_capture.py")),e.push(join(r,"..","src","proxy-addon","testrelic_capture.py"));}catch{}let t=globalThis.__dirname;t&&e.push(join(t,"proxy-addon","testrelic_capture.py"));for(let r of e)if(existsSync(r))return resolve(r);return null}function vo(e){if(e)return mkdirSync(e,{recursive:true}),e;let t=randomBytes(6).toString("hex"),r=join(tmpdir(),`testrelic-maestro-network-${t}`);return mkdirSync(r,{recursive:true}),r}async function ko(){return new Promise(e=>{let t=spawn("mitmdump",["--version"]),r=false,n=o=>{r||(r=true,e(o));};t.on("error",()=>n(false)),t.on("close",o=>n(o===0)),setTimeout(()=>{try{t.kill();}catch{}n(false);},5e3);})}async function Xt(e){let{config:t,verbose:r=true}=e;if(!t.enabled)return null;if(!await ko())return r&&process.stderr.write("\u26A0 TestRelic: --capture-network requested but `mitmdump` is not on PATH.\n Install mitmproxy (`brew install mitmproxy` / `pipx install mitmproxy`)\n or supply --har-path to import a HAR file instead.\n"),null;let n=wo();if(!n)return r&&process.stderr.write(`\u26A0 TestRelic: network-capture addon not found in package; skipping capture.
|
|
1235
|
+
`),null;let o=vo(e.outputDir??t.outputDir??void 0),s=join(o,"network.jsonl"),i=["--listen-host",t.proxyHost,"--listen-port",String(t.proxyPort),"-s",n,"--set",`testrelic_output=${s}`,"--set",`testrelic_redact_headers=${t.redactHeaders.join(",")}`,"--set",`testrelic_redact_body_fields=${t.redactBodyFields.join(",")}`,"--set",`testrelic_max_body_bytes=${t.maxBodyBytes}`,"--set","console_eventlog_verbosity=warn","--set","termlog_verbosity=warn"],a;try{a=spawn("mitmdump",i,{stdio:["ignore","pipe","pipe"]});}catch(c){return r&&process.stderr.write(`\u26A0 TestRelic: failed to spawn mitmdump: ${c.message}
|
|
1236
|
+
`),null}a.stdout?.on("data",c=>{r&&process.stderr.write(`[mitmdump] ${c.toString("utf-8")}`);}),a.stderr?.on("data",c=>{r&&process.stderr.write(`[mitmdump] ${c.toString("utf-8")}`);}),await new Promise(c=>setTimeout(c,750));let l=()=>new Promise(c=>{if(a.killed||a.exitCode!==null){c();return}let d=false,u=()=>{d||(d=true,c());};a.once("close",u),a.once("exit",u);try{a.kill("SIGINT");}catch{try{a.kill();}catch{}}setTimeout(()=>{if(!d){try{a.kill("SIGKILL");}catch{}u();}},4e3);});return {outputPath:s,outputDir:o,host:t.proxyHost,port:t.proxyPort,stop:l}}var $={teardown:async()=>{}};function er(e){let t=spawnSync(e,["--version"],{stdio:"ignore"});return t.error===void 0||t.error.code!=="ENOENT"}function E(e,t){e||process.stderr.write(`${t}
|
|
1237
1237
|
`);}function U(e,t,r,n){e||(t==="android"?process.stderr.write(`\u2139 TestRelic: real-device Android capture \u2014 set the device proxy manually:
|
|
1238
1238
|
Settings \u2192 Wi-Fi \u2192 (long-press your network) \u2192 Modify \u2192 Proxy: Manual
|
|
1239
1239
|
Host: ${r} Port: ${n}
|
|
@@ -1244,14 +1244,14 @@ document.addEventListener('keydown',function(e){
|
|
|
1244
1244
|
Then install + TRUST the mitmproxy CA:
|
|
1245
1245
|
1. Open http://mitm.it from Safari on the device \u2192 install profile.
|
|
1246
1246
|
2. Settings \u2192 General \u2192 About \u2192 Certificate Trust Settings \u2192 enable mitmproxy.
|
|
1247
|
-
`));}async function Qt(e,t){return new Promise(r=>{let n=t?["-s",t,...e]:e,o=spawn("adb",n,{
|
|
1247
|
+
`));}async function Qt(e,t){return new Promise(r=>{let n=t?["-s",t,...e]:e,o=spawn("adb",n,{stdio:["ignore","pipe","pipe"]}),s="",i="";o.stdout?.on("data",a=>{s+=a.toString();}),o.stderr?.on("data",a=>{i+=a.toString();}),o.on("error",()=>r({code:127,stdout:s,stderr:i||"adb not on PATH"})),o.on("close",a=>r({code:a??1,stdout:s,stderr:i}));})}async function To(e){let{deviceId:t,proxyHost:r,proxyPort:n,quiet:o,skipCertInstall:s}=e;if(!er("adb"))return E(o,"\u26A0 TestRelic: `adb` not on PATH; skipping automatic Android proxy setup. See manual instructions:"),U(o,"android",r,n),$;let i=await Qt(["shell","settings","put","global","http_proxy",`${r}:${n}`],t);return i.code!==0?(E(o,`\u26A0 TestRelic: adb set proxy failed: ${i.stderr.trim()||"unknown error"}`),U(o,"android",r,n),$):(E(o,`\u2139 TestRelic: Android proxy set to ${r}:${n} on ${t??"default device"}.`),s||E(o,`\u2139 TestRelic: if HTTPS calls fail, install the mitmproxy CA on the emulator:
|
|
1248
1248
|
open http://mitm.it from Chrome on the emulator and follow prompts,
|
|
1249
1249
|
OR for a system-level install:
|
|
1250
1250
|
adb root && adb remount && adb push <mitm-ca>.0 /system/etc/security/cacerts/ && adb reboot
|
|
1251
|
-
Set --skip-cert-install to silence this hint.`),{teardown:async()=>{await Qt(["shell","settings","put","global","http_proxy",":0"],t);}})}async function Ao(e){return new Promise(t=>{let r=spawn("xcrun",e,{
|
|
1251
|
+
Set --skip-cert-install to silence this hint.`),{teardown:async()=>{await Qt(["shell","settings","put","global","http_proxy",":0"],t);}})}async function Ao(e){return new Promise(t=>{let r=spawn("xcrun",e,{stdio:["ignore","pipe","pipe"]}),n="",o="";r.stdout?.on("data",s=>{n+=s.toString();}),r.stderr?.on("data",s=>{o+=s.toString();}),r.on("error",()=>t({code:127,stdout:n,stderr:o||"xcrun not on PATH"})),r.on("close",s=>t({code:s??1,stdout:n,stderr:o}));})}async function Io(e){let{proxyHost:t,proxyPort:r,quiet:n,skipCertInstall:o}=e;if(process.platform!=="darwin")return E(n,"\u26A0 TestRelic: iOS simulator capture requires macOS; the host is not Darwin. Skipping setup."),U(n,"ios",t,r),$;if(!er("xcrun"))return E(n,"\u26A0 TestRelic: `xcrun` not on PATH; skipping automatic iOS simulator setup."),U(n,"ios",t,r),$;if(!o){let s=join(process.env.HOME??"",".mitmproxy","mitmproxy-ca-cert.pem");if(existsSync(s)){let i=e.deviceId??"booted",a=await Ao(["simctl","keychain",i,"add-root-cert",s]);a.code===0?E(n,`\u2139 TestRelic: installed mitmproxy CA on iOS simulator (${i}).`):(E(n,`\u26A0 TestRelic: failed to add-root-cert via simctl: ${a.stderr.trim()}`),U(n,"ios",t,r));}else E(n,`\u26A0 TestRelic: mitmproxy CA not found at ${s}. Run mitmdump once to generate it,
|
|
1252
1252
|
then re-run with --capture-network. Falling back to manual instructions:`),U(n,"ios",t,r);}return E(n,`\u2139 TestRelic: in the iOS simulator, configure Wi-Fi \u2192 (i) \u2192 Manual proxy:
|
|
1253
1253
|
Server: ${t} Port: ${r}
|
|
1254
|
-
(We do not set host-wide \`networksetup\` proxy automatically; see docs.)`),$}async function tr(e){switch(e.platform){case "android":return To(e);case "ios":return Io(e);case "web":return E(e.quiet,"\u2139 TestRelic: --capture-network ignored for Maestro web flows (browser already handles HTTP)."),$;default:return E(e.quiet,"\u26A0 TestRelic: target platform unknown; printing manual proxy setup instructions:"),U(e.quiet,"android",e.proxyHost,e.proxyPort),U(e.quiet,"ios",e.proxyHost,e.proxyPort),$}}function _o(){let e=randomBytes(8).toString("hex");return join(tmpdir(),`testrelic-maestro-${e}`)}function nr(e,t){let r=[];e.platform&&r.push("--platform",e.platform),e.device&&r.push("--device",e.device),r.push("test");let n=join(t,"report.xml"),o=join(t,"artifacts"),s=join(t,"debug");if(r.push("--format","junit"),r.push("--output",n),r.push("--test-output-dir",o),r.push("--debug-output",s),e.analyze&&r.push("--analyze"),e.includeTags&&r.push("--include-tags",e.includeTags),e.excludeTags&&r.push("--exclude-tags",e.excludeTags),e.shards&&e.shards>1&&r.push("--shards",String(e.shards)),e.config&&r.push("--config",e.config),e.env)for(let[i,a]of Object.entries(e.env))r.push("-e",`${i}=${a}`);return e.maestroArgs&&r.push(...e.maestroArgs),r.push(...e.flowPaths),r}function Lo(e){switch((e??"").toLowerCase()){case "android":return "android";case "ios":return "ios";case "web":return "web";default:return "unknown"}}function Do(e,t,r,n,o,s,i){return new Promise(a=>{let l=[],c=[],d=spawn("maestro",e,{stdio:["inherit","pipe","pipe"],shell:true});d.stdout.on("data",u=>{l.push(u),s||process.stdout.write(u);}),d.stderr.on("data",u=>{c.push(u),s||process.stderr.write(u);}),d.on("close",async u=>{try{await i();}catch{}a({exitCode:u??1,junitPath:t,testOutputDir:r,debugOutputDir:n,stdout:Buffer.concat(l).toString("utf-8"),stderr:Buffer.concat(c).toString("utf-8"),networkJsonlDir:o});}),d.on("error",async u=>{try{await i();}catch{}a({exitCode:127,junitPath:t,testOutputDir:r,debugOutputDir:n,stdout:"",stderr:`Failed to start maestro CLI: ${u.message}`,networkJsonlDir:o});});})}async function No(e,t={}){let r=e.outputDir?resolve(e.outputDir):_o();mkdirSync(join(r,"artifacts"),{recursive:true}),mkdirSync(join(r,"debug"),{recursive:true});let n=nr(e,r),o=join(r,"report.xml"),s=join(r,"artifacts"),i=join(r,"debug"),a=null,l=null,c=t.network;if(c?.enabled){let p=join(r,"network");a=await Xt({config:c,outputDir:p,verbose:!e.quiet}),a&&(l=await tr({platform:Lo(e.platform),deviceId:e.device,proxyHost:a.host,proxyPort:a.port,skipCertInstall:c.skipCertInstall,quiet:e.quiet}));}let d=a?.outputDir??null,u=async()=>{if(a&&await new Promise(p=>setTimeout(p,500)),l)try{await l.teardown();}catch{}if(a)try{await a.stop();}catch{}};return Do(n,o,s,i,d,e.quiet,u)}var ir="[REDACTED]";function or(e,t){if(!e)return null;let r=new Set(t.map(o=>o.toLowerCase())),n={};for(let[o,s]of Object.entries(e))n[o]=r.has(o.toLowerCase())?ir:s;return n}function Ve(e,t){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(n=>Ve(n,t));let r={};for(let[n,o]of Object.entries(e))r[n]=t.has(n)?ir:Ve(o,t);return r}function sr(e,t){if(!e||t.length===0)return e;try{let r=JSON.parse(e),n=Ve(r,new Set(t));return JSON.stringify(n)}catch{return e}}function Je(e,t,r){return {...e,requestHeaders:or(e.requestHeaders,t),responseHeaders:or(e.responseHeaders,t),requestBody:sr(e.requestBody,r),responseBody:e.isBinary?e.responseBody:sr(e.responseBody,r)}}function We(e,t,r){let n=o=>typeof o=="string"?e.includes(o):o.test(e);return r.some(n)?false:t.length===0?true:t.some(n)}function Ho(e){let t=e.trim();if(!t)return null;try{let r=JSON.parse(t);return typeof r.url!="string"||typeof r.method!="string"?null:{id:r.id??`api-call-${Date.now()}`,timestamp:r.timestamp??new Date().toISOString(),method:r.method,url:r.url,requestHeaders:r.requestHeaders??null,requestBody:r.requestBody??null,responseStatusCode:r.responseStatusCode??null,responseStatusText:r.responseStatusText??null,responseHeaders:r.responseHeaders??null,responseBody:r.responseBody??null,responseTimeMs:typeof r.responseTimeMs=="number"?r.responseTimeMs:0,isBinary:r.isBinary??!1,error:r.error??null}}catch{return null}}function $o(e,t){let r=[];for(let n of e.split(/\r?\n/)){let o=Ho(n);o&&We(o.url,t.includeUrls,t.excludeUrls)&&r.push(Je(o,t.redactHeaders,t.redactBodyFields));}return r}function Bo(e,t){try{return $o(readFileSync(e,"utf-8"),t)}catch{return []}}function jo(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>t.endsWith(".jsonl")).map(t=>join(e,t))}catch{return []}}function ar(e){if(!e||e.length===0)return null;let t={};for(let r of e)typeof r.name=="string"&&typeof r.value=="string"&&(t[r.name]=r.value);return Object.keys(t).length>0?t:null}function zo(e){return e?typeof e.text=="string"?e.text:Array.isArray(e.params)?e.params.map(t=>`${encodeURIComponent(t.name)}=${encodeURIComponent(t.value??"")}`).join("&"):null:null}function qo(e){return e?/^(image|audio|video|application\/(octet-stream|pdf|zip|protobuf))/.test(e):false}function Go(e,t){let r=e.request,n=e.response;if(!r?.method||!r.url)return null;let o=n?.content,s=qo(o?.mimeType);return {id:`har-call-${t}`,timestamp:e.startedDateTime??new Date().toISOString(),method:r.method,url:r.url,requestHeaders:ar(r.headers),requestBody:zo(r.postData),responseStatusCode:typeof n?.status=="number"&&n.status>0?n.status:null,responseStatusText:n?.statusText??null,responseHeaders:ar(n?.headers),responseBody:o?.text??null,responseTimeMs:typeof e.time=="number"?e.time:0,isBinary:s,error:null}}function Vo(e,t){let r;try{r=JSON.parse(e);}catch{return []}let n=r.log?.entries??[],o=[];return n.forEach((s,i)=>{let a=Go(s,i);a&&We(a.url,t.includeUrls,t.excludeUrls)&&o.push(Je(a,t.redactHeaders,t.redactBodyFields));}),o}function Jo(e,t){try{return Vo(readFileSync(e,"utf-8"),t)}catch{return []}}function Wo(e,t){let r=new Map;for(let o of t)r.set(o.testId,[]);if(e.length===0||t.length===0)return r;let n=t.map(o=>({testId:o.testId,startMs:Date.parse(o.startedAt),endMs:Date.parse(o.completedAt)}));for(let o of e){let s=Date.parse(o.timestamp);if(!Number.isFinite(s))continue;let i=n.find(l=>Number.isFinite(l.startMs)&&Number.isFinite(l.endMs)&&s>=l.startMs&&s<=l.endMs);if(i){r.get(i.testId).push(o);continue}let a=null;for(let l of n){if(!Number.isFinite(l.startMs)||!Number.isFinite(l.endMs))continue;let c=s<l.startMs?l.startMs-s:s-l.endMs;(!a||c<a.dist)&&(a={testId:l.testId,dist:c});}a&&r.get(a.testId).push(o);}return r}function dr(e,t,r){if(!t.enabled&&!t.harPath)return new Map;let n=[];if(e)for(let o of jo(e))n.push(...Bo(o,t));return t.harPath&&existsSync(t.harPath)&&n.push(...Jo(t.harPath,t)),n.length===0?new Map:Wo(n,r)}function ur(e){return e.map((t,r)=>({...t,id:`api-call-${r}`}))}var Xo=new Set(["localhost","127.0.0.1","0.0.0.0"]);function Ke(e){let t=new URL(e);if(t.protocol!=="https:"&&!(t.protocol==="http:"&&Xo.has(t.hostname)))throw createError(ErrorCode.CLOUD_CONFIG_INVALID,`HTTPS is required for cloud communication. Got: ${t.protocol}//${t.hostname}`)}var Qo=3e3;async function ee(e){let t=new AbortController,r=setTimeout(()=>t.abort(),Qo);try{return (await fetch(`${e}/health`,{method:"GET",signal:t.signal})).ok}catch{return false}finally{clearTimeout(r);}}async function fr(e){return new Promise(t=>setTimeout(t,e))}async function pr(e){try{let r=(await e.json()).error;if(r&&typeof r.message=="string")return r.message}catch{}return `HTTP ${e.status}`}async function te(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),r);try{let s=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(s.ok){let a=await s.json();return {accessToken:a.accessToken,refreshToken:a.refreshToken,expiresIn:a.expiresIn,orgId:a.orgId,orgName:a.orgName,userId:a.userId,userName:a.userName}}if(s.status===429){let a=s.headers.get("Retry-After"),l=a?parseInt(a,10)*1e3:5e3;if(!isNaN(l)&&l>0){await fr(l);let c=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(c.ok){let d=await c.json();return {accessToken:d.accessToken,refreshToken:d.refreshToken,expiresIn:d.expiresIn,orgId:d.orgId,orgName:d.orgName,userId:d.userId,userName:d.userName}}}return {code:"rate_limited",message:"Rate limited during token exchange.",statusCode:429}}return s.status===400?{code:"validation_error",message:await pr(s),statusCode:400}:s.status===401?{code:"invalid_key",message:"API key is invalid or has been revoked.",statusCode:401}:s.status===403?{code:"expired_key",message:"API key has expired.",statusCode:403}:{code:"server_error",message:await pr(s),statusCode:s.status}}catch(s){return s instanceof DOMException&&s.name==="AbortError"?{code:"timeout",message:"Token exchange timed out.",statusCode:null}:{code:"network_error",message:"Failed to reach cloud for token exchange.",statusCode:null}}finally{clearTimeout(o);}}function re(e){return "code"in e&&typeof e.code=="string"&&["invalid_key","expired_key","validation_error","rate_limited","server_error","network_error","timeout"].includes(e.code)}async function Ye(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),r);try{let s=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal});if(s.status===429){let a=s.headers.get("Retry-After"),l=a?parseInt(a,10)*1e3:5e3;!isNaN(l)&&l>0&&(await fr(l),s=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal}));}if(!s.ok)return null;let i=await s.json();return {accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn}}catch{return null}finally{clearTimeout(o);}}async function Xe(e,t,r,n,o,s){let i=new AbortController,a=setTimeout(()=>i.abort(),o);try{let l={gitId:r,displayName:n};s&&(l.branch=s);let c=await fetch(`${e}/repos/resolve`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(l),signal:i.signal});if(!c.ok)return null;let d=await c.json();return {repoId:d.repoId,displayName:d.displayName}}catch{return null}finally{clearTimeout(a);}}var ns=5e3;function H(e,t){try{return execSync(e,{cwd:t,timeout:ns,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}function Qe(e){let t=H("git rev-parse --abbrev-ref HEAD",e),r=H("git rev-parse --short HEAD",e),n=H("git log -1 --pretty=%s",e),o=H("git log -1 --format=%an",e)??H("git config user.name",e),s=os(e),i=s?j(s):null;return {branch:t,commitSha:r,commitMessage:n,commitAuthor:o,remoteUrl:i}}function os(e){let t=H("git remote get-url origin",e);if(t)return t;let r=H("git remote",e);if(!r)return null;let n=r.split(`
|
|
1254
|
+
(We do not set host-wide \`networksetup\` proxy automatically; see docs.)`),$}async function tr(e){switch(e.platform){case "android":return To(e);case "ios":return Io(e);case "web":return E(e.quiet,"\u2139 TestRelic: --capture-network ignored for Maestro web flows (browser already handles HTTP)."),$;default:return E(e.quiet,"\u26A0 TestRelic: target platform unknown; printing manual proxy setup instructions:"),U(e.quiet,"android",e.proxyHost,e.proxyPort),U(e.quiet,"ios",e.proxyHost,e.proxyPort),$}}function _o(){let e=randomBytes(8).toString("hex");return join(tmpdir(),`testrelic-maestro-${e}`)}function nr(e,t){let r=[];e.platform&&r.push("--platform",e.platform),e.device&&r.push("--device",e.device),r.push("test");let n=join(t,"report.xml"),o=join(t,"artifacts"),s=join(t,"debug");if(r.push("--format","junit"),r.push("--output",n),r.push("--test-output-dir",o),r.push("--debug-output",s),e.analyze&&r.push("--analyze"),e.includeTags&&r.push("--include-tags",e.includeTags),e.excludeTags&&r.push("--exclude-tags",e.excludeTags),e.shards&&e.shards>1&&r.push("--shards",String(e.shards)),e.config&&r.push("--config",e.config),e.env)for(let[i,a]of Object.entries(e.env))r.push("-e",`${i}=${a}`);return e.maestroArgs&&r.push(...e.maestroArgs),r.push(...e.flowPaths),r}function Lo(e){switch((e??"").toLowerCase()){case "android":return "android";case "ios":return "ios";case "web":return "web";default:return "unknown"}}function Do(e,t,r,n,o,s,i){return new Promise(a=>{let l=[],c=[],d=spawn("maestro",e,{stdio:["inherit","pipe","pipe"]});d.stdout.on("data",u=>{l.push(u),s||process.stdout.write(u);}),d.stderr.on("data",u=>{c.push(u),s||process.stderr.write(u);}),d.on("close",async u=>{try{await i();}catch{}a({exitCode:u??1,junitPath:t,testOutputDir:r,debugOutputDir:n,stdout:Buffer.concat(l).toString("utf-8"),stderr:Buffer.concat(c).toString("utf-8"),networkJsonlDir:o});}),d.on("error",async u=>{try{await i();}catch{}a({exitCode:127,junitPath:t,testOutputDir:r,debugOutputDir:n,stdout:"",stderr:`Failed to start maestro CLI: ${u.message}`,networkJsonlDir:o});});})}async function No(e,t={}){let r=e.outputDir?resolve(e.outputDir):_o();mkdirSync(join(r,"artifacts"),{recursive:true}),mkdirSync(join(r,"debug"),{recursive:true});let n=nr(e,r),o=join(r,"report.xml"),s=join(r,"artifacts"),i=join(r,"debug"),a=null,l=null,c=t.network;if(c?.enabled){let p=join(r,"network");a=await Xt({config:c,outputDir:p,verbose:!e.quiet}),a&&(l=await tr({platform:Lo(e.platform),deviceId:e.device,proxyHost:a.host,proxyPort:a.port,skipCertInstall:c.skipCertInstall,quiet:e.quiet}));}let d=a?.outputDir??null,u=async()=>{if(a&&await new Promise(p=>setTimeout(p,500)),l)try{await l.teardown();}catch{}if(a)try{await a.stop();}catch{}};return Do(n,o,s,i,d,e.quiet,u)}var ir="[REDACTED]";function or(e,t){if(!e)return null;let r=new Set(t.map(o=>o.toLowerCase())),n={};for(let[o,s]of Object.entries(e))n[o]=r.has(o.toLowerCase())?ir:s;return n}function Ve(e,t){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(n=>Ve(n,t));let r={};for(let[n,o]of Object.entries(e))r[n]=t.has(n)?ir:Ve(o,t);return r}function sr(e,t){if(!e||t.length===0)return e;try{let r=JSON.parse(e),n=Ve(r,new Set(t));return JSON.stringify(n)}catch{return e}}function Je(e,t,r){return {...e,requestHeaders:or(e.requestHeaders,t),responseHeaders:or(e.responseHeaders,t),requestBody:sr(e.requestBody,r),responseBody:e.isBinary?e.responseBody:sr(e.responseBody,r)}}function We(e,t,r){let n=o=>typeof o=="string"?e.includes(o):o.test(e);return r.some(n)?false:t.length===0?true:t.some(n)}function Ho(e){let t=e.trim();if(!t)return null;try{let r=JSON.parse(t);return typeof r.url!="string"||typeof r.method!="string"?null:{id:r.id??`api-call-${Date.now()}`,timestamp:r.timestamp??new Date().toISOString(),method:r.method,url:r.url,requestHeaders:r.requestHeaders??null,requestBody:r.requestBody??null,responseStatusCode:r.responseStatusCode??null,responseStatusText:r.responseStatusText??null,responseHeaders:r.responseHeaders??null,responseBody:r.responseBody??null,responseTimeMs:typeof r.responseTimeMs=="number"?r.responseTimeMs:0,isBinary:r.isBinary??!1,error:r.error??null}}catch{return null}}function $o(e,t){let r=[];for(let n of e.split(/\r?\n/)){let o=Ho(n);o&&We(o.url,t.includeUrls,t.excludeUrls)&&r.push(Je(o,t.redactHeaders,t.redactBodyFields));}return r}function Bo(e,t){try{return $o(readFileSync(e,"utf-8"),t)}catch{return []}}function jo(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>t.endsWith(".jsonl")).map(t=>join(e,t))}catch{return []}}function ar(e){if(!e||e.length===0)return null;let t={};for(let r of e)typeof r.name=="string"&&typeof r.value=="string"&&(t[r.name]=r.value);return Object.keys(t).length>0?t:null}function zo(e){return e?typeof e.text=="string"?e.text:Array.isArray(e.params)?e.params.map(t=>`${encodeURIComponent(t.name)}=${encodeURIComponent(t.value??"")}`).join("&"):null:null}function qo(e){return e?/^(image|audio|video|application\/(octet-stream|pdf|zip|protobuf))/.test(e):false}function Go(e,t){let r=e.request,n=e.response;if(!r?.method||!r.url)return null;let o=n?.content,s=qo(o?.mimeType);return {id:`har-call-${t}`,timestamp:e.startedDateTime??new Date().toISOString(),method:r.method,url:r.url,requestHeaders:ar(r.headers),requestBody:zo(r.postData),responseStatusCode:typeof n?.status=="number"&&n.status>0?n.status:null,responseStatusText:n?.statusText??null,responseHeaders:ar(n?.headers),responseBody:o?.text??null,responseTimeMs:typeof e.time=="number"?e.time:0,isBinary:s,error:null}}function Vo(e,t){let r;try{r=JSON.parse(e);}catch{return []}let n=r.log?.entries??[],o=[];return n.forEach((s,i)=>{let a=Go(s,i);a&&We(a.url,t.includeUrls,t.excludeUrls)&&o.push(Je(a,t.redactHeaders,t.redactBodyFields));}),o}function Jo(e,t){try{return Vo(readFileSync(e,"utf-8"),t)}catch{return []}}function Wo(e,t){let r=new Map;for(let o of t)r.set(o.testId,[]);if(e.length===0||t.length===0)return r;let n=t.map(o=>({testId:o.testId,startMs:Date.parse(o.startedAt),endMs:Date.parse(o.completedAt)}));for(let o of e){let s=Date.parse(o.timestamp);if(!Number.isFinite(s))continue;let i=n.find(l=>Number.isFinite(l.startMs)&&Number.isFinite(l.endMs)&&s>=l.startMs&&s<=l.endMs);if(i){r.get(i.testId).push(o);continue}let a=null;for(let l of n){if(!Number.isFinite(l.startMs)||!Number.isFinite(l.endMs))continue;let c=s<l.startMs?l.startMs-s:s-l.endMs;(!a||c<a.dist)&&(a={testId:l.testId,dist:c});}a&&r.get(a.testId).push(o);}return r}function dr(e,t,r){if(!t.enabled&&!t.harPath)return new Map;let n=[];if(e)for(let o of jo(e))n.push(...Bo(o,t));return t.harPath&&existsSync(t.harPath)&&n.push(...Jo(t.harPath,t)),n.length===0?new Map:Wo(n,r)}function ur(e){return e.map((t,r)=>({...t,id:`api-call-${r}`}))}var Xo=new Set(["localhost","127.0.0.1","0.0.0.0"]);function Ke(e){let t=new URL(e);if(t.protocol!=="https:"&&!(t.protocol==="http:"&&Xo.has(t.hostname)))throw createError(ErrorCode.CLOUD_CONFIG_INVALID,`HTTPS is required for cloud communication. Got: ${t.protocol}//${t.hostname}`)}var Qo=3e3;async function ee(e){let t=new AbortController,r=setTimeout(()=>t.abort(),Qo);try{return (await fetch(`${e}/health`,{method:"GET",signal:t.signal})).ok}catch{return false}finally{clearTimeout(r);}}async function fr(e){return new Promise(t=>setTimeout(t,e))}async function pr(e){try{let r=(await e.json()).error;if(r&&typeof r.message=="string")return r.message}catch{}return `HTTP ${e.status}`}async function te(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),r);try{let s=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(s.ok){let a=await s.json();return {accessToken:a.accessToken,refreshToken:a.refreshToken,expiresIn:a.expiresIn,orgId:a.orgId,orgName:a.orgName,userId:a.userId,userName:a.userName}}if(s.status===429){let a=s.headers.get("Retry-After"),l=a?parseInt(a,10)*1e3:5e3;if(!isNaN(l)&&l>0){await fr(l);let c=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(c.ok){let d=await c.json();return {accessToken:d.accessToken,refreshToken:d.refreshToken,expiresIn:d.expiresIn,orgId:d.orgId,orgName:d.orgName,userId:d.userId,userName:d.userName}}}return {code:"rate_limited",message:"Rate limited during token exchange.",statusCode:429}}return s.status===400?{code:"validation_error",message:await pr(s),statusCode:400}:s.status===401?{code:"invalid_key",message:"API key is invalid or has been revoked.",statusCode:401}:s.status===403?{code:"expired_key",message:"API key has expired.",statusCode:403}:{code:"server_error",message:await pr(s),statusCode:s.status}}catch(s){return s instanceof DOMException&&s.name==="AbortError"?{code:"timeout",message:"Token exchange timed out.",statusCode:null}:{code:"network_error",message:"Failed to reach cloud for token exchange.",statusCode:null}}finally{clearTimeout(o);}}function re(e){return "code"in e&&typeof e.code=="string"&&["invalid_key","expired_key","validation_error","rate_limited","server_error","network_error","timeout"].includes(e.code)}async function Ye(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),r);try{let s=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal});if(s.status===429){let a=s.headers.get("Retry-After"),l=a?parseInt(a,10)*1e3:5e3;!isNaN(l)&&l>0&&(await fr(l),s=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal}));}if(!s.ok)return null;let i=await s.json();return {accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn}}catch{return null}finally{clearTimeout(o);}}async function Xe(e,t,r,n,o,s){let i=new AbortController,a=setTimeout(()=>i.abort(),o);try{let l={gitId:r,displayName:n};s&&(l.branch=s);let c=await fetch(`${e}/repos/resolve`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(l),signal:i.signal});if(!c.ok)return null;let d=await c.json();return {repoId:d.repoId,displayName:d.displayName}}catch{return null}finally{clearTimeout(a);}}var ns=5e3;function H(e,t){try{return execSync(e,{cwd:t,timeout:ns,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}function Qe(e){let t=H("git rev-parse --abbrev-ref HEAD",e),r=H("git rev-parse --short HEAD",e),n=H("git log -1 --pretty=%s",e),o=H("git log -1 --format=%an",e)??H("git config user.name",e),s=os(e),i=s?j(s):null;return {branch:t,commitSha:r,commitMessage:n,commitAuthor:o,remoteUrl:i}}function os(e){let t=H("git remote get-url origin",e);if(t)return t;let r=H("git remote",e);if(!r)return null;let n=r.split(`
|
|
1255
1255
|
`)[0]?.trim();return n?H(`git remote get-url ${n}`,e):null}function j(e){let t=e.trim();return t=t.replace(/^[a-z+]+:\/\//,""),t=t.replace(/^[^@]+@/,""),t=t.replace(/:(?!\d)/,"/"),t=t.replace(/\.git$/,""),t=t.replace(/\/+$/,""),t=t.replace(/^[^@/]+@/,""),t.toLowerCase()}function Ze(e){let t=e.split("/").filter(Boolean);return t[t.length-1]??e}function gr(e){try{let t=readFileSync(join(e,"package.json"),"utf-8"),r=JSON.parse(t);return typeof r.name=="string"&&r.name.length>0?r.name:null}catch{return null}}function z(e){let t=gr(e);return t||`local/${basename(e)}`}var ds="1.0.0",mr=10;function oe(e,t,r,n,o,s,i,a){try{mkdirSync(e,{recursive:!0});let l=Date.now(),c=`${l}-${t}-${r}.json`,d=join(e,c),u={version:ds,queuedAt:new Date(l).toISOString(),reason:n,retryCount:0,targetEndpoint:o,method:s,payload:i,headers:a},p=d+".tmp";writeFileSync(p,JSON.stringify(u,null,2),"utf-8"),renameSync(p,d);}catch(l){l.code==="ENOSPC"?process.stderr.write(`\u26A0 TestRelic: Disk full \u2014 unable to queue upload data.
|
|
1256
1256
|
`):process.stderr.write(`\u26A0 TestRelic: Unable to queue upload data.
|
|
1257
1257
|
`);}}async function tt(e,t,r){let n;try{n=readdirSync(e).filter(s=>s.endsWith(".json")&&!s.endsWith(".tmp")).sort();}catch{return}if(n.length===0)return;let o=[];for(let s=0;s<n.length;s+=mr)o.push(n.slice(s,s+mr));for(let s of o)for(let i of s){let a=join(e,i);try{if(!statSync(a).isFile())continue;let c=readFileSync(a,"utf-8"),d=JSON.parse(c);if(!isValidQueueEntry(d)){unlinkSync(a);continue}let u=d;if((await fetch(u.targetEndpoint,{method:u.method,headers:{...u.headers,Authorization:`Bearer ${r}`},body:JSON.stringify(u.payload)})).ok)unlinkSync(a);else return}catch{return}}}function rt(e,t){try{let r=readdirSync(e).filter(o=>o.endsWith(".json")&&!o.endsWith(".tmp")),n=Date.now();for(let o of r){let s=join(e,o);try{let i=readFileSync(s,"utf-8"),l=JSON.parse(i).queuedAt;if(typeof l=="string"){let c=new Date(l).getTime();n-c>t&&unlinkSync(s);}}catch{try{unlinkSync(s);}catch{}}}}catch{}}var ys=3e5,bs=864e5,xs=6e4,br=3e4,xr="https://platform.testrelic.ai/settings/api-keys",J=class{constructor(t){this.gitMetadata=null;this.repoId=null;this.failureReason=null;this.flushPromise=null;this.healthCheckTimer=null;this.config=t,this.authState={mode:"pending",accessToken:null,refreshToken:null,expiresAt:null,orgId:null,orgName:null,userId:null,userName:null};}async initialize(){if(!this.config||!this.config.apiKey){this.setLocalMode("no_api_key"),process.stderr.write(`\u2139 TestRelic: No API key configured. Running in local mode.
|