@checksum-ai/runtime 1.4.10-alpha → 1.4.11-alpha
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/.env +1 -1
- package/cli.js +1 -1
- package/package.json +1 -1
- package/test-run-monitor.js +2 -1
package/.env
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
CHECKSUM_RUNTIME_BUILD_TIME=2025-11-
|
|
1
|
+
CHECKSUM_RUNTIME_BUILD_TIME=2025-11-23T08:46:34.225Z
|
package/cli.js
CHANGED
|
@@ -1696,7 +1696,7 @@ ${a.map(s=>[s.type,s.nestedLevel,this.getText(s.body)]).join(`,
|
|
|
1696
1696
|
${Kun}
|
|
1697
1697
|
${g}
|
|
1698
1698
|
${Yun}
|
|
1699
|
-
${(await s.getFormattedTestFileCode()).code}`)}loadVtgTestFileMirror(r){if(!r||!r.startsWith("/"))throw new Error("Currently vtg mode can only run with absolute path to file");let a=new owe(r);return a.loadTestFromFile(),a}createActionJsonFileForExistingChecksumSpec(r,a){let s=r.testMirrors[0].translateStatementsToActions({mergeCustomCodeSteps:this.vtgSettingsService.getSettings().mergeCustomCodeSteps}),l=this.getActionJsonFilePath(a);(0,qz.writeFileSync)(l,JSON.stringify(s,null,2))}createFolderIfNotExists(r){return(0,qz.existsSync)(r)||(0,qz.mkdirSync)(r,{recursive:!0}),r}getSavePathForNewChecksumSpec(){return(0,hfe.join)(this.draftsFolderPath,"test.checksum.spec.ts")}getActionJsonFilePath(r){let a=this.getFileName(r).replace(".spec.ts",".json");return(0,hfe.join)(this.draftsFolderPath,a)}getEvalFilePath(r){let a=this.internalE2ETest?".eval.e2e.checksum.spec.ts":".eval.checksum.spec.ts";return(0,hfe.join)(this.draftsFolderPath,a)}getFileName(r){return r.split("/").pop()}};e(qDr,"VtgTestRunner");var hkt=qDr;var yLe=require("fs"),vLe=require("path");var gkt=require("fs"),OP=$d(mD());var ILi=/^[0-9a-zA-Z]+$/,FLi=5;function Xvn(i){return i?i.length===FLi&&ILi.test(i):!1}e(Xvn,"isValidChecksumTestId");var zDr=class zDr{extract(r,a){if(!r)return;let s=r.split("/"),l=s[s.length-1];if(!l.endsWith(".checksum.spec.ts"))return;let g=l.replace(".checksum.spec.ts","").split(" - ").pop();return Xvn(g)?g:void 0}};e(zDr,"FileNameExtractionStrategy");var $Dr=zDr,WDr=class WDr{extract(r,a){if(!(!r||!(0,gkt.existsSync)(r)))try{let s=(0,gkt.readFileSync)(r,"utf-8"),l=OP.createSourceFile(r,s,OP.ScriptTarget.Latest,!0),d=new Map,g=e(b=>{if(OP.isCallExpression(b)){let E=b;if(this.isTestCall(E.expression)){let S=E.arguments[0];if(S&&OP.isCallExpression(S)&&OP.isIdentifier(S.expression)&&S.expression.text==="defineChecksumTest"){let F=this.extractDefineChecksumTestArgs(S);F&&Xvn(F.checksumTestId)&&d.set(F.testTitle,F.checksumTestId)}}}OP.forEachChild(b,g)},"visit");return g(l),a&&d.has(a)?d.get(a):d.size>0?Array.from(d.values())[0]:void 0}catch{return}}isTestCall(r){return OP.isIdentifier(r)&&r.text==="test"?!0:OP.isPropertyAccessExpression(r)?OP.isIdentifier(r.expression)&&r.expression.text==="test":!1}extractDefineChecksumTestArgs(r){let a=r.arguments;if(a.length<2)return;let s=a[0],l=a[1],d=this.extractStringLiteral(s),g=this.extractStringLiteral(l);if(d&&g)return{testTitle:d,checksumTestId:g}}extractStringLiteral(r){if(OP.isStringLiteral(r)||OP.isNoSubstitutionTemplateLiteral(r))return r.text}};e(WDr,"FileContentExtractionStrategy");var VDr=WDr,HDr=class HDr{constructor(r){this.strategies=r||[new VDr,new $Dr]}extract(r,a){for(let s of this.strategies){let l=s.extract(r,a);if(l)return l}}};e(HDr,"ChecksumTestIdExtractor");var JDr=HDr;var Zvn=new JDr;var GDr=e(i=>isNaN(i)?0:i,"getStat"),PLi=e((i,r,a)=>{if(!i)return;let s=a||r,l;if((0,vLe.isAbsolute)(i))l=i;else{let g=(0,vLe.dirname)(r);l=(0,vLe.resolve)(g,i)}return l.replace(s+"/","")},"toRelativeFilePath"),exn=e(i=>{let r=[];if(i.specs&&r.push(...i.specs),i.suites)for(let a of i.suites)r.push(...exn(a));return r},"extractSpecsFromSuite"),NLi=e(i=>{let r=[];for(let a of i.suites)r.push(...exn(a));return r},"extractFlatSpecsMap"),OLi=e((i,r,a,s,l)=>{let{expected:d,unexpected:g,flaky:b}=i.stats,E=[];NLi(i).forEach(O=>{let N=BLi(O.id,r);N&&(O.recovered=!0);let q=O.tests[0],Q=O.tags.includes("bug")||q.annotations.some(fe=>fe.type==="bug"),z=q.annotations&&q.annotations.length>0?q.annotations.map(fe=>({type:fe.type,description:fe.description||""})):[],se=O.tags||[],ue=a[O.id]||Zvn.extract(O.file,O.title);E.push({checksumTestId:ue,playwrightTestId:O.id,success:!!O.ok,recovered:N,bug:Q,annotations:z,tags:se,outcome:q.status,filePath:O.file,relativeFilePath:s?PLi(O.file,s,l):O.file})});let F={passed:GDr(b)+GDr(d),failed:GDr(g),bug:E.filter(O=>O.bug).length,recovered:E.filter(O=>O.recovered).length,tests:E};return E.forEach(O=>{O.bug&&(O.outcome==="expected"||O.outcome==="flaky"?F.passed--:O.outcome==="unexpected"&&F.failed--)}),F},"modifyStatsPerTestFile"),BLi=e((i,r)=>Object.values(r[i]||{}).some(a=>{var s,l;return(l=(s=a.autoRecoveryMetadata)==null?void 0:s.data)==null?void 0:l.autoRecovered}),"isAutoRecovered"),txn=e((i,r,a,s,l)=>{(0,yLe.cpSync)(i,i+".backup");try{let d=JSON.parse((0,yLe.readFileSync)(i,"utf-8")),g=OLi(d,r,a,s,l);return d.checksumMetadata=g,(0,yLe.writeFileSync)(i,JSON.stringify(d,null,2)),d}catch(d){return console.log("Error processing JSON report",d.message),null}},"processJSONReport");var YDr=class YDr extends IP{constructor(a,s=!1,l=!1){super(a,s);this.vtgMode=l;this.MAX_COMPLETION_WAIT=2*3600*1e3;this.didFail=!1;this.isolationMode=!1;this.trmMessagesBuffer="";this.completeIndicators={upload:!1,tests:!1,report:!1};this.uploadProgress=0;this.playwrightIdToReportMetadata={};this.pwTestIdToChecksumTestId={};this.logFilter={"upload-progress":{logEveryMS:1e3*30,lastLogTimestamp:0,logOnValueChange:!0,value:""}}}get replMode(){return this.getChecksumArg("repl")??!1}async run(){if(this.loadTracer(),this.validateAuthExists(),this.buildVolatileChecksumConfig(),this.vtgMode&&(this.config.options.hostReports=!1),!await this.getSession())return;this.testSuiteAnalytics=Hwt.getInstance(this.testSuiteRunInfo,this.isolationMode),this.testSuiteAnalytics.genericEvent(`Project root found at ${this.projectRootDirectory}`,{message:`Checksum root found at ${this.checksumRoot}`});let a={CHECKSUM_ROOT_FOLDER:this.checksumRoot,CHECKSUM_TEST_SUITE_INFO:JSON.stringify(this.testSuiteRunInfo)},s;try{s=await E8(this.startTestRunMonitor(this.testSuiteRunId),1e4,"test run monitor timeout"),a.CHECKSUM_UPLOAD_AGENT_PORT=s}catch{let b="Error starting test run monitor. Test results will not be available on checksum.";this.testSuiteAnalytics.testRunMonitorError({error:b}),this.log(b)}a.PW_TEST_HTML_REPORT_OPEN="never",this.isolationMode&&(a.CHECKSUM_ISOLATED_MODE="true"),this.testSuiteRunId&&(a.CHECKSUM_TEST_SUITE_ID=this.testSuiteRunId),this.replMode&&(a.CHECKSUM_REPL="true"),this.getChecksumArg("tm")&&(a.CHECKSUM_SHOW_TIME_MACHINE="true");let l=this.getNonChecksumArgs();this.vtgMode&&(await new hkt(this.getChecksumArg("id")||void 0,this.getChecksumArg("edit")||void 0,this.getChecksumArg("legacy")||!1,eg.vtg.isE2ETestMode,this.getChecksumArg("restore")||!1,this.checksumRoot,this.getInternalFilesDirPath()).initAndUpdateEnvAndPlaywrightArgs(a,l),eg.promptKillActivePlaywrightProcesses&&await this.promptKillActivePlaywrightProcesses()),this.replMode&&l.push("--debug");let d=`npx playwright test --config "${this.getPlaywrightConfigFilePath()}" ${l.map(g=>`"${g}"`).join(" ")}`;await this.patchPlaywright();try{console.log(`Tests running with @checksum-ai/runtime version ${this.checksumRuntimeVersion}`),this.replMode?(console.log("Running in REPL mode"),this.execCmd(d,a),await this.execCmd(`node ${__dirname}/repl.js`,a)):(this.testSuiteAnalytics.testSuiteStart(),await this.execCmd(d,a)),console.log(`Tests execution finished. Checksum is finalizing${this.isolationMode?"":" and uploading"} the report, please wait...`)}catch{this.didFail=!0,console.log("Error during test execution: Failed passing test"),this.testSuiteAnalytics.testsFailed()}finally{this.isolationMode||console.log("Waiting for test files to upload to Checksum..."),this.sendReportUploadRequest(),await this.patchPlaywright(!0),this.completeIndicators.tests=!0,await this.handleCompleteMessage()}}loadPlaywrightConfigOptions(){var S,F;let a=e(O=>(B7("Using report folder",O),(0,NK.join)(O,"index.html")),"makeFilePath"),s=e(O=>(B7("Using JSON report folder",O),(0,NK.join)(O,"report.json")),"makeJsonFilePath"),l,d,g=!1,b="never";process.env.PLAYWRIGHT_HTML_OUTPUT_DIR&&(l=a(process.env.PLAYWRIGHT_HTML_OUTPUT_DIR));let E=(S=this.playwrightConfig)==null?void 0:S.reporter;if(E instanceof Array){let O=E.filter(Q=>Q instanceof Array&&Q[0]==="html"),N=E.filter(Q=>Q instanceof Array&&Q[0]==="json");if(!process.env.PLAYWRIGHT_HTML_OUTPUT_DIR){let Q=O.find(z=>{var se;return(se=z[1])==null?void 0:se.outputFolder});Q&&(l=a((0,NK.join)(this.checksumRoot,Q[1].outputFolder)))}let q=N.find(Q=>{var z;return(z=Q[1])==null?void 0:z.outputFile});q&&(g=!0,d=(0,NK.join)(this.checksumRoot,q[1].outputFile));for(let Q of O){let z=(F=Q[1])==null?void 0:F.open;if(z==="always"||z==="on-failure"){b=z;break}}}l||(eg.isRepoMode?l=a((0,NK.join)(eg.runtimeRoot,"playwright-report")):l=a((0,NK.join)(this.projectRootDirectory,"playwright-report"))),d||(eg.isRepoMode?d=s((0,NK.join)(eg.runtimeRoot,"playwright-report")):d=s((0,NK.join)(this.projectRootDirectory,"playwright-report"))),this.playwrightConfigOptions={openReportCriteria:b,reportPath:l,jsonReportPath:d,hasJsonReporter:g}}sendReportUploadRequest(){let a=e(F=>{this.testSuiteAnalytics.testSuiteError({error:F}),this.log(F),this.completeIndicators.report=!0,this.testRunMonitorProcess.stdin.write("cli:report=false")},"makeError");if(!this.playwrightConfigOptions)return a("No playwright config options");let{reportPath:s,openReportCriteria:l,jsonReportPath:d,hasJsonReporter:g}=this.playwrightConfigOptions;if(g&&((0,Yrt.existsSync)(d)?txn(d,this.playwrightIdToReportMetadata,this.pwTestIdToChecksumTestId,this.checksumRoot,this.projectRootDirectory):console.warn(`Could not find JSON report file at ${d}`)),!(0,Yrt.existsSync)(s))return a(`Could not find report file at ${s}`);B7("Sending report upload request",s);let b=this.saveMetadataToFile((0,NK.dirname)(s)),E={reportPath:s,pathToChecksumMetadata:b,openReportCriteria:l,didFail:this.didFail,checksumRoot:this.checksumRoot,projectRoot:this.projectRootDirectory},S=Buffer.from(JSON.stringify(E)).toString("base64");this.testRunMonitorProcess.stdin.write(`cli:report=${S}`)}saveMetadataToFile(a){try{let s=(0,NK.join)(a,`checksum-metadata-${(0,KDr.randomUUID)()}.json`);return(0,Yrt.writeFileSync)(s,JSON.stringify(this.playwrightIdToReportMetadata,null,2)),s}catch(s){let l=`Error saving metadata to file - ${s.message}`;this.testSuiteAnalytics.testSuiteError({error:l}),this.log(l);return}}startTestMonitorProcess(a){let l=[JSON.stringify({sessionId:a,apiURL:this.config.apiURL,apiKey:this.config.apiKey}),...this.isolationMode?["isolated"]:[]],d={command:"node",args:[(0,NK.join)(__dirname,"test-run-monitor.js"),...l]};return eg.isRepoMode&&(d.command="yarn",d.args=["test-run-monitor",...l]),rxn.spawn(d.command,d.args)}startTestRunMonitor(a){return new Promise(s=>{console.log("Starting test run monitor"),this.testRunMonitorProcess=this.startTestMonitorProcess(a),this.testRunMonitorProcess.stdout.on("data",l=>{let d=this.parseTRMMessages(l.toString().trim());if(d.length)for(let g of d){if(g.startsWith("trace")){this.logTRMMessage(g),this.handleTestRunMonitorTrace(g.substring("trace".length+1));continue}if(!g.startsWith("monitor")){this.logTRMMessage(g);continue}let b=e(()=>{let O=g.substring("monitor".length+1),N=O.indexOf("=");if(N===-1)return{key:O,value:""};let[q,Q]=[O.substring(0,N),O.substring(N+1)];return{key:q,value:Q}},"getKeyAndValue"),{key:E,value:S}=b();if(!Object.values(Ror).includes(E)){this.logTRMMessage(`Received unknown monitor message: "${g}"`);continue}let F=E;this.logInterProcessEventMessage(F,S),E==="port"?s(S):this.handleTestRunMonitorMessage(F,S)}}),this.testRunMonitorProcess.on("exit",(l,d)=>{let g=`test run monitor process exited with code ${l} and signal ${d}`;this.testSuiteAnalytics.testRunMonitorError({error:g}),this.log(g)}),this.testRunMonitorProcess.stderr.on("data",l=>{let d=`TRM Error: ${l.toString().substring(0,300)}`;this.testSuiteAnalytics.testRunMonitorError({error:d}),this.log(d)}),this.testRunMonitorProcess.on("error",l=>{let d=`Error starting test run monitor: ${l.message}`;this.testSuiteAnalytics.testRunMonitorError({error:d}),this.log(d)})})}logInterProcessEventMessage(a,s){e(()=>{if(!this.logFilter[a])return!0;if(this.logFilter[a].logOnValueChange&&this.logFilter[a].value!==s)return this.logFilter[a].value=s,!0;if(this.logFilter[a].logEveryMS){let d=Date.now();if(d-this.logFilter[a].lastLogTimestamp>=this.logFilter[a].logEveryMS)return this.logFilter[a].lastLogTimestamp=d,!0}return!1},"shouldLog")()&&this.logTRMMessage(`Received monitor message: "${a}${s?`=${s}`:""}"`)}parseTRMMessages(a){let s=this.trmMessagesBuffer+a,l,d,g=e(()=>{l=s.indexOf("{trm}"),d=s.indexOf("{/trm}")},"findIndexes");g();let b=[];for(;l!==-1&&d!==-1&&d>l;){if(b.push(s.substring(l+"{trm}".length,d)),s=s.slice(d+"{/trm}".length).trim(),s.length&&!s.startsWith("{trm}"))return console.warn("Buffered data does not start with start delimiter",s),this.trmMessagesBuffer="",b;this.trmMessagesBuffer=s,g()}return b}setChecksumTestMetadata(a){let{retry:s,type:l,pwTestId:d,checksumTestId:g}=a;this.playwrightIdToReportMetadata[d]||(this.playwrightIdToReportMetadata[d]={}),this.playwrightIdToReportMetadata[d][s]||(this.playwrightIdToReportMetadata[d][s]={}),this.playwrightIdToReportMetadata[d][s][l]=a,this.pwTestIdToChecksumTestId[d]=g}async handleTestRunMonitorTrace(a){let s=a.indexOf("="),[l,d]=s>-1?[a.substring(0,s),a.substring(s+1)]:[a,""];if(!Object.values(Wwt).includes(l)){B7("Unknown trace event",l);return}try{let g=d?JSON.parse(d):{};switch(l){case"Upload Start":this.testSuiteAnalytics.uploadStart({filename:g.filename});break;case"Upload Complete":this.testSuiteAnalytics.uploadComplete({filename:g.filename});break;case"Upload Failed":this.testSuiteAnalytics.uploadFailed({filename:g.filename,error:g.error});break;case"Trace Processing Error":this.testSuiteAnalytics.traceProcessingError({error:g.error});break}}catch(g){B7(`Error parsing trace payload, ${g.message}`)}}async handleTestRunMonitorMessage(a,s){var l;switch(a){case"uploads-complete-with-errors":console.log("Error uploading test files to Checksum");try{let g=JSON.parse(s);this.testSuiteAnalytics.uploadsCompleteWithErrors(g)}catch{}this.sendProcessingError().then(()=>{this.completeIndicators.upload=!0});break;case"checksumTestMetadata":try{let g=JSON.parse(s);this.setChecksumTestMetadata(g)}catch(g){let b=`Error parsing test metadata event - ${g.message}`;this.testSuiteAnalytics.testSuiteError({error:b}),this.log(b)}break;case"uploads-complete":this.isolationMode||console.log("Test files uploaded successfully"),this.testSuiteAnalytics.allUploadsComplete(),this.sendUploadsComplete().then(()=>{this.completeIndicators.upload=!0});break;case"report-complete":{if(this.isolationMode){this.completeIndicators.report=!0;break}B7("Report processing and upload completed, updating cloud with test stats...");try{let g=s.slice(0,s.indexOf(":"))==="true",b=s.slice(s.indexOf(":")+1),E=this.handleStats(b);if(this.testSuiteAnalytics.testSuiteEnd({passed:E.passed,failed:E.failed,bug:E.bug,total:((l=E.tests)==null?void 0:l.length)||0}),await this.sendTestRunEnd(E),this.completeIndicators.report=!0,g){let S=`${this.checksumAppUrl}/#/test-runs/${this.testSuiteRunId}`,F=`Checksum report URL: ${S}`,O="*".repeat(F.length);console.log(`${O}
|
|
1699
|
+
${(await s.getFormattedTestFileCode()).code}`)}loadVtgTestFileMirror(r){if(!r||!r.startsWith("/"))throw new Error("Currently vtg mode can only run with absolute path to file");let a=new owe(r);return a.loadTestFromFile(),a}createActionJsonFileForExistingChecksumSpec(r,a){let s=r.testMirrors[0].translateStatementsToActions({mergeCustomCodeSteps:this.vtgSettingsService.getSettings().mergeCustomCodeSteps}),l=this.getActionJsonFilePath(a);(0,qz.writeFileSync)(l,JSON.stringify(s,null,2))}createFolderIfNotExists(r){return(0,qz.existsSync)(r)||(0,qz.mkdirSync)(r,{recursive:!0}),r}getSavePathForNewChecksumSpec(){return(0,hfe.join)(this.draftsFolderPath,"test.checksum.spec.ts")}getActionJsonFilePath(r){let a=this.getFileName(r).replace(".spec.ts",".json");return(0,hfe.join)(this.draftsFolderPath,a)}getEvalFilePath(r){let a=this.internalE2ETest?".eval.e2e.checksum.spec.ts":".eval.checksum.spec.ts";return(0,hfe.join)(this.draftsFolderPath,a)}getFileName(r){return r.split("/").pop()}};e(qDr,"VtgTestRunner");var hkt=qDr;var yLe=require("fs"),vLe=require("path");var gkt=require("fs"),OP=$d(mD());var ILi=/^[0-9a-zA-Z]+$/,FLi=5;function Xvn(i){return i?i.length===FLi&&ILi.test(i):!1}e(Xvn,"isValidChecksumTestId");var zDr=class zDr{extract(r,a){if(!r)return;let s=r.split("/"),l=s[s.length-1];if(!l.endsWith(".checksum.spec.ts"))return;let g=l.replace(".checksum.spec.ts","").split(" - ").pop();return Xvn(g)?g:void 0}};e(zDr,"FileNameExtractionStrategy");var $Dr=zDr,WDr=class WDr{extract(r,a){if(!(!r||!(0,gkt.existsSync)(r)))try{let s=(0,gkt.readFileSync)(r,"utf-8"),l=OP.createSourceFile(r,s,OP.ScriptTarget.Latest,!0),d=new Map,g=e(b=>{if(OP.isCallExpression(b)){let E=b;if(this.isTestCall(E.expression)){let S=E.arguments[0];if(S&&OP.isCallExpression(S)&&OP.isIdentifier(S.expression)&&S.expression.text==="defineChecksumTest"){let F=this.extractDefineChecksumTestArgs(S);F&&Xvn(F.checksumTestId)&&d.set(F.testTitle,F.checksumTestId)}}}OP.forEachChild(b,g)},"visit");return g(l),a&&d.has(a)?d.get(a):d.size>0?Array.from(d.values())[0]:void 0}catch{return}}isTestCall(r){return OP.isIdentifier(r)&&r.text==="test"?!0:OP.isPropertyAccessExpression(r)?OP.isIdentifier(r.expression)&&r.expression.text==="test":!1}extractDefineChecksumTestArgs(r){let a=r.arguments;if(a.length<2)return;let s=a[0],l=a[1],d=this.extractStringLiteral(s),g=this.extractStringLiteral(l);if(d&&g)return{testTitle:d,checksumTestId:g}}extractStringLiteral(r){if(OP.isStringLiteral(r)||OP.isNoSubstitutionTemplateLiteral(r))return r.text}};e(WDr,"FileContentExtractionStrategy");var VDr=WDr,HDr=class HDr{constructor(r){this.strategies=r||[new VDr,new $Dr]}extract(r,a){for(let s of this.strategies){let l=s.extract(r,a);if(l)return l}}};e(HDr,"ChecksumTestIdExtractor");var JDr=HDr;var Zvn=new JDr;var GDr=e(i=>isNaN(i)?0:i,"getStat"),PLi=e((i,r,a)=>{if(!i)return;let s=a||r,l;if((0,vLe.isAbsolute)(i))l=i;else{let g=(0,vLe.dirname)(r);l=(0,vLe.resolve)(g,i)}return l.replace(s+"/","")},"toRelativeFilePath"),exn=e(i=>{let r=[];if(i.specs&&r.push(...i.specs),i.suites)for(let a of i.suites)r.push(...exn(a));return r},"extractSpecsFromSuite"),NLi=e(i=>{let r=[];for(let a of i.suites)r.push(...exn(a));return r},"extractFlatSpecsMap"),OLi=e((i,r,a,s,l)=>{let{expected:d,unexpected:g,flaky:b}=i.stats,E=[];NLi(i).forEach(O=>{let N=BLi(O.id,r);N&&(O.recovered=!0);let q=O.tests[0],Q=O.tags.includes("bug")||q.annotations.some(fe=>fe.type==="bug"),z=q.annotations&&q.annotations.length>0?q.annotations.map(fe=>({type:fe.type,description:fe.description||""})):[],se=O.tags||[],ue=a[O.id]||Zvn.extract(O.file,O.title);E.push({checksumTestId:ue,playwrightTestId:O.id,success:!!O.ok,recovered:N,bug:Q,annotations:z,tags:se,outcome:q.status,filePath:O.file,relativeFilePath:s?PLi(O.file,s,l):O.file})});let F={passed:GDr(b)+GDr(d),failed:GDr(g),bug:E.filter(O=>O.bug).length,recovered:E.filter(O=>O.recovered).length,tests:E};return E.forEach(O=>{O.bug&&(O.outcome==="expected"||O.outcome==="flaky"?F.passed--:O.outcome==="unexpected"&&F.failed--)}),F},"modifyStatsPerTestFile"),BLi=e((i,r)=>Object.values(r[i]||{}).some(a=>{var s,l;return(l=(s=a.autoRecoveryMetadata)==null?void 0:s.data)==null?void 0:l.autoRecovered}),"isAutoRecovered"),txn=e((i,r,a,s,l)=>{(0,yLe.cpSync)(i,i+".backup");try{let d=JSON.parse((0,yLe.readFileSync)(i,"utf-8")),g=OLi(d,r,a,s,l);return d.checksumMetadata=g,(0,yLe.writeFileSync)(i,JSON.stringify(d,null,2)),d}catch(d){return console.log("Error processing JSON report",d.message),null}},"processJSONReport");var YDr=class YDr extends IP{constructor(a,s=!1,l=!1){super(a,s);this.vtgMode=l;this.MAX_COMPLETION_WAIT=2*3600*1e3;this.didFail=!1;this.isolationMode=!1;this.trmMessagesBuffer="";this.completeIndicators={upload:!1,tests:!1,report:!1};this.uploadProgress=0;this.playwrightIdToReportMetadata={};this.pwTestIdToChecksumTestId={};this.logFilter={"upload-progress":{logEveryMS:1e3*30,lastLogTimestamp:0,logOnValueChange:!0,value:""}}}get replMode(){return this.getChecksumArg("repl")??!1}async run(){if(this.loadTracer(),this.validateAuthExists(),this.buildVolatileChecksumConfig(),this.vtgMode&&(this.config.options.hostReports=!1),!await this.getSession())return;this.testSuiteAnalytics=Hwt.getInstance(this.testSuiteRunInfo,this.isolationMode),this.testSuiteAnalytics.genericEvent(`Project root found at ${this.projectRootDirectory}`,{message:`Checksum root found at ${this.checksumRoot}`});let a={CHECKSUM_ROOT_FOLDER:this.checksumRoot,CHECKSUM_TEST_SUITE_INFO:JSON.stringify(this.testSuiteRunInfo)},s;try{s=await E8(this.startTestRunMonitor(this.testSuiteRunId),1e4,"test run monitor timeout"),a.CHECKSUM_UPLOAD_AGENT_PORT=s}catch{let b="Error starting test run monitor. Test results will not be available on checksum.";this.testSuiteAnalytics.testRunMonitorError({error:b}),this.log(b)}a.PW_TEST_HTML_REPORT_OPEN="never",this.isolationMode&&(a.CHECKSUM_ISOLATED_MODE="true"),this.testSuiteRunId&&(a.CHECKSUM_TEST_SUITE_ID=this.testSuiteRunId),this.replMode&&(a.CHECKSUM_REPL="true"),this.getChecksumArg("tm")&&(a.CHECKSUM_SHOW_TIME_MACHINE="true");let l=this.getNonChecksumArgs();this.vtgMode&&(await new hkt(this.getChecksumArg("id")||void 0,this.getChecksumArg("edit")||void 0,this.getChecksumArg("legacy")||!1,eg.vtg.isE2ETestMode,this.getChecksumArg("restore")||!1,this.checksumRoot,this.getInternalFilesDirPath()).initAndUpdateEnvAndPlaywrightArgs(a,l),eg.promptKillActivePlaywrightProcesses&&await this.promptKillActivePlaywrightProcesses()),this.replMode&&l.push("--debug");let d=`npx playwright test --config "${this.getPlaywrightConfigFilePath()}" ${l.map(g=>`"${g}"`).join(" ")}`;await this.patchPlaywright();try{console.log(`Tests running with @checksum-ai/runtime version ${this.checksumRuntimeVersion}`),this.replMode?(console.log("Running in REPL mode"),this.execCmd(d,a),await this.execCmd(`node ${__dirname}/repl.js`,a)):(this.testSuiteAnalytics.testSuiteStart(),await this.execCmd(d,a)),console.log(`Tests execution finished. Checksum is finalizing${this.isolationMode?"":" and uploading"} the report, please wait...`)}catch{this.didFail=!0,console.log("Error during test execution: Failed passing test"),this.testSuiteAnalytics.testsFailed()}finally{this.isolationMode||console.log("Waiting for test files to upload to Checksum..."),this.sendReportUploadRequest(),await this.patchPlaywright(!0),this.completeIndicators.tests=!0,await this.handleCompleteMessage()}}loadPlaywrightConfigOptions(){var S,F;let a=e(O=>(B7("Using report folder",O),(0,NK.join)(O,"index.html")),"makeFilePath"),s=e(O=>(B7("Using JSON report folder",O),(0,NK.join)(O,"report.json")),"makeJsonFilePath"),l,d,g=!1,b="never";process.env.PLAYWRIGHT_HTML_OUTPUT_DIR&&(l=a(process.env.PLAYWRIGHT_HTML_OUTPUT_DIR));let E=(S=this.playwrightConfig)==null?void 0:S.reporter;if(E instanceof Array){let O=E.filter(Q=>Q instanceof Array&&Q[0]==="html"),N=E.filter(Q=>Q instanceof Array&&Q[0]==="json");if(!process.env.PLAYWRIGHT_HTML_OUTPUT_DIR){let Q=O.find(z=>{var se;return(se=z[1])==null?void 0:se.outputFolder});Q&&(l=a((0,NK.join)(this.checksumRoot,Q[1].outputFolder)))}let q=N.find(Q=>{var z;return(z=Q[1])==null?void 0:z.outputFile});q&&(g=!0,d=(0,NK.join)(this.checksumRoot,q[1].outputFile));for(let Q of O){let z=(F=Q[1])==null?void 0:F.open;if(z==="always"||z==="on-failure"){b=z;break}}}l||(eg.isRepoMode?l=a((0,NK.join)(eg.runtimeRoot,"playwright-report")):l=a((0,NK.join)(this.projectRootDirectory,"playwright-report"))),d||(eg.isRepoMode?d=s((0,NK.join)(eg.runtimeRoot,"playwright-report")):d=s((0,NK.join)(this.projectRootDirectory,"playwright-report"))),this.playwrightConfigOptions={openReportCriteria:b,reportPath:l,jsonReportPath:d,hasJsonReporter:g}}sendReportUploadRequest(){let a=e(F=>{this.testSuiteAnalytics.testSuiteError({error:F}),this.log(F),this.completeIndicators.report=!0,this.testRunMonitorProcess.stdin.write("cli:report=false")},"makeError");if(!this.playwrightConfigOptions)return a("No playwright config options");let{reportPath:s,openReportCriteria:l,jsonReportPath:d,hasJsonReporter:g}=this.playwrightConfigOptions;if(g&&((0,Yrt.existsSync)(d)?txn(d,this.playwrightIdToReportMetadata,this.pwTestIdToChecksumTestId,this.checksumRoot,this.projectRootDirectory):console.warn(`Could not find JSON report file at ${d}`)),!(0,Yrt.existsSync)(s))return a(`Could not find report file at ${s}`);B7("Sending report upload request",s);let b=this.saveMetadataToFile((0,NK.dirname)(s)),E={reportPath:s,pathToChecksumMetadata:b,openReportCriteria:l,didFail:this.didFail,checksumRoot:this.checksumRoot,projectRoot:this.projectRootDirectory},S=Buffer.from(JSON.stringify(E)).toString("base64");this.testRunMonitorProcess.stdin.write(`cli:report=${S}`)}saveMetadataToFile(a){try{let s=(0,NK.join)(a,`checksum-metadata-${(0,KDr.randomUUID)()}.json`);return(0,Yrt.writeFileSync)(s,JSON.stringify(this.playwrightIdToReportMetadata,null,2)),s}catch(s){let l=`Error saving metadata to file - ${s.message}`;this.testSuiteAnalytics.testSuiteError({error:l}),this.log(l);return}}startTestMonitorProcess(a){let l=[JSON.stringify({sessionId:a,apiURL:this.config.apiURL,apiKey:this.config.apiKey}),...this.isolationMode?["isolated"]:[]],d={command:"node",args:[(0,NK.join)(__dirname,"test-run-monitor.js"),...l]};return eg.isRepoMode&&(d.command="yarn",d.args=["test-run-monitor",...l]),rxn.spawn(d.command,d.args)}startTestRunMonitor(a){return new Promise(s=>{console.log("Starting test run monitor"),this.testRunMonitorProcess=this.startTestMonitorProcess(a),this.testRunMonitorProcess.stdout.on("data",l=>{try{console.log("[DATA]",l.toString().trim());let d=this.parseTRMMessages(l.toString().trim());if(!d.length){console.log("[DATA NO MESSAGES]");return}for(let g of d){if(console.log("[DATA MESSAGE]",g),g.startsWith("trace")){this.logTRMMessage(g),this.handleTestRunMonitorTrace(g.substring("trace".length+1));continue}if(!g.startsWith("monitor")){this.logTRMMessage(g);continue}console.log("[DATA MONITOR MESSAGE]",g);let b=e(()=>{let O=g.substring("monitor".length+1),N=O.indexOf("=");if(N===-1)return{key:O,value:""};let[q,Q]=[O.substring(0,N),O.substring(N+1)];return{key:q,value:Q}},"getKeyAndValue"),{key:E,value:S}=b();if(!Object.values(Ror).includes(E)){this.logTRMMessage(`Received unknown monitor message: "${g}"`);continue}let F=E;this.logInterProcessEventMessage(F,S),E==="port"?s(S):this.handleTestRunMonitorMessage(F,S)}}catch(d){console.error("[DATA ERROR]",d)}}),this.testRunMonitorProcess.on("exit",(l,d)=>{let g=`test run monitor process exited with code ${l} and signal ${d}`;this.testSuiteAnalytics.testRunMonitorError({error:g}),this.log(g)}),this.testRunMonitorProcess.stderr.on("data",l=>{let d=`TRM Error: ${l.toString().substring(0,300)}`;this.testSuiteAnalytics.testRunMonitorError({error:d}),this.log(d)}),this.testRunMonitorProcess.on("error",l=>{let d=`Error starting test run monitor: ${l.message}`;this.testSuiteAnalytics.testRunMonitorError({error:d}),this.log(d)})})}logInterProcessEventMessage(a,s){e(()=>{if(!this.logFilter[a])return!0;if(this.logFilter[a].logOnValueChange&&this.logFilter[a].value!==s)return this.logFilter[a].value=s,!0;if(this.logFilter[a].logEveryMS){let d=Date.now();if(d-this.logFilter[a].lastLogTimestamp>=this.logFilter[a].logEveryMS)return this.logFilter[a].lastLogTimestamp=d,!0}return!1},"shouldLog")()&&this.logTRMMessage(`Received monitor message: "${a}${s?`=${s}`:""}"`)}parseTRMMessages(a){let s=this.trmMessagesBuffer+a,l,d,g=e(()=>{l=s.indexOf("{trm}"),d=s.indexOf("{/trm}")},"findIndexes");g(),console.log("[parseTRMMessages] BUFFERED DATA:",s),console.log("[parseTRMMessages] START INDEX:",l),console.log("[parseTRMMessages] END INDEX:",d);let b=[];for(;l!==-1&&d!==-1&&d>l;){if(b.push(s.substring(l+"{trm}".length,d)),s=s.slice(d+"{/trm}".length).trim(),s.length&&!s.startsWith("{trm}"))return console.warn("Buffered data does not start with start delimiter",s),this.trmMessagesBuffer="",b;this.trmMessagesBuffer=s,g()}return console.log("[parseTRMMessages] MESSAGES:",b),b}setChecksumTestMetadata(a){let{retry:s,type:l,pwTestId:d,checksumTestId:g}=a;this.playwrightIdToReportMetadata[d]||(this.playwrightIdToReportMetadata[d]={}),this.playwrightIdToReportMetadata[d][s]||(this.playwrightIdToReportMetadata[d][s]={}),this.playwrightIdToReportMetadata[d][s][l]=a,this.pwTestIdToChecksumTestId[d]=g}async handleTestRunMonitorTrace(a){let s=a.indexOf("="),[l,d]=s>-1?[a.substring(0,s),a.substring(s+1)]:[a,""];if(!Object.values(Wwt).includes(l)){B7("Unknown trace event",l);return}try{let g=d?JSON.parse(d):{};switch(l){case"Upload Start":this.testSuiteAnalytics.uploadStart({filename:g.filename});break;case"Upload Complete":this.testSuiteAnalytics.uploadComplete({filename:g.filename});break;case"Upload Failed":this.testSuiteAnalytics.uploadFailed({filename:g.filename,error:g.error});break;case"Trace Processing Error":this.testSuiteAnalytics.traceProcessingError({error:g.error});break}}catch(g){B7(`Error parsing trace payload, ${g.message}`)}}async handleTestRunMonitorMessage(a,s){var l;switch(a){case"uploads-complete-with-errors":console.log("Error uploading test files to Checksum");try{let g=JSON.parse(s);this.testSuiteAnalytics.uploadsCompleteWithErrors(g)}catch{}this.sendProcessingError().then(()=>{this.completeIndicators.upload=!0});break;case"checksumTestMetadata":try{let g=JSON.parse(s);this.setChecksumTestMetadata(g)}catch(g){let b=`Error parsing test metadata event - ${g.message}`;this.testSuiteAnalytics.testSuiteError({error:b}),this.log(b)}break;case"uploads-complete":this.isolationMode||console.log("Test files uploaded successfully"),this.testSuiteAnalytics.allUploadsComplete(),this.sendUploadsComplete().then(()=>{this.completeIndicators.upload=!0});break;case"report-complete":{if(console.log("In InterProcessEvents.ReportComplete handler"),this.isolationMode){this.completeIndicators.report=!0;break}B7("Report processing and upload completed, updating cloud with test stats...");try{let g=s.slice(0,s.indexOf(":"))==="true",b=s.slice(s.indexOf(":")+1),E=this.handleStats(b);if(this.testSuiteAnalytics.testSuiteEnd({passed:E.passed,failed:E.failed,bug:E.bug,total:((l=E.tests)==null?void 0:l.length)||0}),await this.sendTestRunEnd(E),this.completeIndicators.report=!0,g){let S=`${this.checksumAppUrl}/#/test-runs/${this.testSuiteRunId}`,F=`Checksum report URL: ${S}`,O="*".repeat(F.length);console.log(`${O}
|
|
1700
1700
|
${F}
|
|
1701
1701
|
${O}`),this.testSuiteAnalytics.reportComplete({stats:E,reportUrl:S})}else this.testSuiteAnalytics.testSuiteError({error:"An error occurred while uploading the test report to Checksum"}),this.testSuiteAnalytics.reportUploadError(),console.log("An error occurred while uploading the test report to Checksum")}catch(g){throw B7(`Error sending test run end - ${g.message}`),g}break}case"upload-progress":{if(this.isolationMode)break;let g=parseInt(s);(g<this.uploadProgress||g>=this.uploadProgress+10||g===100&&this.uploadProgress!==100)&&(this.uploadProgress=g,console.log(`[ Uploads progress: ${this.uploadProgress}% ]`))}break;case"log":console.log(s);break;case"trace":let d=s;if(!Object.values(Wwt).includes(d))return;this.testSuiteAnalytics.genericEvent(d);break;case"playwrightConfig":try{this.playwrightConfig||(this.playwrightConfig=JSON.parse(s),this.testSuiteAnalytics.playwrightConfig({config:this.playwrightConfig}),this.loadPlaywrightConfigOptions())}catch(g){let b=`Error parsing playwright config - ${g.message}`;this.testSuiteAnalytics.playwrightConfigError({error:b}),this.log(b)}break;default:this.testSuiteAnalytics.testRunMonitorError({error:`Unhandled test run monitor message: ${a}=${s}`}),this.log(`Unhandled test run monitor message: ${a}=${s}`)}}handleStats(a){let s={};try{a&&a.length>0?(s=JSON.parse(a),s.tests=s.tests.map(l=>{let d=this.playwrightIdToReportMetadata[l.playwrightTestId];if(!d)return l;let g=Object.keys(d??{}),b=!1,E=!1,S=[];g.forEach(O=>{var N;if(d[O]){let q=d[O].autoRecoverySummaries;(N=q==null?void 0:q.data)!=null&&N.length&&S.push(...q.data)}});let F=g[g.length-1];if(F&&d[F]){let O=d[F].autoRecoveryMetadata;b=(O==null?void 0:O.data.autoRecoveryTriggered)??!1,E=(O==null?void 0:O.data.autoRecovered)??!1}return{...l,recovered:E,autoRecoveryTriggered:b,autoRecoverySummaries:S}})):(this.testSuiteAnalytics.testSuiteError({error:"No stats received from test run monitor"}),B7("No stats received from test run monitor"))}catch(l){this.testSuiteAnalytics.testSuiteError({error:`Error parsing stats - ${l.message}`}),this.log(`Error parsing stats - ${l.message}`)}return s}async handleCompleteMessage(){let a=Date.now(),s=12;for(;;){if(Date.now()-a>this.MAX_COMPLETION_WAIT){console.log("Warning: Checksum wasn't able to upload all test assets or expected a file the couldn't be found. This might cause issues when viewing the report/trace."),this.testSuiteAnalytics.runtimeTimeout(),this.shutdown(1);return}if(Object.keys(this.completeIndicators).find(l=>!this.completeIndicators[l]))B7(this.completeIndicators),--s===0&&(this.testSuiteAnalytics.completionStatus({stats:this.completeIndicators}),s=12),await IT(5e3);else{this.testSuiteAnalytics.runtimeComplete(),console.log("Checksum test suite run has completed"),await this.shutdown(this.didFail?1:0);return}}}async shutdown(a=0){await this.cleanup(),process.exit(a)}async cleanup(){await super.cleanup(),this.testRunMonitorProcess&&(this.testRunMonitorProcess.stdin.write("cli:shutdown"),this.testRunMonitorProcess.kill())}async getSession(){let a,s;try{if(!this.config.options.hostReports)return this.setIsolatedMode(),!0;if(s=this.config.apiKey,!s||s==="<API key>"){let S="No API key found in checksum config - please set it in the config file - checksum.config.ts";return this.runtimeTrace(S,"Checksum Config Error"),this.log(S,!0),this.shutdown(1),!1}let l=await this.getEnvInfo(),d=JSON.stringify({...l,isHidden:!!this.config.options.hideReports}),g=await fetch(`${this.config.apiURL}/client-api/test-runs`,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:s},body:d}),{uuid:b,appName:E}=await g.json();return this.testSuiteRunId=b,l.commit=l.name,l.name=E,this.testSuiteRunInfo={appName:E,commitHash:l.commitHash,envName:l.name,branch:l.branch,testSuiteRunId:b,checksumRuntimeVersion:this.checksumRuntimeVersion},!0}catch(l){let d=`Error connecting to Checksum, the report will not be hosted - ${l.message}`;return this.runtimeTrace(d,"Test Suite Init Error"),this.log(d),this.setIsolatedMode(),!0}}setIsolatedMode(){this.testSuiteRunId=process.env.CHECKSUM_TEST_SUITE_ID||(0,KDr.randomUUID)(),this.isolationMode=!0,this.completeIndicators.upload=!0,eg.testRun.monitoring.debugAnalytics?this.testSuiteRunInfo=zun(this.checksumRuntimeVersion,this.testSuiteRunId):this.testSuiteRunInfo=Jun(this.checksumRuntimeVersion,this.testSuiteRunId)}async sendTestRunEnd(a){if(!this.isolationMode){B7("Sending test run end API request");try{let s="{}";try{s=JSON.stringify({...a,endedAt:Date.now()})}catch(l){this.testSuiteAnalytics.testSuiteError({error:`Error stringifying stats ${l.message}`}),this.log(`Error stringifying stats ${l.message}`,!0),B7("Error preparing test stats for API request")}B7("Sending test run end request",s),await this.updateTestRun(`${this.config.apiURL}/client-api/test-runs/${this.testSuiteRunId}`,"PATCH",s)}catch(s){return this.testSuiteAnalytics.testSuiteError({error:`Error sending test run end ${s.message}`}),this.log(`Error sending test run end ${s.message}`,!0),null}}}async sendUploadsComplete(){if(!this.isolationMode)try{await this.updateTestRun(`${this.config.apiURL}/client-api/test-runs/${this.testSuiteRunId}/uploads-completed`,"PATCH")}catch(a){this.testSuiteAnalytics.testSuiteError({error:`Error sending test run uploads complete - ${a.message}`}),this.log(`Error sending test run uploads complete - ${a.message}`,!0)}}async sendProcessingError(){if(!this.isolationMode)try{await this.updateTestRun(`${this.config.apiURL}/client-api/test-runs/${this.testSuiteRunId}/process-error`,"PATCH")}catch(a){this.testSuiteAnalytics.testSuiteError({error:`Error sending test run processing error - ${a.message}`}),this.log(`Error sending test run processing error - ${a.message}`,!0)}}async updateTestRun(a,s,l=void 0){let d=await fetch(a,{method:s,headers:{Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:this.config.apiKey},body:l});return B7("Received update test run response from url:",a),await this.logApiResponse(d),d}async logApiResponse(a){try{if(!a.ok){let{status:l,statusText:d}=a,g=await a.text();this.testSuiteAnalytics.testSuiteError({status:l,statusText:d,error:g});return}a.headers.get("Content-Type").includes("application/json")?a.json().then(l=>{B7("API Response:",l)}):a.text().then(l=>{B7("API Response:",l)})}catch(s){this.testSuiteAnalytics.testSuiteError({error:`Error logging API response - ${s.message}`})}}logTRMMessage(a){(Array.isArray(a)?a:[a]).forEach(s=>{B7("[trm]",s)})}};e(YDr,"TestsRunner");var Xrt=YDr;var XDr=class XDr extends IP{constructor(r,a=!1){super(r,a)}async run(r){switch(r){default:console.log(`
|
|
1702
1702
|
Checksum CLI
|
package/package.json
CHANGED
package/test-run-monitor.js
CHANGED
|
@@ -450,7 +450,8 @@ Additional information: BADCLIENT: Bad error code, ${E} not found in range ${l}.
|
|
|
450
450
|
`+fe.map(BQe).join(`
|
|
451
451
|
`):" "+BQe(fe[0]):"as no adapter specified";throw new os("There is no suitable adapter to dispatch the request "+Re,"ERR_NOT_SUPPORT")}return J},"getAdapter"),adapters:FTe};function RTe(p){if(p.cancelToken&&p.cancelToken.throwIfRequested(),p.signal&&p.signal.aborted)throw new tb(null,p)}t(RTe,"throwIfCancellationRequested");function Bre(p){return RTe(p),p.headers=Op.from(p.headers),p.data=LU.call(p,p.transformRequest),["post","put","patch"].indexOf(p.method)!==-1&&p.headers.setContentType("application/x-www-form-urlencoded",!1),jre.getAdapter(p.adapter||n9.adapter,p)(p).then(t(function(D){return RTe(p),D.data=LU.call(p,p.transformResponse,D),D.headers=Op.from(D.headers),D},"onAdapterResolution"),t(function(D){return MU(D)||(RTe(p),D&&D.response&&(D.response.data=LU.call(p,p.transformResponse,D.response),D.response.headers=Op.from(D.response.headers))),Promise.reject(D)},"onAdapterRejection"))}t(Bre,"dispatchRequest");var Jre={};["object","boolean","number","function","string","symbol"].forEach((p,y)=>{Jre[p]=t(function(D){return typeof D===p||"a"+(y<1?"n ":" ")+p},"validator")});var JQe={};Jre.transitional=t(function(y,S,D){function J(Q,fe){return"[Axios v"+TI+"] Transitional option '"+Q+"'"+fe+(D?". "+D:"")}return t(J,"formatMessage"),(Q,fe,Re)=>{if(y===!1)throw new os(J(fe," has been removed"+(S?" in "+S:"")),os.ERR_DEPRECATED);return S&&!JQe[fe]&&(JQe[fe]=!0,console.warn(J(fe," has been deprecated since v"+S+" and will be removed in the near future"))),y?y(Q,fe,Re):!0}},"transitional");Jre.spelling=t(function(y){return(S,D)=>(console.warn(`${D} is likely a misspelling of ${y}`),!0)},"spelling");function zOt(p,y,S){if(typeof p!="object")throw new os("options must be an object",os.ERR_BAD_OPTION_VALUE);let D=Object.keys(p),J=D.length;for(;J-- >0;){let Q=D[J],fe=y[Q];if(fe){let Re=p[Q],st=Re===void 0||fe(Re,Q,p);if(st!==!0)throw new os("option "+Q+" must be "+st,os.ERR_BAD_OPTION_VALUE);continue}if(S!==!0)throw new os("Unknown option "+Q,os.ERR_BAD_OPTION)}}t(zOt,"assertOptions");var qU={assertOptions:zOt,validators:Jre};var Nk=qU.validators,LTe=class LTe{constructor(y){this.defaults=y||{},this.interceptors={request:new $2e,response:new $2e}}async request(y,S){try{return await this._request(y,S)}catch(D){if(D instanceof Error){let J={};Error.captureStackTrace?Error.captureStackTrace(J):J=new Error;let Q=J.stack?J.stack.replace(/^.+\n/,""):"";try{D.stack?Q&&!String(D.stack).endsWith(Q.replace(/^.+\n.+\n/,""))&&(D.stack+=`
|
|
452
452
|
`+Q):D.stack=Q}catch{}}throw D}}_request(y,S){typeof y=="string"?(S=S||{},S.url=y):S=y||{},S=I2(this.defaults,S);let{transitional:D,paramsSerializer:J,headers:Q}=S;D!==void 0&&qU.assertOptions(D,{silentJSONParsing:Nk.transitional(Nk.boolean),forcedJSONParsing:Nk.transitional(Nk.boolean),clarifyTimeoutError:Nk.transitional(Nk.boolean)},!1),J!=null&&(Vr.isFunction(J)?S.paramsSerializer={serialize:J}:qU.assertOptions(J,{encode:Nk.function,serialize:Nk.function},!0)),S.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?S.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:S.allowAbsoluteUrls=!0),qU.assertOptions(S,{baseUrl:Nk.spelling("baseURL"),withXsrfToken:Nk.spelling("withXSRFToken")},!0),S.method=(S.method||this.defaults.method||"get").toLowerCase();let fe=Q&&Vr.merge(Q.common,Q[S.method]);Q&&Vr.forEach(["delete","get","head","post","put","patch","common"],dt=>{delete Q[dt]}),S.headers=Op.concat(fe,Q);let Re=[],st=!0;this.interceptors.request.forEach(t(function(gt){typeof gt.runWhen=="function"&>.runWhen(S)===!1||(st=st&>.synchronous,Re.unshift(gt.fulfilled,gt.rejected))},"unshiftRequestInterceptors"));let Ke=[];this.interceptors.response.forEach(t(function(gt){Ke.push(gt.fulfilled,gt.rejected)},"pushResponseInterceptors"));let $e,Er=0,ke;if(!st){let dt=[Bre.bind(this),void 0];for(dt.unshift(...Re),dt.push(...Ke),ke=dt.length,$e=Promise.resolve(S);Er<ke;)$e=$e.then(dt[Er++],dt[Er++]);return $e}ke=Re.length;let Zr=S;for(;Er<ke;){let dt=Re[Er++],gt=Re[Er++];try{Zr=dt(Zr)}catch(Gn){gt.call(this,Gn);break}}try{$e=Bre.call(this,Zr)}catch(dt){return Promise.reject(dt)}for(Er=0,ke=Ke.length;Er<ke;)$e=$e.then(Ke[Er++],Ke[Er++]);return $e}getUri(y){y=I2(this.defaults,y);let S=vI(y.baseURL,y.url,y.allowAbsoluteUrls);return yI(S,y.params,y.paramsSerializer)}};t(LTe,"Axios");var _9=LTe;Vr.forEach(["delete","get","head","options"],t(function(y){_9.prototype[y]=function(S,D){return this.request(I2(D||{},{method:y,url:S,data:(D||{}).data}))}},"forEachMethodNoData"));Vr.forEach(["post","put","patch"],t(function(y){function S(D){return t(function(Q,fe,Re){return this.request(I2(Re||{},{method:y,headers:D?{"Content-Type":"multipart/form-data"}:{},url:Q,data:fe}))},"httpMethod")}t(S,"generateHTTPMethod"),_9.prototype[y]=S(),_9.prototype[y+"Form"]=S(!0)},"forEachMethodWithData"));var VU=_9;var zre=class zre{constructor(y){if(typeof y!="function")throw new TypeError("executor must be a function.");let S;this.promise=new Promise(t(function(Q){S=Q},"promiseExecutor"));let D=this;this.promise.then(J=>{if(!D._listeners)return;let Q=D._listeners.length;for(;Q-- >0;)D._listeners[Q](J);D._listeners=null}),this.promise.then=J=>{let Q,fe=new Promise(Re=>{D.subscribe(Re),Q=Re}).then(J);return fe.cancel=t(function(){D.unsubscribe(Q)},"reject"),fe},y(t(function(Q,fe,Re){D.reason||(D.reason=new tb(Q,fe,Re),S(D.reason))},"cancel"))}throwIfRequested(){if(this.reason)throw this.reason}subscribe(y){if(this.reason){y(this.reason);return}this._listeners?this._listeners.push(y):this._listeners=[y]}unsubscribe(y){if(!this._listeners)return;let S=this._listeners.indexOf(y);S!==-1&&this._listeners.splice(S,1)}toAbortSignal(){let y=new AbortController,S=t(D=>{y.abort(D)},"abort");return this.subscribe(S),y.signal.unsubscribe=()=>this.unsubscribe(S),y.signal}static source(){let y;return{token:new zre(t(function(J){y=J},"executor")),cancel:y}}};t(zre,"CancelToken");var MTe=zre,zQe=MTe;function jTe(p){return t(function(S){return p.apply(null,S)},"wrap")}t(jTe,"spread");function BTe(p){return Vr.isObject(p)&&p.isAxiosError===!0}t(BTe,"isAxiosError");var JTe={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(JTe).forEach(([p,y])=>{JTe[y]=p});var UQe=JTe;function WQe(p){let y=new VU(p),S=wU(VU.prototype.request,y);return Vr.extend(S,VU.prototype,y,{allOwnKeys:!0}),Vr.extend(S,y,null,{allOwnKeys:!0}),S.create=t(function(J){return WQe(I2(p,J))},"create"),S}t(WQe,"createInstance");var em=WQe(n9);em.Axios=VU;em.CanceledError=tb;em.CancelToken=zQe;em.isCancel=MU;em.VERSION=TI;em.toFormData=TP;em.AxiosError=os;em.Cancel=em.CanceledError;em.all=t(function(y){return Promise.all(y)},"all");em.spread=jTe;em.isAxiosError=BTe;em.mergeConfig=I2;em.AxiosHeaders=Op;em.formToJSON=p=>Pre(Vr.isHTMLForm(p)?new FormData(p):p);em.getAdapter=jre.getAdapter;em.HttpStatusCode=UQe;em.default=em;var Ure=em;var{Axios:Dzt,AxiosError:Pzt,CanceledError:Azt,isCancel:Nzt,CancelToken:Izt,VERSION:Ozt,all:Fzt,Cancel:Rzt,isAxiosError:Lzt,spread:Mzt,toFormData:jzt,AxiosHeaders:Bzt,HttpStatusCode:Jzt,formToJSON:zzt,getAdapter:Uzt,mergeConfig:Wzt}=Ure;var qre=require("fs");var zTe=class zTe{constructor(y,S,D,J,Q=!1,fe={start:t(Re=>{},"start"),complete:t(Re=>{},"complete"),error:t((Re,st)=>{},"error")}){this.apiBaseURL=y;this.apiKey=S;this.uploadTimeout=D;this.makeGetUploadUrlAPIPath=J;this.isolationMode=Q;this.reporter=fe}async uploadAsset(y){if(y.uploadStarted=!0,this.isolationMode){y.lastProgress=Date.now(),y.loadedBytes=0,y.sizeBytes=100,y.response=new Promise(D=>{setTimeout(()=>{y.complete=!0,y.lastProgress=Date.now(),y.loadedBytes=100,D({statusCode:200,ok:!0,body:"OK"})},10)});return}let{path:S}=y.info;try{let J=(0,qre.statSync)(S).size;if(y.sizeBytes=J,y.loadedBytes=0,y.lastProgress=Date.now(),this.reporter.start(S),await this.getSignedURLForUpload(y),!y.uploadURL){y.error=!0;return}let Q=(0,qre.createReadStream)(S),fe=await Ure.put(y.uploadURL,Q,{headers:{"Content-Type":uGe[y.info.type]??""},maxBodyLength:1/0,maxContentLength:1/0,onUploadProgress:t(Re=>{y.lastProgress=Re.loaded>y.loadedBytes?Date.now():y.lastProgress,y.loadedBytes=Re.loaded,y.sizeBytes=Re.total??J},"onUploadProgress"),timeout:this.uploadTimeout??void 0});if(fe.status!==200)throw new Error(`Upload failed with status ${fe.status}`);this.reporter.complete(S),y.complete=!0,y.response=fe.data}catch(D){this.reporter.error(S,D),y.error=!0}}async getSignedURLForUpload(y){try{let S=JSON.stringify(y.info),D=`${this.apiBaseURL}/${this.makeGetUploadUrlAPIPath(y)}`,J={Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:this.apiKey},Q=await fetch(D,{method:"POST",headers:J,body:S}),{url:fe}=await Q.json();y.uploadURL=fe}catch(S){return this.reporter.error(y.info.path,"Error getting signed URL for artifact"+String(S)),null}}};t(zTe,"TestAssetUploader");var Wre=zTe;var WTe=class WTe{constructor(){}sendToCLI(...y){console.log(`{trm}${y.map(S=>S.toString()).join(`,
|
|
453
|
-
`)}{/trm}`)}event(y,S){return new Promise(D=>{let J=S?`${y}=${S}`:y;setTimeout(()=>{this.sendToCLI(`monitor:${J}`),D(!0)},100)})}trace(y,S){try{let D=S?`${y}=${JSON.stringify(S)}`:y;setTimeout(()=>{this.sendToCLI(`trace:${D}`)},100)}catch{this.event("log","Error tracing event: "+y)}}log(y){return this.event("log",y)}debug(...y){this.sendToCLI(y)}};t(WTe,"CLIChannel");var UTe=WTe,qTe=class qTe{constructor(y,S=!1){this.config=y;this.isolationMode=S;this.MAX_UPLOADS=15;this.MONITOR_INTERVAL=2500;this.UPLOAD_TIMEOUT=10*60*1e3;this.UPLOAD_STALL_TIMEOUT=3*60*60*1e3;this.WATCH_TIMEOUT=2*60*1e3;this.assets=[];this.watchAssets=[];this.reportComplete=!1;this.processingInProgress=!1;this.pwTestIdToChecksumTestId={};this.channel=new UTe,this.testAssetUploader=new Wre(y.apiURL,y.apiKey,this.UPLOAD_TIMEOUT,()=>`client-api/test-runs/${this.config.sessionId}/get-upload-url`,this.isolationMode,{start:t(D=>this.channel.trace("Upload Start",{filename:D}),"start"),complete:t(D=>{if(!this.reportAsset||D!==this.reportAsset.info.path)try{(0,od.unlinkSync)(D),this.channel.debug(`[TestAssetUploader] Deleted file after successful upload: ${D}`)}catch(J){this.channel.debug(`[TestAssetUploader] Failed to delete file after upload: ${D}`,J)}this.channel.trace("Upload Complete",{filename:D})},"complete"),error:t((D,J)=>{this.channel.debug(`[TestAssetUploader] Error uploading asset: ${D}`),this.channel.trace("Upload Failed",{filename:D,error:J})},"error")}),setInterval(this.monitorUploads.bind(this),this.MONITOR_INTERVAL),this.listenForMessages(),this.startServer()}listenForMessages(){process.stdin.on("data",async y=>{let S=y.toString().trim();if(!S.startsWith("cli:"))return;let[D,J]=S.substring(4).split("=");switch(this.channel.debug("Received message from CLI "+D+" "+J),D){case"report":if(this.testRunEndTime=Date.now(),J!=="false")try{let Q=Buffer.from(J,"base64").toString("utf-8"),fe=JSON.parse(Q);await this.handleReport(fe)}catch(Q){this.channel.debug("Error JSON parsing report payload, continue without report. Error: "+this.stringify(Q)),this.reportComplete=!0}else this.channel.debug("Report received as false, marking as complete"),this.reportComplete=!0;this.channel.debug("Starting monitorUploadsCompletion"),this.monitorUploadsCompletion();break;case"shutdown":this.shutdown();break}})}readMetadataFile(y){try{return JSON.parse((0,od.readFileSync)(y,"utf-8"))}catch(S){return this.channel.trace("Runtime Error",`Error reading checksum metadata file ${y}: ${S.message}`),{}}}async serveReport(y){try{let S=(0,Lx.dirname)(y);await this.channel.log("Serving report in browser: "+S);let D=nre.isRepoMode?`yarn playwright show-report ${S}`:`npx playwright show-report ${S}`,J=(0,VQe.execSync)(D,{encoding:"utf8",stdio:"pipe"});await this.channel.log("Success: Report opened in browser")}catch(S){await this.channel.log(`Error serving report in browser: ${S.message}`),S.stderr&&await this.channel.log(S.stderr.toString())}}async handleReport(y){let{reportPath:S,pathToChecksumMetadata:D,didFail:J,openReportCriteria:Q,checksumRoot:fe,projectRoot:Re}=y;this.channel.debug(`Handling report ${this.isolationMode?"(isolation mode)":""}`+S),this.uploadReportData((0,Lx.dirname)(S));try{let st=this.readMetadataFile(D),Ke=new pre(S,this.config.sessionId,this.pwTestIdToChecksumTestId,st,{hosted:!this.isolationMode},this.channel,fe,Re);try{this.reportAsset=this.initAsset({type:"report",path:void 0}),await Ke.process(),this.reportAsset.info.path=Ke.getProcessedFilePath(),this.uploadAsset(this.reportAsset)}catch(Er){this.channel.debug("Error processing report, "+Er.message),this.reportAsset.error=!0}this.stats=Ke.getReportsStats(),this.channel.debug("Checking watch assets");let $e=this.watchAssets.filter(Er=>!(Er.type!=="trace"||Ke.testHasTrace(Er.testId,Er.project)));$e.length>0&&(this.channel.debug("Removed watch assets - "),this.channel.debug(JSON.stringify($e.map(Er=>Er.path)))),this.watchAssets=this.watchAssets.filter(Er=>Er.type!=="trace"||Ke.testHasTrace(Er.testId,Er.project))}catch(st){this.channel.debug("Error processing report, "+this.stringify(st)),this.reportAsset.error=!0}finally{if((Q==="always"||Q==="on-failure"&&J)&&await this.serveReport(S),D&&(0,od.existsSync)(D))try{(0,od.unlinkSync)(D)}catch(Ke){console.error(`Error deleting checksum metadata file ${D}: ${Ke.message}`)}}}async uploadReportData(y){let S=(0,Lx.join)(y,"data");try{let D=(0,od.readdirSync)(S),J=[".zip",".webm"],Q=D.filter(fe=>!J.includes((0,Lx.extname)(fe)));this.channel.debug("Preparing to upload report data files,"+Q);for(let fe of Q)this.channel.debug("Uploading report data file,"+fe),this.addAsset({type:"report-data-file",fileName:fe,path:`${S}/${fe}`})}catch(D){this.channel.debug(`Error reading/adding report data files from dir ${S}`+D.message)}}shutdown(){this.channel.debug("Received shutdown message from CLI"),this.server.close(),process.exit(0)}async monitorUploadsCompletion(){var D,J,Q,fe,Re;if(this.channel.debug("monitorUploadsCompletion",JSON.stringify({reportComplete:this.reportComplete,reportAssetExists:!!this.reportAsset,reportAssetComplete:(D=this.reportAsset)==null?void 0:D.complete,reportAssetError:(J=this.reportAsset)==null?void 0:J.error,processingInProgress:this.processingInProgress,numberOfAssets:this.assets.length,numberOfWatchAssets:this.watchAssets.length,numberOfAssetsComplete:this.assets.filter(st=>st.complete).length,numberOfAssetsError:this.assets.filter(st=>st.error).length})),!this.reportComplete&&this.reportAsset&&(this.reportAsset.complete||this.reportAsset.error)){this.channel.debug("Report complete, preparing stats"),this.channel.debug("Stats: "+this.stats?`{passed: ${this.stats.passed}, failed: ${this.stats.failed}, total: ${((Q=this.stats.tests)==null?void 0:Q.length)||0}}`:"No stats"),this.reportComplete=!0;let st="{}";try{st=JSON.stringify(this.stats)}catch(Ke){this.channel.debug("Error stringifying stats"),this.channel.log(`[monitorUploadsCompletion] Error stringifying stats: ${Ke.message}`)}this.channel.debug("Sending report-complete event: "+((fe=this.reportAsset)==null?void 0:fe.complete)?"complete: true":"complete: false"),this.channel.event("report-complete",`${(Re=this.reportAsset)!=null&&Re.complete?"true":"false"}:${st}`)}let y=this.testRunEndTime&&Date.now()-this.testRunEndTime>this.WATCH_TIMEOUT,S=this.isUploadStalled();if(!this.processingInProgress&&this.reportComplete&&(this.assets.filter(st=>st.complete||st.error).length===this.assets.length||S)&&(this.watchAssets.length===0||y)){let st=this.assets.find($e=>$e.error)?"uploads-complete-with-errors":"uploads-complete";this.channel.debug("Uploads complete, sending uploads complete event: "+st+" watchAssetsTimeoutExceeded: "+y+" isUploadStalled: "+S);let Ke=st==="uploads-complete"?{}:{uploadErrors:this.assets.filter($e=>$e.error).map($e=>{try{return JSON.stringify($e)}catch{return $e.info.path}}),watchAssets:this.watchAssets,testRunEndTime:this.testRunEndTime,now:Date.now()};this.cleanUp(),this.channel.event(st,JSON.stringify(Ke));return}await Kbe(1e3),this.monitorUploadsCompletion()}cleanUp(){let y;for(let S of this.assets)if(S.info.type==="rrweb-recording"){y=(0,Lx.dirname)(S.info.path);break}y&&(0,od.rmdirSync)(y,{recursive:!0})}isUploadStalled(){let y=this.assets.reduce((S,D)=>Math.max(S,D.lastProgress??0),0)-Date.now()>this.UPLOAD_STALL_TIMEOUT;return y&&this.channel.log("Uploads are stalled"),y}async startServer(){let y=await this.acquirePortNumber();this.channel.event("port",y.toString()),this.server=(0,HQe.createServer)((S,D)=>{let J=t(fe=>{D.writeHead(400,{"Content-Type":"text/plain"}),D.end(fe)},"returnErrorWithMessage");if(S.method!=="POST"){D.writeHead(404,{"Content-Type":"text/plain"}),D.end("Method not allowed");return}let Q="";S.on("data",fe=>{Q+=fe.toString()}),S.on("end",()=>{let fe;try{fe=JSON.parse(Q)}catch{return J("Invalid body")}let{type:Re,payload:st,watch:Ke}=fe;switch(this.channel.debug(`Server received message, ${Re}, ${this.stringify(st)}`),Re){case"asset":if(!st.path||!st.type)return J("Missing arguments");Ke?this.watchAsset(st):this.processAsset(st);break;case"testInfo":if(!st.pwTestId||!st.checksumTestId)return J("Missing arguments");this.pwTestIdToChecksumTestId[st.pwTestId]=st.checksumTestId;break;case"checksumTestMetadata":let $e=st;if(!$e.checksumTestId||!st.data)return J("Missing arguments");this.channel.event("checksumTestMetadata",JSON.stringify({...$e}));break;case"testStats":break;case"playwrightConfig":this.channel.event("playwrightConfig",JSON.stringify(st));break;default:return J("Invalid message type")}D.writeHead(200,{"Content-Type":"text/plain"}),D.end("OK")})}),this.server.listen(y)}stringify(y){try{return JSON.stringify(y)}catch{return"message"in y?y.message:y}}monitorUploads(){let{totalSizeBytes:y,totalUploadedBytes:S}=this.calculateUploadProgress();if(y>0&&!this.isolationMode){let Q=(S/y*100).toFixed(2);this.channel.event("upload-progress",Q)}let D=this.assets.filter(Q=>!Q.uploadStarted);if(D.length===0)return;let J=t(()=>this.assets.filter(Q=>Q.uploadStarted&&!Q.complete&&!Q.error).length,"getNumOfActiveUploads");if(!(J()>=this.MAX_UPLOADS))for(;D.length>0&&J()<this.MAX_UPLOADS;){let Q=D.pop();this.uploadAsset(Q)}}calculateUploadProgress(){let y=this.assets.reduce((D,{sizeBytes:J})=>D+(J??0),0),S=Math.min(y,this.assets.reduce((D,{loadedBytes:J})=>D+(J??0),0));return{totalSizeBytes:y,totalUploadedBytes:S}}getUploadLogMessage(y){switch(y.info.type){case"report":return"Uploading report";case"har":return`Uploading har file for test ${y.info.testId}`;case"trace":return`Uploading trace file for test ${y.info.testId}`;case"esra":return`Uploading metadata file for test ${y.info.testId}`;case"test-files":return`Uploading auto-healed test code for file ${y.info.path}`}}async uploadAsset(y){try{y.uploadStarted=!0;let S=this.getUploadLogMessage(y);S&&!this.isolationMode&&this.channel.event("log",S),await this.testAssetUploader.uploadAsset(y)}catch(S){y.error=!0,this.channel.debug("Error uploading asset"+this.stringify(S)),this.channel.trace("Upload Failed",{asset:y.info.fileName,error:String(S)})}}async getSignedURLForUpload(y){try{let{apiKey:S,sessionId:D,apiURL:J}=this.config,Q=y.info,fe=await fetch(`${J}/client-api/test-runs/${D}/get-upload-url`,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:S},body:JSON.stringify(Q)}),{url:Re}=await fe.json();y.uploadURL=Re}catch(S){return this.channel.debug("Error getting signed URL for artifact"+this.stringify(S)),null}}watchAsset(y){this.channel.debug("Watching file "+y.path),this.watchAssets.push({...y,addedAt:Date.now()});let S=t(async()=>{await this.waitForFileComplete(y.path)&&(this.processAsset(y),this.watchAssets=this.watchAssets.filter(J=>J.path!==y.path))},"waitForCompletion");if((0,od.existsSync)(y.path))S();else{let D=(0,Lx.dirname)(y.path),J=(0,Lx.basename)(y.path),Q=!1,fe=(0,od.watch)(D,async(Re,st)=>{if(!(st!==J||Q))try{this.channel.debug("Watched file changed "+y.path),Q=!0,await S()}finally{fe.close()}})}}waitForFileComplete(y,S=1e3,D=6e4,J=1){return new Promise(Q=>{let fe=Date.now(),Re=0,st=t(()=>{if(!(0,od.existsSync)(y))return this.channel.debug(`Asset required for upload doesn't exist anymore ${y}`),Q(!1);let Ke=(0,od.statSync)(y).size;if(Ke===Re){if(J>0){this.channel.debug(`File size has not changed, verifying stabilization, ${y}, size: ${Ke}, equalSizeValidationCountLeft: ${J}`),J--,setTimeout(st,S);return}return this.channel.debug(`File size has not changed, stabilization verified, ${y}, size: ${Ke}`),Q(!0)}if(this.channel.debug(`File size changed, waiting for stabilization, ${y}, previous size: ${Re}, current size: ${Ke}`),Date.now()-fe>D)return this.channel.debug(`Asset required for upload is taking over ${D} ms to write to disk ${y}`),Q(!0);Re=Ke,setTimeout(st,S)},"checkFile");st()})}processAsset(y){switch(y.type){case"trace":return this.processTrace(y.path,y.testId);case"har":return this.processHar(y.path,y.testId);case"rrweb-recording":case"esra":case"test-files":return this.addAsset(y)}}async processHar(y,S){}calculateSha1(y){let S=(0,Hre.createHash)("sha1");return S.update(y),S.digest("hex")}async processTrace(y,S){try{this.processingInProgress=!0,await Kbe(1e3);let D=y;if(!this.isolationMode){this.channel.debug(`Preparing trace for upload (testId: ${S})...`),D=y.replace(".zip",".actual.zip"),(0,od.renameSync)(y,D);let fe="checksum-playwright-trace:"+Date.now().toString()+(0,Hre.randomBytes)(1024).toString("hex");(0,od.writeFileSync)(y,fe)}let Q=t(()=>{let fe=(0,od.readFileSync)(y);return this.calculateSha1(fe)+(0,Lx.extname)(y)},"makePlaywrightHTMLReporterName")();this.channel.debug(`Trace file for test ${S} has been manipulated with file name ${Q}, sending for upload...`),this.addAsset({type:"report-data-file",path:D,testId:S,fileName:Q})}catch(D){let J=String(D);this.channel.debug("Error processing trace file"+J),this.channel.trace("Trace Processing Error",{error:J})}finally{this.processingInProgress=!1}}addAsset(y){this.channel.debug("Adding file "+y.path);let S=this.initAsset(y);return this.assets.push(S),S}initAsset(y){return{complete:!1,error:!1,response:void 0,info:y,removeAfterUpload:y.type==="rrweb-recording"}}async acquirePortNumber(){return await new Promise((y,S)=>{let D=GQe.createServer();D.unref(),D.on("error",S),D.listen(0,()=>{let J=D.address().port;D.close(()=>{y(J)})})})}};t(qTe,"TestRunMonitor");var Vre=qTe,$Qe;try{$Qe=JSON.parse(process.argv[2])}catch(p){console.log("Error starting test run monitor",p),process.exit(1)}var qQe;new Vre($Qe,((qQe=process.argv)==null?void 0:qQe[3])==="isolated");0&&(module.exports={TestRunMonitor});
|
|
453
|
+
`)}{/trm}`)}event(y,S){return new Promise(D=>{let J=S?`${y}=${S}`:y;setTimeout(()=>{this.sendToCLI(`monitor:${J}`),D(!0)},100)})}trace(y,S){try{let D=S?`${y}=${JSON.stringify(S)}`:y;setTimeout(()=>{this.sendToCLI(`trace:${D}`)},100)}catch{this.event("log","Error tracing event: "+y)}}log(y){return this.event("log",y)}debug(...y){this.sendToCLI(y)}};t(WTe,"CLIChannel");var UTe=WTe,qTe=class qTe{constructor(y,S=!1){this.config=y;this.isolationMode=S;this.MAX_UPLOADS=15;this.MONITOR_INTERVAL=2500;this.UPLOAD_TIMEOUT=10*60*1e3;this.UPLOAD_STALL_TIMEOUT=3*60*60*1e3;this.WATCH_TIMEOUT=2*60*1e3;this.assets=[];this.watchAssets=[];this.reportComplete=!1;this.processingInProgress=!1;this.pwTestIdToChecksumTestId={};this.channel=new UTe,this.testAssetUploader=new Wre(y.apiURL,y.apiKey,this.UPLOAD_TIMEOUT,()=>`client-api/test-runs/${this.config.sessionId}/get-upload-url`,this.isolationMode,{start:t(D=>this.channel.trace("Upload Start",{filename:D}),"start"),complete:t(D=>{if(!this.reportAsset||D!==this.reportAsset.info.path)try{(0,od.unlinkSync)(D),this.channel.debug(`[TestAssetUploader] Deleted file after successful upload: ${D}`)}catch(J){this.channel.debug(`[TestAssetUploader] Failed to delete file after upload: ${D}`,J)}this.channel.trace("Upload Complete",{filename:D})},"complete"),error:t((D,J)=>{this.channel.debug(`[TestAssetUploader] Error uploading asset: ${D}`),this.channel.trace("Upload Failed",{filename:D,error:J})},"error")}),setInterval(this.monitorUploads.bind(this),this.MONITOR_INTERVAL),this.listenForMessages(),this.startServer()}listenForMessages(){process.stdin.on("data",async y=>{let S=y.toString().trim();if(!S.startsWith("cli:"))return;let[D,J]=S.substring(4).split("=");switch(this.channel.debug("Received message from CLI "+D+" "+J),D){case"report":if(this.testRunEndTime=Date.now(),J!=="false")try{let Q=Buffer.from(J,"base64").toString("utf-8"),fe=JSON.parse(Q);await this.handleReport(fe)}catch(Q){this.channel.debug("Error JSON parsing report payload, continue without report. Error: "+this.stringify(Q)),this.reportComplete=!0}else this.channel.debug("Report received as false, marking as complete"),this.reportComplete=!0;this.channel.debug("Starting monitorUploadsCompletion"),this.monitorUploadsCompletion();break;case"shutdown":this.shutdown();break}})}readMetadataFile(y){try{return JSON.parse((0,od.readFileSync)(y,"utf-8"))}catch(S){return this.channel.trace("Runtime Error",`Error reading checksum metadata file ${y}: ${S.message}`),{}}}async serveReport(y){try{let S=(0,Lx.dirname)(y);await this.channel.log("Serving report in browser: "+S);let D=nre.isRepoMode?`yarn playwright show-report ${S}`:`npx playwright show-report ${S}`,J=(0,VQe.execSync)(D,{encoding:"utf8",stdio:"pipe"});await this.channel.log("Success: Report opened in browser")}catch(S){await this.channel.log(`Error serving report in browser: ${S.message}`),S.stderr&&await this.channel.log(S.stderr.toString())}}async handleReport(y){let{reportPath:S,pathToChecksumMetadata:D,didFail:J,openReportCriteria:Q,checksumRoot:fe,projectRoot:Re}=y;this.channel.debug(`Handling report ${this.isolationMode?"(isolation mode)":""}`+S),this.uploadReportData((0,Lx.dirname)(S));try{let st=this.readMetadataFile(D),Ke=new pre(S,this.config.sessionId,this.pwTestIdToChecksumTestId,st,{hosted:!this.isolationMode},this.channel,fe,Re);try{this.reportAsset=this.initAsset({type:"report",path:void 0}),await Ke.process(),this.reportAsset.info.path=Ke.getProcessedFilePath(),this.uploadAsset(this.reportAsset)}catch(Er){this.channel.debug("Error processing report, "+Er.message),this.reportAsset.error=!0}this.stats=Ke.getReportsStats(),this.channel.debug("Checking watch assets");let $e=this.watchAssets.filter(Er=>!(Er.type!=="trace"||Ke.testHasTrace(Er.testId,Er.project)));$e.length>0&&(this.channel.debug("Removed watch assets - "),this.channel.debug(JSON.stringify($e.map(Er=>Er.path)))),this.watchAssets=this.watchAssets.filter(Er=>Er.type!=="trace"||Ke.testHasTrace(Er.testId,Er.project))}catch(st){this.channel.debug("Error processing report, "+this.stringify(st)),this.reportAsset.error=!0}finally{if((Q==="always"||Q==="on-failure"&&J)&&await this.serveReport(S),D&&(0,od.existsSync)(D))try{(0,od.unlinkSync)(D)}catch(Ke){this.channel.debug(`[handleReport] Error deleting checksum metadata file ${D}: ${Ke.message}`)}}}async uploadReportData(y){let S=(0,Lx.join)(y,"data");try{let D=(0,od.readdirSync)(S),J=[".zip",".webm"],Q=D.filter(fe=>!J.includes((0,Lx.extname)(fe)));this.channel.debug("Preparing to upload report data files,"+Q);for(let fe of Q)this.channel.debug("Uploading report data file,"+fe),this.addAsset({type:"report-data-file",fileName:fe,path:`${S}/${fe}`})}catch(D){this.channel.debug(`Error reading/adding report data files from dir ${S}`+D.message)}}shutdown(){this.channel.debug("Received shutdown message from CLI"),this.server.close(),process.exit(0)}async monitorUploadsCompletion(){var D,J,Q,fe,Re;if(this.channel.debug("monitorUploadsCompletion",JSON.stringify({reportComplete:this.reportComplete,reportAssetExists:!!this.reportAsset,reportAssetComplete:(D=this.reportAsset)==null?void 0:D.complete,reportAssetError:(J=this.reportAsset)==null?void 0:J.error,processingInProgress:this.processingInProgress,numberOfAssets:this.assets.length,numberOfWatchAssets:this.watchAssets.length,numberOfAssetsComplete:this.assets.filter(st=>st.complete).length,numberOfAssetsError:this.assets.filter(st=>st.error).length})),!this.reportComplete&&this.reportAsset&&(this.reportAsset.complete||this.reportAsset.error)){this.channel.debug("Report complete, preparing stats"),this.channel.debug("Stats: "+this.stats?`{passed: ${this.stats.passed}, failed: ${this.stats.failed}, total: ${((Q=this.stats.tests)==null?void 0:Q.length)||0}}`:"No stats"),this.reportComplete=!0;let st="{}";try{st=JSON.stringify(this.stats)}catch(Ke){this.channel.debug("Error stringifying stats"),this.channel.log(`[monitorUploadsCompletion] Error stringifying stats: ${Ke.message}`)}this.channel.debug("Sending report-complete event:"),this.channel.debug((fe=this.reportAsset)!=null&&fe.complete?"complete: true":"complete: false"),this.channel.debug(`Stats JSON:
|
|
454
|
+
`+st),this.channel.event("report-complete",`${(Re=this.reportAsset)!=null&&Re.complete?"true":"false"}:${st}`)}let y=this.testRunEndTime&&Date.now()-this.testRunEndTime>this.WATCH_TIMEOUT,S=this.isUploadStalled();if(!this.processingInProgress&&this.reportComplete&&(this.assets.filter(st=>st.complete||st.error).length===this.assets.length||S)&&(this.watchAssets.length===0||y)){let st=this.assets.find($e=>$e.error)?"uploads-complete-with-errors":"uploads-complete";this.channel.debug("Uploads complete, sending uploads complete event: "+st+" watchAssetsTimeoutExceeded: "+y+" isUploadStalled: "+S);let Ke=st==="uploads-complete"?{}:{uploadErrors:this.assets.filter($e=>$e.error).map($e=>{try{return JSON.stringify($e)}catch{return $e.info.path}}),watchAssets:this.watchAssets,testRunEndTime:this.testRunEndTime,now:Date.now()};this.cleanUp(),this.channel.event(st,JSON.stringify(Ke));return}await Kbe(1e3),this.monitorUploadsCompletion()}cleanUp(){let y;for(let S of this.assets)if(S.info.type==="rrweb-recording"){y=(0,Lx.dirname)(S.info.path);break}y&&(0,od.rmdirSync)(y,{recursive:!0})}isUploadStalled(){let y=this.assets.reduce((S,D)=>Math.max(S,D.lastProgress??0),0)-Date.now()>this.UPLOAD_STALL_TIMEOUT;return y&&this.channel.log("Uploads are stalled"),y}async startServer(){let y=await this.acquirePortNumber();this.channel.event("port",y.toString()),this.server=(0,HQe.createServer)((S,D)=>{let J=t(fe=>{D.writeHead(400,{"Content-Type":"text/plain"}),D.end(fe)},"returnErrorWithMessage");if(S.method!=="POST"){D.writeHead(404,{"Content-Type":"text/plain"}),D.end("Method not allowed");return}let Q="";S.on("data",fe=>{Q+=fe.toString()}),S.on("end",()=>{let fe;try{fe=JSON.parse(Q)}catch{return J("Invalid body")}let{type:Re,payload:st,watch:Ke}=fe;switch(this.channel.debug(`Server received message, ${Re}, ${this.stringify(st)}`),Re){case"asset":if(!st.path||!st.type)return J("Missing arguments");Ke?this.watchAsset(st):this.processAsset(st);break;case"testInfo":if(!st.pwTestId||!st.checksumTestId)return J("Missing arguments");this.pwTestIdToChecksumTestId[st.pwTestId]=st.checksumTestId;break;case"checksumTestMetadata":let $e=st;if(!$e.checksumTestId||!st.data)return J("Missing arguments");this.channel.event("checksumTestMetadata",JSON.stringify({...$e}));break;case"testStats":break;case"playwrightConfig":this.channel.event("playwrightConfig",JSON.stringify(st));break;default:return J("Invalid message type")}D.writeHead(200,{"Content-Type":"text/plain"}),D.end("OK")})}),this.server.listen(y)}stringify(y){try{return JSON.stringify(y)}catch{return"message"in y?y.message:y}}monitorUploads(){let{totalSizeBytes:y,totalUploadedBytes:S}=this.calculateUploadProgress();if(y>0&&!this.isolationMode){let Q=(S/y*100).toFixed(2);this.channel.event("upload-progress",Q)}let D=this.assets.filter(Q=>!Q.uploadStarted);if(D.length===0)return;let J=t(()=>this.assets.filter(Q=>Q.uploadStarted&&!Q.complete&&!Q.error).length,"getNumOfActiveUploads");if(!(J()>=this.MAX_UPLOADS))for(;D.length>0&&J()<this.MAX_UPLOADS;){let Q=D.pop();this.uploadAsset(Q)}}calculateUploadProgress(){let y=this.assets.reduce((D,{sizeBytes:J})=>D+(J??0),0),S=Math.min(y,this.assets.reduce((D,{loadedBytes:J})=>D+(J??0),0));return{totalSizeBytes:y,totalUploadedBytes:S}}getUploadLogMessage(y){switch(y.info.type){case"report":return"Uploading report";case"har":return`Uploading har file for test ${y.info.testId}`;case"trace":return`Uploading trace file for test ${y.info.testId}`;case"esra":return`Uploading metadata file for test ${y.info.testId}`;case"test-files":return`Uploading auto-healed test code for file ${y.info.path}`}}async uploadAsset(y){try{y.uploadStarted=!0;let S=this.getUploadLogMessage(y);S&&!this.isolationMode&&this.channel.event("log",S),await this.testAssetUploader.uploadAsset(y)}catch(S){y.error=!0,this.channel.debug("Error uploading asset"+this.stringify(S)),this.channel.trace("Upload Failed",{asset:y.info.fileName,error:String(S)})}}async getSignedURLForUpload(y){try{let{apiKey:S,sessionId:D,apiURL:J}=this.config,Q=y.info,fe=await fetch(`${J}/client-api/test-runs/${D}/get-upload-url`,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:S},body:JSON.stringify(Q)}),{url:Re}=await fe.json();y.uploadURL=Re}catch(S){return this.channel.debug("Error getting signed URL for artifact"+this.stringify(S)),null}}watchAsset(y){this.channel.debug("Watching file "+y.path),this.watchAssets.push({...y,addedAt:Date.now()});let S=t(async()=>{await this.waitForFileComplete(y.path)&&(this.processAsset(y),this.watchAssets=this.watchAssets.filter(J=>J.path!==y.path))},"waitForCompletion");if((0,od.existsSync)(y.path))S();else{let D=(0,Lx.dirname)(y.path),J=(0,Lx.basename)(y.path),Q=!1,fe=(0,od.watch)(D,async(Re,st)=>{if(!(st!==J||Q))try{this.channel.debug("Watched file changed "+y.path),Q=!0,await S()}finally{fe.close()}})}}waitForFileComplete(y,S=1e3,D=6e4,J=1){return new Promise(Q=>{let fe=Date.now(),Re=0,st=t(()=>{if(!(0,od.existsSync)(y))return this.channel.debug(`Asset required for upload doesn't exist anymore ${y}`),Q(!1);let Ke=(0,od.statSync)(y).size;if(Ke===Re){if(J>0){this.channel.debug(`File size has not changed, verifying stabilization, ${y}, size: ${Ke}, equalSizeValidationCountLeft: ${J}`),J--,setTimeout(st,S);return}return this.channel.debug(`File size has not changed, stabilization verified, ${y}, size: ${Ke}`),Q(!0)}if(this.channel.debug(`File size changed, waiting for stabilization, ${y}, previous size: ${Re}, current size: ${Ke}`),Date.now()-fe>D)return this.channel.debug(`Asset required for upload is taking over ${D} ms to write to disk ${y}`),Q(!0);Re=Ke,setTimeout(st,S)},"checkFile");st()})}processAsset(y){switch(y.type){case"trace":return this.processTrace(y.path,y.testId);case"har":return this.processHar(y.path,y.testId);case"rrweb-recording":case"esra":case"test-files":return this.addAsset(y)}}async processHar(y,S){}calculateSha1(y){let S=(0,Hre.createHash)("sha1");return S.update(y),S.digest("hex")}async processTrace(y,S){try{this.processingInProgress=!0,await Kbe(1e3);let D=y;if(!this.isolationMode){this.channel.debug(`Preparing trace for upload (testId: ${S})...`),D=y.replace(".zip",".actual.zip"),(0,od.renameSync)(y,D);let fe="checksum-playwright-trace:"+Date.now().toString()+(0,Hre.randomBytes)(1024).toString("hex");(0,od.writeFileSync)(y,fe)}let Q=t(()=>{let fe=(0,od.readFileSync)(y);return this.calculateSha1(fe)+(0,Lx.extname)(y)},"makePlaywrightHTMLReporterName")();this.channel.debug(`Trace file for test ${S} has been manipulated with file name ${Q}, sending for upload...`),this.addAsset({type:"report-data-file",path:D,testId:S,fileName:Q})}catch(D){let J=String(D);this.channel.debug("Error processing trace file"+J),this.channel.trace("Trace Processing Error",{error:J})}finally{this.processingInProgress=!1}}addAsset(y){this.channel.debug("Adding file "+y.path);let S=this.initAsset(y);return this.assets.push(S),S}initAsset(y){return{complete:!1,error:!1,response:void 0,info:y,removeAfterUpload:y.type==="rrweb-recording"}}async acquirePortNumber(){return await new Promise((y,S)=>{let D=GQe.createServer();D.unref(),D.on("error",S),D.listen(0,()=>{let J=D.address().port;D.close(()=>{y(J)})})})}};t(qTe,"TestRunMonitor");var Vre=qTe,$Qe;try{$Qe=JSON.parse(process.argv[2])}catch(p){console.log("Error starting test run monitor",p),process.exit(1)}var qQe;new Vre($Qe,((qQe=process.argv)==null?void 0:qQe[3])==="isolated");0&&(module.exports={TestRunMonitor});
|
|
454
455
|
/*! Bundled license information:
|
|
455
456
|
|
|
456
457
|
typescript/lib/typescript.js:
|