@testrelic/playwright-analytics 2.3.10 → 2.3.12
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/README.md +42 -0
- package/dist/cli.cjs +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -947,7 +947,7 @@ body{
|
|
|
947
947
|
/* Load first page of network requests */
|
|
948
948
|
if(merged._networkCount>0){
|
|
949
949
|
pending++;
|
|
950
|
-
fetchData(testId,'network',1,
|
|
950
|
+
fetchData(testId,'network',1,5000,function(err,result){
|
|
951
951
|
if(!err&&result){
|
|
952
952
|
merged.networkRequests=result.items;
|
|
953
953
|
merged._networkTotal=result.total;
|
|
@@ -960,7 +960,7 @@ body{
|
|
|
960
960
|
/* Load first page of console logs */
|
|
961
961
|
if(merged._consoleCount>0){
|
|
962
962
|
pending++;
|
|
963
|
-
fetchData(testId,'console',1,
|
|
963
|
+
fetchData(testId,'console',1,5000,function(err,result){
|
|
964
964
|
if(!err&&result){
|
|
965
965
|
merged.consoleLogs=result.items;
|
|
966
966
|
merged._consoleTotal=result.total;
|
|
@@ -2478,7 +2478,7 @@ ${o?`<script id="artifact-manifest-data" type="application/json">${o}</script>`:
|
|
|
2478
2478
|
</body>
|
|
2479
2479
|
</html>`}function Le(t){try{let e=process.platform,r;e==="darwin"?r=`open "${t}"`:e==="win32"?r=`start "" "${t}"`:r=`xdg-open "${t}"`,exec(r,n=>{n&&process.stderr.write(`[testrelic] Failed to open browser: ${n.message}
|
|
2480
2480
|
`);});}catch{}}var yt=join(tmpdir(),"testrelic-data"),N=class{constructor(e){this.count=0;this.closed=false;mkdirSync(yt,{recursive:true}),this.filePath=join(yt,`${e}-${randomUUID().substring(0,8)}.jsonl`),this.fd=openSync(this.filePath,"w");}append(e){if(this.closed)return;let r=JSON.stringify(e)+`
|
|
2481
|
-
`;writeSync(this.fd,r),this.count++;}getPath(){return this.filePath}getCount(){return this.count}close(){if(!this.closed){this.closed=true;try{closeSync(this.fd);}catch{}}}cleanup(){try{unlinkSync(this.filePath);}catch{}}};async function wt(t,e,r,n){let s=(e-1)*r,a=[],o=0,i=createInterface({input:createReadStream(t,{encoding:"utf-8"}),crlfDelay:1/0});for await(let c of i)if(c.length!==0){if(o>=s&&a.length<r)try{a.push(JSON.parse(c));}catch{}if(o++,a.length>=r&&n!==void 0)break}let l=n??o,d=Math.max(1,Math.ceil(l/r));return {items:a,total:l,page:e,pageSize:r,totalPages:d}}var Ct=/^[a-f0-9]{12}$/,Ne=/^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}(-\d+)?$/,Tt=
|
|
2481
|
+
`;writeSync(this.fd,r),this.count++;}getPath(){return this.filePath}getCount(){return this.count}close(){if(!this.closed){this.closed=true;try{closeSync(this.fd);}catch{}}}cleanup(){try{unlinkSync(this.filePath);}catch{}}};async function wt(t,e,r,n){let s=(e-1)*r,a=[],o=0,i=createInterface({input:createReadStream(t,{encoding:"utf-8"}),crlfDelay:1/0});for await(let c of i)if(c.length!==0){if(o>=s&&a.length<r)try{a.push(JSON.parse(c));}catch{}if(o++,a.length>=r&&n!==void 0)break}let l=n??o,d=Math.max(1,Math.ceil(l/r));return {items:a,total:l,page:e,pageSize:r,totalPages:d}}var Ct=/^[a-f0-9]{12}$/,Ne=/^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}(-\d+)?$/,Tt=5e3;function x(t,e,r){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(r));}function St(t){t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Access-Control-Allow-Methods","GET, DELETE, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type");}function re(t){try{return existsSync(t)?JSON.parse(readFileSync(t,"utf-8")):null}catch{return null}}function ne(t){let e=0;try{let r=readdirSync(t,{withFileTypes:!0});for(let n of r){let s=join(t,n.name);n.isFile()?e+=statSync(s).size:n.isDirectory()&&(e+=ne(s));}}catch{}return e}function Rt(t,e,r,n){let s=re(join(r,"index.json"));x(e,200,{status:"ok",reportMode:"streaming",testCount:s?.length??0,uptime:Math.floor((Date.now()-n)/1e3)});}function At(t,e,r){let n=re(join(r,"summary.json"));if(!n){x(e,404,{error:"Summary not found"});return}x(e,200,n);}function _t(t,e,r){let n=re(join(r,"index.json"));if(!n){x(e,404,{error:"Test index not found"});return}let a=new URL(t.url??"/",`http://${t.headers.host}`).searchParams,o=Math.max(1,parseInt(a.get("page")??"1",10)||1),i=Math.min(Tt,Math.max(1,parseInt(a.get("pageSize")??"100",10)||100)),l=a.get("status")?.split(",").filter(Boolean)??null,d=a.get("file")??null,c=a.get("search")?.toLowerCase()??null,p=a.get("tag")?.split(",").filter(Boolean)??null,f=a.get("sort")??"file",u=a.get("order")==="desc"?-1:1,g=n;l&&l.length>0&&(g=g.filter(w=>l.includes(w.status))),d&&(g=g.filter(w=>w.filePath===d||w.filePath.startsWith(d+"/"))),c&&(g=g.filter(w=>w.title.toLowerCase().includes(c)||w.filePath.toLowerCase().includes(c))),p&&p.length>0&&(g=g.filter(w=>p.some(y=>w.tags.includes(y)))),g=[...g].sort((w,y)=>{let T=0;switch(f){case "duration":T=w.duration-y.duration;break;case "status":T=w.status.localeCompare(y.status);break;case "title":T=w.title.localeCompare(y.title);break;default:T=w.filePath.localeCompare(y.filePath);break}return T*u});let h=g.length,m=Math.max(1,Math.ceil(h/i)),b=(o-1)*i,C=g.slice(b,b+i);x(e,200,{tests:C,pagination:{page:o,pageSize:i,totalItems:h,totalPages:m},filters:{status:l,file:d,search:c,tag:p}});}function It(t,e,r,n){if(!Ct.test(n)){x(e,400,{error:"Invalid test ID format"});return}let s=join(r,"tests",n,"meta.json"),a=join(r,"tests",`${n}.json`),o=existsSync(s)?s:existsSync(a)?a:null;if(!o){x(e,404,{error:`Test not found: ${n}`});return}try{let i=readFileSync(o,"utf-8");e.writeHead(200,{"Content-Type":"application/json"}),e.end(i);}catch(i){x(e,500,{error:i instanceof Error?i.message:String(i)});}}async function Lt(t,e,r,n,s){if(!Ct.test(n)){x(e,400,{error:"Invalid test ID format"});return}let o=join(r,"tests",n,{network:"network.jsonl",console:"console.jsonl","api-calls":"api-calls.jsonl"}[s]);if(!existsSync(o)){x(e,200,{items:[],total:0,page:1,pageSize:50,totalPages:0});return}try{let l=new URL(t.url??"/",`http://${t.headers.host}`).searchParams,d=Math.max(1,parseInt(l.get("page")??"1",10)||1),c=Math.min(Tt,Math.max(1,parseInt(l.get("pageSize")??"50",10)||50)),p,f=join(r,"tests",n,"meta.json");if(existsSync(f))try{let g=JSON.parse(readFileSync(f,"utf-8"));switch(s){case "network":p=g.networkRequestsCount;break;case "console":p=g.consoleLogsCount;break;case "api-calls":p=g.apiCallsCount;break}}catch{}let u=await wt(o,d,c,p);x(e,200,u);}catch(i){x(e,500,{error:i instanceof Error?i.message:String(i)});}}function Nt(t,e,r){let n=re(join(r,"index.json"));if(!n){x(e,404,{error:"Test index not found"});return}let s=new Map;for(let o of n){if(o.isRetry)continue;let i=s.get(o.filePath);switch(i||(i={total:0,passed:0,failed:0,flaky:0,skipped:0,timedOut:0},s.set(o.filePath,i)),i.total++,o.status){case "passed":i.passed++;break;case "failed":i.failed++;break;case "flaky":i.flaky++;break;case "skipped":i.skipped++;break;case "timedout":i.timedOut++;break}}let a=Array.from(s.entries()).map(([o,i])=>({filePath:o,...i})).sort((o,i)=>o.filePath.localeCompare(i.filePath));x(e,200,{files:a});}function Mt(t,e,r){if(!existsSync(r)){x(e,200,{runs:[],totalSizeBytes:0});return}try{let n=[],s=0,a=readdirSync(r,{withFileTypes:!0});for(let o of a){if(!o.isDirectory()||!Ne.test(o.name))continue;let i=join(r,o.name),l=ne(i),d=readdirSync(i,{withFileTypes:!0}).filter(c=>c.isDirectory());n.push({folderName:o.name,totalSizeBytes:l,testCount:d.length}),s+=l;}n.sort((o,i)=>i.folderName.localeCompare(o.folderName)),x(e,200,{runs:n,totalSizeBytes:s});}catch(n){x(e,500,{error:n instanceof Error?n.message:String(n)});}}function Et(t,e,r){try{let n=0,s=0;if(existsSync(r)){let a=readdirSync(r,{withFileTypes:!0});for(let o of a){if(!o.isDirectory()||!Ne.test(o.name))continue;let i=join(r,o.name),l=ne(i);rmSync(i,{recursive:!0,force:!0}),s+=l,n++;}}x(e,200,{deletedCount:n,freedBytes:s});}catch(n){x(e,500,{error:n instanceof Error?n.message:String(n)});}}function Pt(t,e,r,n){if(!Ne.test(n)){x(e,400,{error:"Invalid folder name"});return}let s=join(r,n);try{if(!statSync(s).isDirectory()){x(e,404,{error:"Not found"});return}}catch{x(e,404,{error:"Not found"});return}try{let a=ne(s);rmSync(s,{recursive:!0,force:!0}),x(e,200,{deleted:n,freedBytes:a});}catch(a){x(e,500,{error:a instanceof Error?a.message:String(a)});}}function Ft(t,e,r){x(e,200,{status:"shutting_down"}),r.close();}function Me(t,e,r){if(!existsSync(r)){x(e,404,{error:"File not found"});return}try{let n=readFileSync(r),s=extname(r).toLowerCase(),a=wn[s]??"application/octet-stream";e.writeHead(200,{"Content-Type":a}),e.end(n);}catch(n){x(e,500,{error:n instanceof Error?n.message:String(n)});}}var wn={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".webm":"video/webm",".mp4":"video/mp4",".json":"application/json",".html":"text/html",".css":"text/css",".js":"text/javascript",".svg":"image/svg+xml"};var Tn=9323,Sn=10,Rn=1800*1e3;function G(t,e){return new Promise((r,n)=>{let s=e?.port??Tn,a=Date.now(),o,i=0,l=existsSync(join(t,"artifacts"))?join(t,"artifacts"):existsSync(join(t,"..","artifacts"))?join(t,"..","artifacts"):join(t,"artifacts");function d(){clearTimeout(o),o=setTimeout(()=>{p.close();},Rn);}let c=e?.htmlPath??null;if(!c){let u=dirname(t);try{let g=readdirSync(u).find(h=>h.endsWith(".html"));g&&(c=join(u,g));}catch{}}let p=createServer((u,g)=>{if(d(),St(g),u.method==="OPTIONS"){g.writeHead(204),g.end();return}let h;try{h=new URL(u.url??"/",`http://${u.headers.host??"localhost"}`).pathname;}catch{x(g,400,{error:"Invalid URL"});return}if(u.method==="GET"&&(h==="/"||h==="/index.html")){if(c&&existsSync(c)){Me(u,g,c);return}x(g,404,{error:"HTML report not found"});return}if(u.method==="GET"&&h==="/api/health"){Rt(u,g,t,a);return}if(u.method==="GET"&&h==="/api/summary"){At(u,g,t);return}if(u.method==="GET"&&h==="/api/tests"){_t(u,g,t);return}if(u.method==="GET"&&h==="/api/files"){Nt(u,g,t);return}let m=h.match(/^\/api\/tests\/([a-f0-9]+)\/(network|console|api-calls)$/);if(u.method==="GET"&&m){Lt(u,g,t,m[1],m[2]);return}let b=h.match(/^\/api\/tests\/([a-f0-9]+)$/);if(u.method==="GET"&&b){It(u,g,t,b[1]);return}if(u.method==="GET"&&h==="/api/artifacts"){Mt(u,g,l);return}if(u.method==="DELETE"&&h==="/api/artifacts"){Et(u,g,l);return}let C=h.match(/^\/api\/artifacts\/(.+)$/);if(u.method==="DELETE"&&C){Pt(u,g,l,decodeURIComponent(C[1]));return}if(u.method==="GET"&&h.startsWith("/artifacts/")){let w=decodeURIComponent(h.slice(11));if(w.includes("..")||w.includes("\0")){x(g,400,{error:"Invalid path"});return}Me(u,g,join(l,w));return}if(u.method==="POST"&&h==="/api/shutdown"){Ft(u,g,p);return}x(g,404,{error:"Not found"});});function f(u){let g=h=>{h.code==="EADDRINUSE"&&i<Sn?(i++,f(u+1)):n(h);};p.once("error",g),p.listen(u,"127.0.0.1",()=>{p.removeListener("error",g);let h=p.address();if(!h||typeof h=="string"){n(new Error("Failed to get server address"));return}d(),r({port:h.port,dispose:()=>new Promise(m=>{clearTimeout(o),p.close(()=>m());})});});}f(s);})}async function Dt(t){let e=await G(t);return {port:e.port,dispose:e.dispose}}function In(t,e,r){let n=JSON.stringify(t),s=r?JSON.stringify(r):null;return vt(n,e,s)}async function Pe(t,e,r){try{let n=null,s=null,a=e.reportMode==="streaming"||e.reportMode==="auto"&&t.timeline.length===0&&t.summary.total>=e.streamingThreshold,o,i=e.htmlReportPath,l=dirname(i);mkdirSync(l,{recursive:!0});let d="",c="[]",p=null;if(a){d=JSON.stringify(t.summary);let u=dirname(e.outputPath),g=join(u,".testrelic-report");try{let h=join(g,"index-compact.json"),m=join(g,"index.json");existsSync(h)?c=readFileSync(h,"utf-8"):existsSync(m)&&(c=readFileSync(m,"utf-8"));}catch{}p=r?JSON.stringify(r):null,o=Ie(d,c,null,p);}else o=In(t,null,r);let f=i+".tmp";if(writeFileSync(f,o,"utf-8"),renameSync(f,i),a){if(t.ci===null){let u=dirname(e.outputPath),g=join(u,".testrelic-report"),h=resolve(i);try{if(await Nn(),n=await Mn(g),!n){s=await G(g,{htmlPath:h}),n=s.port;let m=setInterval(()=>{},6e4),b=()=>{clearInterval(m),s?.dispose();};process.on("SIGINT",b),process.on("SIGTERM",b),setTimeout(b,1800*1e3).unref();}if(n){process.stderr.write(`
|
|
2482
2482
|
Report server: http://127.0.0.1:${n}
|
|
2483
2483
|
`);try{let m=Ie(d,c,n,p),b=i+".tmp";writeFileSync(b,m,"utf-8"),renameSync(b,i);}catch{}}}catch{}}}else if(e.openReport&&t.ci===null&&e.includeArtifacts){let u=dirname(e.outputPath),g=join(u,"artifacts");if(existsSync(g))try{let h=await Dt(g);n=h.port,process.on("exit",()=>{h.dispose();});}catch{}}if(e.openReport&&t.ci===null)if(a&&n)Le(`http://127.0.0.1:${n}`);else {let u=resolve(i);Le(u);}}catch(n){process.stderr.write(`[testrelic] Failed to write HTML report: ${n instanceof Error?n.message:String(n)}
|
|
2484
2484
|
`);}}var ie=9323,Ut=10;async function Ln(){for(let t=ie;t<ie+Ut;t++)try{let e=new AbortController,r=setTimeout(()=>e.abort(),500),n=await fetch(`http://127.0.0.1:${t}/api/health`,{signal:e.signal});if(clearTimeout(r),n.ok)return t}catch{}return null}async function Nn(){for(let t=ie;t<ie+Ut;t++)try{let e=new AbortController,r=setTimeout(()=>e.abort(),1e3);await fetch(`http://127.0.0.1:${t}/api/shutdown`,{method:"POST",signal:e.signal}),clearTimeout(r);}catch{}await new Promise(t=>setTimeout(t,300));}async function Mn(t){let r=[join(__dirname,"cli.cjs"),join(__dirname,"cli.js"),join(__dirname,"..","dist","cli.cjs"),join(__dirname,"..","dist","cli.js")].find(n=>existsSync(n));if(!r){let n=await G(t);return process.on("exit",()=>{n?.dispose();}),n.port}return new Promise(n=>{let s=spawn(process.execPath,[r,"serve",t],{detached:true,stdio:["ignore","ignore","pipe"],env:{...process.env}}),a="",o=false,i=setTimeout(()=>{o||(o=true,s.stderr?.removeAllListeners(),Ln().then(n));},5e3);s.stderr?.on("data",l=>{a+=l.toString();let d=a.match(/127\.0\.0\.1:(\d+)/);d&&!o&&(o=true,clearTimeout(i),s.stderr?.removeAllListeners(),s.unref(),n(Number(d[1])));}),s.on("error",()=>{o||(o=true,clearTimeout(i),n(null));}),s.on("exit",()=>{o||(o=true,clearTimeout(i),n(null));}),s.unref();})}var Fn=20,Fe=0,De=[];async function jt(t,e){Fe>=Fn&&await new Promise(r=>De.push(r)),Fe++;try{return await copyFile(t,e),!0}catch{return false}finally{Fe--,De.length>0&&De.shift()();}}var K=[];async function zt(){K.length!==0&&(await Promise.allSettled(K),K.length=0);}function Vt(t){let e=new Date,r=a=>String(a).padStart(2,"0"),n=`${e.getFullYear()}-${r(e.getMonth()+1)}-${r(e.getDate())}T${r(e.getHours())}-${r(e.getMinutes())}-${r(e.getSeconds())}`;if(!existsSync(join(t,n)))return n;let s=1;for(;existsSync(join(t,`${n}-${s}`));)s++;return `${n}-${s}`}function Dn(t){let e=t.replace(/[^a-zA-Z0-9\-_ ]/g,"-").replace(/\s+/g,"-").replace(/-{2,}/g,"-").replace(/^-+|-+$/g,"");return e.length>100&&(e=e.substring(0,100).replace(/-+$/,"")),e||"unnamed-test"}function Wt(t,e,r,n,s){let a=t.find(f=>f.name==="screenshot"&&f.path),o=t.find(f=>f.name==="video"&&f.path);if(!a&&!o)return null;let i=Dn(e);r>0&&(i+=`--retry-${r}`);let l=s?["artifacts",s,i]:["artifacts",i],d=join(n,...l),c=l,p={};try{mkdirSync(d,{recursive:!0});}catch{return null}if(a?.path&&existsSync(a.path)){let u=`screenshot${extname(a.path)||".png"}`,g=join(d,u);K.push(jt(a.path,g).then(()=>{})),p.screenshot=`${c.join("/")}/${u}`;}if(o?.path&&existsSync(o.path)){let u=`video${extname(o.path)||".webm"}`,g=join(d,u);K.push(jt(o.path,g).then(()=>{})),p.video=`${c.join("/")}/${u}`;}return !p.screenshot&&!p.video?null:p}var qn=/^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}(-\d+)?$/,Hn="1.0";function Un(t){let e=extname(t).toLowerCase();return [".png",".jpg",".jpeg",".gif",".bmp",".webp"].includes(e)?"screenshot":[".webm",".mp4",".avi",".mov"].includes(e)?"video":"other"}function Gt(t,e,r){let n=[];try{let s=readdirSync(t,{withFileTypes:!0});for(let a of s){if(!a.isFile())continue;let o=join(t,a.name),i=statSync(o);n.push({name:a.name,type:Un(a.name),relativePath:`artifacts/${e}/${r}/${a.name}`,sizeBytes:i.size});}}catch{}return {testName:r,files:n}}function $n(t,e){let r=join(t,e),n=[],s=0;try{let o=readdirSync(r,{withFileTypes:!0});for(let i of o){if(!i.isDirectory())continue;let l=Gt(join(r,i.name),e,i.name);n.push(l);for(let d of l.files)s+=d.sizeBytes;}}catch{}let a=e.replace(/^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})/,"$1T$2:$3:$4").replace(/-\d+$/,"");return n.sort((o,i)=>o.testName.localeCompare(i.testName)),{folderName:e,timestamp:a,totalSizeBytes:s,testCount:n.length,tests:n,isCurrentRun:false}}function Jt(t,e){let r=join(t,"artifacts"),n=[],s=[],a=0;try{let i=readdirSync(r,{withFileTypes:!0});for(let l of i)if(l.isDirectory())if(qn.test(l.name)){let d=$n(r,l.name);n.push({...d,isCurrentRun:l.name===e});}else {let d=Gt(join(r,l.name),l.name,l.name);s.push(d);for(let c of d.files)a+=c.sizeBytes;}}catch{}n.sort((i,l)=>l.timestamp.localeCompare(i.timestamp)),s.length>0&&(s.sort((i,l)=>i.testName.localeCompare(l.testName)),n.push({folderName:"__legacy__",timestamp:"1970-01-01T00:00:00",totalSizeBytes:a,testCount:s.length,tests:s,isCurrentRun:false}));let o=n.reduce((i,l)=>i+l.totalSizeBytes,0);return {schemaVersion:Hn,generatedAt:new Date().toISOString(),artifactBaseDir:"artifacts",totalSizeBytes:o,runs:n,serverPort:null}}function Gn(t){let e=t,{root:r}=parse(e);for(;e!==r;){if(existsSync(join(e,".git")))return e;e=join(e,"..");}return null}function Yt(t){try{let e=Gn(t);if(!e)return;let r=join(e,".gitignore"),n=relative(e,t).replace(/\\/g,"/"),s=n.endsWith("/")?n:`${n}/`;if(existsSync(r)&&readFileSync(r,"utf-8").split(`
|