@checksum-ai/runtime 1.1.37 → 1.1.38
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/cli.js +1 -1
- package/package.json +1 -1
- package/test-run-monitor.js +5 -5
package/cli.js
CHANGED
|
@@ -114,7 +114,7 @@ Please see the 3.x to 4.x migration guide for details on how to update your app.
|
|
|
114
114
|
export default getChecksumConfig(${JSON.stringify(this.config,null,2)});
|
|
115
115
|
`;(0,dt.writeFileSync)(t,r)}cleanup(){this.deleteVolatileConfig(),this.childProcesses.forEach(t=>{t.kill("SIGTERM")})}async getEnvInfo(){let t={commitHash:"",branch:"branch",environment:process.env.CI?"CI":"local",name:"name",startedAt:Date.now(),runtimeVersion:this.checksumRuntimeVersion};try{t.commitHash=await this.getCmdOutput("git rev-parse HEAD")}catch(r){console.log("Error getting git hash",r.message)}try{t.branch=await this.getCmdOutput("git rev-parse --abbrev-ref HEAD")}catch(r){console.log("Error getting branch",r.message)}return t.name=await this.getEnvName(),t}async getEnvName(){let t=this.getChecksumArg("title");if(typeof t=="string"&&(t==null?void 0:t.length)>0)return t;try{return await this.getCmdOutput("git log -1 --pretty=%B")}catch(r){console.log("Error getting name",r.message);return}}getVolatileConfigPath(){return(0,er.join)(this.checksumRoot??"","checksum.config.tmp.ts")}deleteVolatileConfig(){let t=this.getVolatileConfigPath();(0,dt.existsSync)(t)&&(0,dt.rmSync)(t)}setChecksumConfig(){this.config={...require((0,er.join)(this.checksumRoot,"checksum.config.ts")).default||{},...this.volatileChecksumConfig||{}},this.debugMode&&(this.config.options.printLogs=!0)}processConfigArg(){this.deleteVolatileConfig();let t=this.getChecksumArg("config");if(t)try{this.volatileChecksumConfig=JSON.parse(t)}catch(r){this.volatileChecksumConfig=void 0,console.log("Error parsing cksm config",r.message)}}getNonChecksumArgs(){return this.args.filter(t=>!this.isChecksumArg(t))}getArg(t){var a;let r=this.args.find(s=>s.startsWith(`${t}`)),i=(a=r==null?void 0:r.split("=")[1])==null?void 0:a.trim();return i||!!r}getChecksumArg(t){return this.getArg(`--cksm-${t}`)}getChecksumRootOrigin(){return(0,er.join)(this.projectRootDirectory,"node_modules","@checksum-ai","runtime","checksum-root")}locateChecksumLibs(){try{this.findProjectRoot(),this.findChecksumRoot(),Ve("Project root found at",this.projectRootDirectory),Ve("Checksum root found at",this.checksumRoot)}catch(t){console.log(t.message),process.exit(1)}}findProjectRoot(){let t=process.cwd();for(let r=0;r<6;r++){let i=(0,er.join)(t,"node_modules","@checksum-ai","runtime");if((0,dt.existsSync)(i)){this.projectRootDirectory=t;return}if((0,er.parse)(t).root===t)break;t=(0,er.join)(t,"..")}throw new Error("Could not resolve checksum root origins")}findChecksumRoot(){let t=n(i=>{try{return(0,dt.readdirSync)(i).includes("checksum.config.ts")}catch{return!1}},"containsChecksumConfig"),r=[this.projectRootDirectory];for(;r.length;){let i=r.pop(),a=(0,dt.readdirSync)(i,{withFileTypes:!0});for(let s of a){let l=(0,er.join)(i,s.name),u=l;if(s.isSymbolicLink())try{let d=(0,dt.readlinkSync)(l);if(!(0,dt.lstatSync)(d).isDirectory())continue;u=d}catch{continue}else if(!s.isDirectory())continue;if(s.name===Fl){if(t(u)){this.checksumRoot=u;return}}else r.push(l)}}throw new Error("Could not find checksum root folder. Run `npx checksumai init` to create one.")}isChecksumArg(t){return t.startsWith("--cksm-")}};n(eg,"CLICommandBase");var mr=eg;var tg=class tg extends mr{constructor(r,i=!1){super(r,i);this.MAX_COMPLETION_WAIT=10*60*1e3;this.TEST_RUN_MONITOR_PATH=(0,Ns.join)(__dirname,"test-run-monitor.js");this.didFail=!1;this.isolationMode=!1;this.trmMessagesBuffer="";this.completeIndicators={upload:!1,tests:!1,report:!1};this.uploadProgress=0;this.replMode}get replMode(){return this.getChecksumArg("repl")}async run(){if(this.loadChecksumData(),this.validateAuthExists(),!await this.getSession())return;let r;try{r=await gt(this.startTestRunMonitor(this.testSession),1e4,"test run monitor timeout")}catch{console.log("Error starting test run monitor. Test results will not be available on checksum.")}this.buildVolatileConfig();let i={CHECKSUM_ROOT_FOLDER:this.checksumRoot};r&&(i.CHECKSUM_UPLOAD_AGENT_PORT=r),this.config.options.hostReports&&(i.PW_TEST_HTML_REPORT_OPEN="never"),this.testSession&&this.testSession!=="isolated-session"&&(i.CHECKSUM_TEST_SUITE_ID=this.testSession),this.replMode&&(i.CHECKSUM_REPL="true");let a=this.getNonChecksumArgs();this.replMode&&a.push("--debug");let s=`npx playwright test --config "${this.getPlaywrightConfigFilePath()}" ${a.map(l=>`"${l}"`).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(s,i),await this.execCmd(`node ${__dirname}/repl.js`,i)):await this.execCmd(s,i),console.log("Tests execution finished")}catch{this.didFail=!0,console.log("Error during test execution: Failed passing test")}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()}}getPlaywrightReportPath(){var a;let r=n(s=>(Ve("Using report folder",s),(0,Ns.join)(s,"index.html")),"makeFilePath");if(process.env.PLAYWRIGHT_HTML_OUTPUT_DIR)return r(process.env.PLAYWRIGHT_HTML_OUTPUT_DIR);let i=(a=this.playwrightConfig)==null?void 0:a.reporter;if(i instanceof Array){let l=i.filter(u=>u instanceof Array&&u[0]==="html").find(u=>{var d;return(d=u[1])==null?void 0:d.outputFolder});if(l)return r((0,Ns.join)(this.checksumRoot,l[1].outputFolder))}return r((0,Ns.join)(this.projectRootDirectory,"playwright-report"))}sendReportUploadRequest(){let r=this.getPlaywrightReportPath();if(!(0,w_.existsSync)(r)){console.log(`Could not find report file at ${r}`),this.completeIndicators.report=!0,this.testRunMonitorProcess.stdin.write("cli:report=false");return}Ve("Sending report upload request",r),this.testRunMonitorProcess.stdin.write(`cli:report=${r}`)}startTestRunMonitor(r){return new Promise(i=>{console.log("Starting test run monitor"),this.testRunMonitorProcess=S_.spawn("node",[this.TEST_RUN_MONITOR_PATH,JSON.stringify({sessionId:r,apiURL:this.config.apiURL,apiKey:this.config.apiKey}),...this.isolationMode?["isolated"]:[]]),this.testRunMonitorProcess.stdout.on("data",a=>{let s=this.handleTRMMessage(a.toString().trim());if(s.length){Ve("[trm]",s.length===1?s[0]:s);for(let l of s){if(!l.startsWith("monitor"))return;let u=l.substring("monitor".length+1),d=u.indexOf("=");if(d===-1){this.handleTestRunMonitorMessage(u,"");continue}let[f,h]=[u.substring(0,d),u.substring(d+1)];if(!Object.values($d).includes(f)){console.warn(`Unknown test run monitor message: ${f}`);continue}f==="port"?i(h):this.handleTestRunMonitorMessage(f,h)}}}),this.testRunMonitorProcess.on("exit",(a,s)=>{console.log(`test run monitor process exited with code ${a} and signal ${s}`)}),this.testRunMonitorProcess.stderr.on("data",a=>{this.debugMode&&console.error("[trm] Error:",a.toString())}),this.testRunMonitorProcess.on("error",a=>{console.error(`Error starting test run monitor: ${a.message}`)})})}handleTRMMessage(r){let i=this.trmMessagesBuffer+r,a,s,l=n(()=>{a=i.indexOf("{trm}"),s=i.indexOf("{/trm}")},"findIndexes");l();let u=[];for(;a!==-1&&s!==-1&&s>a;){if(u.push(i.substring(a+"{trm}".length,s)),i=i.slice(s+"{/trm}".length).trim(),i.length&&!i.startsWith("{trm}"))return console.warn("Buffered data does not start with start delimiter",i),this.trmMessagesBuffer="",u;this.trmMessagesBuffer=i,l()}return u}async handleTestRunMonitorMessage(r,i){switch(r){case"complete-with-errors":console.log("Error uploading test files to Checksum");try{let a=JSON.parse(i);console.log("Error data",a)}catch{}this.sendProcessingError().then(()=>{this.completeIndicators.upload=!0});break;case"complete":this.isolationMode||console.log("Test files uploaded successfully"),this.sendUploadsComplete().then(()=>{this.completeIndicators.upload=!0});break;case"report-complete":{if(this.isolationMode){this.completeIndicators.report=!0;break}let a=i.slice(0,i.indexOf(":"))==="true",s=i.slice(i.indexOf(":")+1),l={};try{l=JSON.parse(s)}catch(u){console.log("Error parsing stats",u.message)}if(await this.sendTestRunEnd(l),this.completeIndicators.report=!0,a){let u=`Checksum report URL: ${this.checksumAppUrl}/#/test-runs/${this.testSession}`,d="*".repeat(u.length);console.log(`${d}
|
|
116
116
|
${u}
|
|
117
|
-
${d}`)}else console.log("An error occurred while uploading the test report to Checksum");break}case"upload-progress":{let a=parseInt(i);(a<this.uploadProgress||a>=this.uploadProgress+10||a===100&&this.uploadProgress!==100)&&(this.uploadProgress=a,console.log(`[ Uploads progress: ${this.uploadProgress}% ]`))}break;case"log":console.log(i);break;case"playwrightConfig":try{this.playwrightConfig=JSON.parse(i)}catch(a){console.warn("Error parsing playwright config",a.message)}break;default:console.warn(`Unhandled test run monitor message: ${r}=${i}`)}}async handleCompleteMessage(){let r=Date.now();for(;;){if(Date.now()-r>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.shutdown(1);return}Object.keys(this.completeIndicators).find(i=>!this.completeIndicators[i])?(Ve(this.completeIndicators),await Ce(5e3)):(console.log("Checksum test run complete"),this.shutdown(
|
|
117
|
+
${d}`)}else console.log("An error occurred while uploading the test report to Checksum");break}case"upload-progress":{let a=parseInt(i);(a<this.uploadProgress||a>=this.uploadProgress+10||a===100&&this.uploadProgress!==100)&&(this.uploadProgress=a,console.log(`[ Uploads progress: ${this.uploadProgress}% ]`))}break;case"log":console.log(i);break;case"playwrightConfig":try{this.playwrightConfig=JSON.parse(i)}catch(a){console.warn("Error parsing playwright config",a.message)}break;default:console.warn(`Unhandled test run monitor message: ${r}=${i}`)}}async handleCompleteMessage(){let r=Date.now();for(;;){if(Date.now()-r>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.shutdown(1);return}Object.keys(this.completeIndicators).find(i=>!this.completeIndicators[i])?(Ve(this.completeIndicators),await Ce(5e3)):(console.log("Checksum test run complete"),this.shutdown(0))}}shutdown(r=0){this.cleanup(),process.exit(r)}cleanup(){var r,i;super.cleanup(),(r=this.testRunMonitorProcess)==null||r.stdin.write("cli:shutdown"),(i=this.testRunMonitorProcess)==null||i.kill()}async getSession(){try{if(!this.config.options.hostReports)return this.setIsolatedMode(),!0;let r=this.config.apiKey;if(!r||r==="<API key>")return this.printError("No API key found in checksum config - please set it in the config file - checksum.config.ts"),this.shutdown(1),!1;let i=JSON.stringify(await this.getEnvInfo()),a=await fetch(`${this.config.apiURL}/client-api/test-runs`,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:r},body:i});return this.testSession=(await a.json()).uuid,!0}catch{return console.log("Error connecting to Checksum, the report will not be hosted"),this.setIsolatedMode(),!0}}setIsolatedMode(){this.isolationMode=!0,this.testSession="isolated-session"}async sendTestRunEnd(r){if(!this.isolationMode)try{Ve("Sending test run end",r);let i="{}";try{i=JSON.stringify({...r,endedAt:Date.now()})}catch(a){console.log("Error stringifying stats",a.message,r)}await this.updateTestRun(`${this.config.apiURL}/client-api/test-runs/${this.testSession}`,"PATCH",i)}catch(i){return console.log("Error sending test run end",i.message),null}}async sendUploadsComplete(){if(!this.isolationMode)try{await this.updateTestRun(`${this.config.apiURL}/client-api/test-runs/${this.testSession}/uploads-completed`,"PATCH")}catch(r){console.log("Error sending test run uploads complete",r.message)}}async sendProcessingError(){if(!this.isolationMode)try{await this.updateTestRun(`${this.config.apiURL}/client-api/test-runs/${this.testSession}/process-error`,"PATCH")}catch(r){console.log("Error sending test run processing error",r.message)}}async updateTestRun(r,i,a=void 0){let s=await fetch(r,{method:i,headers:{Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:this.config.apiKey},body:a});return Ve("Received update test run response from url:",r),await this.logApiResponse(s),s}async logApiResponse(r){try{if(!r.ok){Ve("HTTP Error:",r.status,r.statusText);let a=await r.text();Ve("Error Details:",a);return}r.headers.get("Content-Type").includes("application/json")?r.json().then(a=>{Ve("API Response:",a)}):r.text().then(a=>{Ve("API Response:",a)})}catch(i){Ve("Error logging API response",i.message)}}};n(tg,"TestsRunner");var Iu=tg;var rg=class rg extends mr{constructor(t,r=!1){super(t,r)}async run(t){switch(t){default:console.log(`
|
|
118
118
|
Checksum CLI
|
|
119
119
|
Usage: checksum [command] [options]
|
|
120
120
|
|