@testrelic/playwright-analytics 2.4.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4,7 +4,7 @@
4
4
  `),s}catch{}let a=path.dirname(t);if(a===t)break;t=a;}return null}function we(e){try{let t=fs$1.readFileSync(e,"utf-8"),r=JSON.parse(t);return typeof r!="object"||r===null||Array.isArray(r)||!xe(r)?null:r}catch{return null}}function xe(e){for(let t of Object.keys(e)){if(an.has(t))return false;let r=e[t];if(typeof r=="object"&&r!==null&&!Array.isArray(r)&&!xe(r))return false}return true}function ke(e){let t=/^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(e);if(t)return process.env[t[1]]??null;let r=/^\$([A-Za-z_][A-Za-z0-9_]*)$/.exec(e);return r?process.env[r[1]]??null:e}function Ct(e){let t=Object.create(null);for(let r of Object.keys(e)){let n=e[r];typeof n=="string"&&n.startsWith("$")?t[r]=ke(n):typeof n=="object"&&n!==null&&!Array.isArray(n)?t[r]=Ct(n):t[r]=n;}return t}function ve(e){let t=/^(\d+)\s*([smhd])$/.exec(e.trim());if(!t)return null;let r=parseInt(t[1],10),n=t[2],s=on[n];return !s||r<=0?null:r*s}function Ce(e,t){let r=Object.create(null);if(Object.assign(r,me),e){let l=e.cloud;l&&typeof l=="object"&&(typeof l.endpoint=="string"&&(r.endpoint=l.endpoint),typeof l.upload=="string"&&(r.uploadStrategy=l.upload),typeof l.timeout=="number"&&(r.timeout=l.timeout),typeof l.apiKey=="string"&&l.apiKey.length>0&&(r.apiKey=l.apiKey));let d=e["testrelic-repo"]??e.project;d&&typeof d=="object"&&typeof d.name=="string"&&(r.projectName=d.name),e.project&&!e["testrelic-repo"]&&process.stderr.write(`[testrelic] Deprecation: "project" key in config is deprecated. Rename it to "testrelic-repo".
5
5
  `);let c=e.queue;if(c&&typeof c=="object"){if(typeof c.maxAge=="string"){let p=ve(c.maxAge);p!==null&&(r.queueMaxAge=p);}typeof c.directory=="string"&&(r.queueDirectory=c.directory);}}if(t){if(typeof t.apiKey=="string"&&t.apiKey.length>0){let l=t.apiKey.startsWith("$")?ke(t.apiKey):t.apiKey;l&&(r.apiKey=l);}if(typeof t.endpoint=="string"&&(r.endpoint=t.endpoint),typeof t.upload=="string"&&(r.uploadStrategy=t.upload),typeof t.timeout=="number"&&(r.timeout=t.timeout),typeof t.projectName=="string"&&(r.projectName=t.projectName),typeof t.queueMaxAge=="string"){let l=ve(t.queueMaxAge);l!==null&&(r.queueMaxAge=l);}typeof t.queueDirectory=="string"&&(r.queueDirectory=t.queueDirectory),typeof t.uploadArtifacts=="boolean"&&(r.uploadArtifacts=t.uploadArtifacts),typeof t.artifactMaxSizeMb=="number"&&(r.artifactMaxSizeMb=t.artifactMaxSizeMb);}let n=process.env.TESTRELIC_API_KEY;n&&n.length>0&&(r.apiKey=n);let s=process.env.TESTRELIC_CLOUD_ENDPOINT;s&&core.isValidEndpointUrl(s)&&(r.endpoint=s);let a=process.env.TESTRELIC_UPLOAD_STRATEGY;a&&["batch","realtime","both"].includes(a)&&(r.uploadStrategy=a);let o=process.env.TESTRELIC_CLOUD_TIMEOUT;if(o){let l=parseInt(o,10);!isNaN(l)&&l>=1e3&&l<=12e4&&(r.timeout=l);}let i=Object.freeze(r);return core.isValidCloudConfig(i)?i:me}var un=[/AKIA[A-Z0-9]{16}/g,/Bearer\s+[A-Za-z0-9\-._~+/]+=*/g,/-----BEGIN\s+(RSA\s+)?PRIVATE\sKEY-----[\s\S]*?-----END/g,/\/\/[^:]+:[^@]+@/g],pn=["authorization","cookie","set-cookie","x-api-key"],fn=["password","secret","token","apiKey","api_key"];function Te(e){let t=Object.create(null);return t.trackApiCalls=e?.trackApiCalls??true,t.captureRequestHeaders=e?.captureRequestHeaders??true,t.captureResponseHeaders=e?.captureResponseHeaders??true,t.captureRequestBody=e?.captureRequestBody??true,t.captureResponseBody=e?.captureResponseBody??true,t.captureAssertions=e?.captureAssertions??true,t.redactHeaders=e?.redactHeaders??[...pn],t.redactBodyFields=e?.redactBodyFields??[...fn],t.apiIncludeUrls=e?.apiIncludeUrls??[],t.apiExcludeUrls=e?.apiExcludeUrls??[],Object.freeze(t)}function Se(e){if(e!==void 0&&!core.isValidConfig(e))throw core.createError(core.ErrorCode.CONFIG_INVALID,"Invalid reporter configuration");let t=Object.create(null);t.outputPath=e?.outputPath??"./test-results/analytics-timeline.json",t.includeStackTrace=e?.includeStackTrace??false,t.includeCodeSnippets=e?.includeCodeSnippets??true,t.codeContextLines=e?.codeContextLines??3,t.includeNetworkStats=e?.includeNetworkStats??true,t.navigationTypes=e?.navigationTypes??null,t.redactPatterns=[...un,...e?.redactPatterns??[]],t.testRunId=e?.testRunId??null,t.metadata=e?.metadata??null;let r=t.outputPath;t.openReport=e?.openReport??true,t.htmlReportPath=e?.htmlReportPath??r.replace(/\.json$/,".html"),t.includeArtifacts=e?.includeArtifacts??true,t.trackApiCalls=e?.trackApiCalls??true,t.quiet=e?.quiet??false,t.includeActionSteps=e?.includeActionSteps??true,t.captureConsoleLogs=e?.captureConsoleLogs??true;let n=be(process.cwd()),s=n?we(n):null,a=s?Ct(s):null,o=Ce(a,e?.cloud);return t.cloud=o.apiKey?o:null,t.reportMode=e?.reportMode??"streaming",t.streamingThreshold=e?.streamingThreshold??0,Object.freeze(t)}var et="1.3.0";function Re(e,t,r){try{let s=fs$1.readFileSync(e,"utf-8").split(`
6
6
  `);if(t<1||t>s.length)return null;let a=Math.max(1,t-r),o=Math.min(s.length,t+r),i=[];for(let l=a;l<=o;l++){let d=l===t?">":" ",c=String(l).padStart(String(o).length," ");i.push(`${d} ${c} | ${s[l-1]}`);}return i.join(`
7
- `)}catch{return null}}function Ae(e){return t=>{let r=t;for(let n of e)if(typeof n=="string"){let s=n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");r=r.replace(new RegExp(s,"g"),"[REDACTED]");}else {let s=n.flags.includes("g")?n.flags:n.flags+"g",a=new RegExp(n.source,s);r=r.replace(a,"[REDACTED]");}return r}}function hn(e){return e.GITHUB_ACTIONS!=="true"?null:{provider:"github-actions",buildId:e.GITHUB_RUN_ID??null,commitSha:e.GITHUB_SHA??null,branch:e.GITHUB_REF_NAME??null,runUrl:e.GITHUB_SERVER_URL&&e.GITHUB_REPOSITORY&&e.GITHUB_RUN_ID?`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`:null}}function mn(e){return e.GITLAB_CI!=="true"?null:{provider:"gitlab-ci",buildId:e.CI_PIPELINE_ID??null,commitSha:e.CI_COMMIT_SHA??null,branch:e.CI_COMMIT_BRANCH??e.CI_COMMIT_REF_NAME??null,runUrl:e.CI_PIPELINE_URL??null}}function vn(e){if(!e.JENKINS_URL)return null;let t=e.GIT_BRANCH??null;return t?.startsWith("origin/")&&(t=t.slice(7)),{provider:"jenkins",buildId:e.BUILD_ID??null,commitSha:e.GIT_COMMIT??null,branch:t,runUrl:e.BUILD_URL??null}}function yn(e){return e.CIRCLECI!=="true"?null:{provider:"circleci",buildId:e.CIRCLE_BUILD_NUM??null,commitSha:e.CIRCLE_SHA1??null,branch:e.CIRCLE_BRANCH??null,runUrl:e.CIRCLE_BUILD_URL??null}}function bn(e){if(!e.BITBUCKET_PIPELINE_UUID)return null;let t=e.BITBUCKET_WORKSPACE&&e.BITBUCKET_REPO_SLUG&&e.BITBUCKET_PIPELINE_UUID?`https://bitbucket.org/${e.BITBUCKET_WORKSPACE}/${e.BITBUCKET_REPO_SLUG}/pipelines/results/${e.BITBUCKET_PIPELINE_UUID}`:null;return {provider:"bitbucket-pipelines",buildId:e.BITBUCKET_BUILD_NUMBER??null,commitSha:e.BITBUCKET_COMMIT??null,branch:e.BITBUCKET_BRANCH??null,runUrl:t}}var wn=[hn,mn,vn,yn,bn];function D(e){let t=process.env;for(let r of wn){let n=r(t);if(n)return n}return null}var Tt=`
7
+ `)}catch{return null}}function Ae(e){return t=>{let r=t;for(let n of e)if(typeof n=="string"){let s=n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");r=r.replace(new RegExp(s,"g"),"[REDACTED]");}else {let s=n.flags.includes("g")?n.flags:n.flags+"g",a=new RegExp(n.source,s);r=r.replace(a,"[REDACTED]");}return r}}function hn(e){return e.GITHUB_ACTIONS!=="true"?null:{provider:"github-actions",buildId:e.GITHUB_RUN_ID??null,commitSha:e.GITHUB_SHA??null,branch:e.GITHUB_REF_NAME??null,runUrl:e.GITHUB_SERVER_URL&&e.GITHUB_REPOSITORY&&e.GITHUB_RUN_ID?`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`:null}}function mn(e){return e.GITLAB_CI!=="true"?null:{provider:"gitlab-ci",buildId:e.CI_PIPELINE_ID??null,commitSha:e.CI_COMMIT_SHA??null,branch:e.CI_COMMIT_BRANCH??e.CI_COMMIT_REF_NAME??null,runUrl:e.CI_PIPELINE_URL??null}}function vn(e){if(!e.JENKINS_URL)return null;let t=e.GIT_BRANCH??null;return t?.startsWith("origin/")&&(t=t.slice(7)),{provider:"jenkins",buildId:e.BUILD_ID??null,commitSha:e.GIT_COMMIT??null,branch:t,runUrl:e.BUILD_URL??null}}function yn(e){return e.CIRCLECI!=="true"?null:{provider:"circleci",buildId:e.CIRCLE_BUILD_NUM??null,commitSha:e.CIRCLE_SHA1??null,branch:e.CIRCLE_BRANCH??null,runUrl:e.CIRCLE_BUILD_URL??null}}function bn(e){if(!e.BITBUCKET_PIPELINE_UUID)return null;let t=e.BITBUCKET_WORKSPACE&&e.BITBUCKET_REPO_SLUG&&e.BITBUCKET_PIPELINE_UUID?`https://bitbucket.org/${e.BITBUCKET_WORKSPACE}/${e.BITBUCKET_REPO_SLUG}/pipelines/results/${e.BITBUCKET_PIPELINE_UUID}`:null;return {provider:"bitbucket-pipelines",buildId:e.BITBUCKET_BUILD_NUMBER??null,commitSha:e.BITBUCKET_COMMIT??null,branch:e.BITBUCKET_BRANCH??null,runUrl:t}}var wn=[hn,mn,vn,yn,bn];function B(e){let t=process.env;for(let r of wn){let n=r(t);if(n)return n}return null}var Tt=`
8
8
  /* Theme Variables */
9
9
  :root,[data-theme="dark"]{
10
10
  --bg:#0f1117;--bg-1:#161b22;--bg-2:#1c2128;--bg-3:#21262d;--bg-code:#13111c;
@@ -2556,8 +2556,8 @@ ${s}
2556
2556
  `}function Vt(e,t,r,n){if(n||e.total===0)return;let s=`\u250C${"\u2500".repeat(58)}\u2510
2557
2557
  `,a=`\u2514${"\u2500".repeat(58)}\u2518
2558
2558
  `,o=I(""),i=s;i+=I("TestRelic AI - Playwright Test Report"),i+=o;let l=[];if(e.passed>0&&l.push(`${e.passed} \u2713`),e.failed>0&&l.push(`${e.failed} \u2717`),e.flaky>0&&l.push(`${e.flaky} \u26A0`),e.skipped>0&&l.push(`${e.skipped} skipped`),e.timedout>0&&l.push(`${e.timedout} timedout`),i+=I(`Tests: ${e.total} total (${l.join(" ")})`),e.totalNavigations>0&&(i+=I(`Navigations: ${e.totalNavigations} visits across ${e.uniqueNavigationUrls} unique URLs`)),e.totalApiCalls>0){i+=I(`API Calls: ${e.totalApiCalls} calls across ${e.uniqueApiUrls} unique endpoints`);let d=Object.entries(e.apiCallsByMethod).filter(([,p])=>p>0).map(([p,f])=>`${p}: ${f}`);d.length>0&&(i+=I(` ${d.join(" ")}`));let c=Object.entries(e.apiCallsByStatusRange).filter(([,p])=>p>0).map(([p,f])=>`${p}: ${f}`);c.length>0&&(i+=I(` ${c.join(" ")}`)),e.apiResponseTime&&(i+=I(` Avg response: ${e.apiResponseTime.avg}ms P95: ${e.apiResponseTime.p95}ms`));}if(e.totalAssertions>0&&(i+=I(`Assertions: ${e.totalAssertions} total (${e.passedAssertions} \u2713 ${e.failedAssertions} \u2717)`)),e.totalActionSteps>0){let d=[],c=e.actionStepsByCategory;c.ui_action&&d.push(`${c.ui_action} UI`),c.assertion&&d.push(`${c.assertion} assertions`),c.custom_step&&d.push(`${c.custom_step} custom`);let p=d.length>0?` (${d.join(" ")})`:"";i+=I(`Actions: ${e.totalActionSteps} steps${p}`);}i+=I(`Report: ${r}`),i+=I(`Data: ${t}`),i+=a,i+=`For more information visit us at https://docs.testrelic.ai
2559
- `,process.stderr.write(i);}var ms=new Set(["pw:api","expect","test.step"]);function vs(e){return e==="expect"?"assertion":e==="test.step"?"custom_step":"ui_action"}function Gt(e,t,r){if(ms.has(e.category)){let n=[];for(let a of e.steps)Gt(a,t,n);let s=e.startTime.getTime()-t.getTime();r.push({title:e.title,category:vs(e.category),timestamp:e.startTime.toISOString(),duration:e.duration,videoOffset:s>=0?s/1e3:null,status:e.error?"failed":"passed",error:e.error?.message??null,children:n});}else for(let n of e.steps)Gt(n,t,r);}function pr(e,t){let r=[];for(let n of e)Gt(n,t,r);return r}var ws=new Set(["localhost","127.0.0.1","0.0.0.0"]);function gr(e){let t=new URL(e);if(t.protocol!=="https:"&&!(t.protocol==="http:"&&ws.has(t.hostname)))throw core.createError(core.ErrorCode.CLOUD_CONFIG_INVALID,`HTTPS is required for cloud communication. Got: ${t.protocol}//${t.hostname}`)}var xs=3e3;async function Wt(e){let t=new AbortController,r=setTimeout(()=>t.abort(),xs);try{return (await fetch(`${e}/health`,{method:"GET",signal:t.signal})).ok}catch{return false}finally{clearTimeout(r);}}async function hr(e){return new Promise(t=>setTimeout(t,e))}async function fr(e){try{let r=(await e.json()).error;if(r&&typeof r.message=="string"){let n=r.details;if(Array.isArray(n)&&n.length>0){let s=n.map(a=>`${a.field}: ${a.message}`).join(", ");return `${r.message} (${s})`}return r.message}}catch{}return `HTTP ${e.status}`}async function Jt(e,t,r){let n=new AbortController,s=setTimeout(()=>n.abort(),r);try{let a=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(a.ok){let i=await a.json();return {accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn,orgId:i.orgId,orgName:i.orgName,userId:i.userId,userName:i.userName}}if(a.status===429){let i=a.headers.get("Retry-After"),l=i?parseInt(i,10)*1e3:5e3;if(!isNaN(l)&&l>0){await hr(l);let d=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(d.ok){let c=await d.json();return {accessToken:c.accessToken,refreshToken:c.refreshToken,expiresIn:c.expiresIn,orgId:c.orgId,orgName:c.orgName,userId:c.userId,userName:c.userName}}}return {code:"rate_limited",message:"Rate limited during token exchange.",statusCode:429}}return a.status===400?{code:"validation_error",message:await fr(a),statusCode:400}:a.status===401?{code:"invalid_key",message:"API key is invalid or has been revoked.",statusCode:401}:a.status===403?{code:"expired_key",message:"API key has expired.",statusCode:403}:{code:"server_error",message:await fr(a),statusCode:a.status}}catch(a){return a instanceof DOMException&&a.name==="AbortError"?{code:"timeout",message:"Token exchange timed out.",statusCode:null}:{code:"network_error",message:"Failed to reach cloud for token exchange.",statusCode:null}}finally{clearTimeout(s);}}function Kt(e){return "code"in e&&typeof e.code=="string"&&["invalid_key","expired_key","validation_error","rate_limited","server_error","network_error","timeout"].includes(e.code)}async function mr(e,t,r){let n=new AbortController,s=setTimeout(()=>n.abort(),r);try{let a=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal});if(a.status===429){let i=a.headers.get("Retry-After"),l=i?parseInt(i,10)*1e3:5e3;!isNaN(l)&&l>0&&(await hr(l),a=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal}));}if(!a.ok)return null;let o=await a.json();return {accessToken:o.accessToken,refreshToken:o.refreshToken,expiresIn:o.expiresIn}}catch{return null}finally{clearTimeout(s);}}async function vr(e,t,r,n,s,a){let o=new AbortController,i=setTimeout(()=>o.abort(),s);try{let l={gitId:r,displayName:n};a&&(l.branch=a);let d=await fetch(`${e}/repos/resolve`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(l),signal:o.signal});if(!d.ok)return null;let c=await d.json();return {repoId:c.repoId,displayName:c.displayName}}catch{return null}finally{clearTimeout(i);}}var Rs=5e3;function O(e,t){try{return child_process.execSync(e,{cwd:t,timeout:Rs,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}function yr(e){let t=O("git rev-parse --abbrev-ref HEAD",e),r=O("git rev-parse --short HEAD",e),n=O("git log -1 --pretty=%s",e),s=As(e),a=s?Q(s):null;return {branch:t,commitSha:r,commitMessage:n,remoteUrl:a}}function As(e){let t=O("git remote get-url origin",e);if(t)return t;let r=O("git remote",e);if(!r)return null;let n=r.split(`
2560
- `)[0]?.trim();return n?O(`git remote get-url ${n}`,e):null}function Q(e){let t=e.trim();return t=t.replace(/^[a-z+]+:\/\//,""),t=t.replace(/^[^@]+@/,""),t=t.replace(/:(?!\d)/,"/"),t=t.replace(/\.git$/,""),t=t.replace(/\/+$/,""),t=t.replace(/^[^@/]+@/,""),t.toLowerCase()}function br(e){let t=e.split("/").filter(Boolean);return t[t.length-1]??e}function Yt(e){try{let t=fs$1.readFileSync(path.join(e,"package.json"),"utf-8"),r=JSON.parse(t);return typeof r.name=="string"&&r.name.length>0?r.name:null}catch{return null}}function X(e){let t=Yt(e);return t||`local/${path.basename(e)}`}var Es="1.0.0",wr=10;function tt(e,t,r,n,s,a,o,i){try{fs$1.mkdirSync(e,{recursive:!0});let l=Date.now(),d=`${l}-${t}-${r}.json`,c=path.join(e,d),p={version:Es,queuedAt:new Date(l).toISOString(),reason:n,retryCount:0,targetEndpoint:s,method:a,payload:o,headers:i},f=c+".tmp";fs$1.writeFileSync(f,JSON.stringify(p,null,2),"utf-8"),fs$1.renameSync(f,c);}catch(l){l.code==="ENOSPC"?process.stderr.write(`\u26A0 TestRelic: Disk full \u2014 unable to queue upload data.
2559
+ `,process.stderr.write(i);}var ms=new Set(["pw:api","expect","test.step"]);function vs(e){return e==="expect"?"assertion":e==="test.step"?"custom_step":"ui_action"}function Gt(e,t,r){if(ms.has(e.category)){let n=[];for(let a of e.steps)Gt(a,t,n);let s=e.startTime.getTime()-t.getTime();r.push({title:e.title,category:vs(e.category),timestamp:e.startTime.toISOString(),duration:e.duration,videoOffset:s>=0?s/1e3:null,status:e.error?"failed":"passed",error:e.error?.message??null,children:n});}else for(let n of e.steps)Gt(n,t,r);}function pr(e,t){let r=[];for(let n of e)Gt(n,t,r);return r}var ws=new Set(["localhost","127.0.0.1","0.0.0.0"]);function gr(e){let t=new URL(e);if(t.protocol!=="https:"&&!(t.protocol==="http:"&&ws.has(t.hostname)))throw core.createError(core.ErrorCode.CLOUD_CONFIG_INVALID,`HTTPS is required for cloud communication. Got: ${t.protocol}//${t.hostname}`)}var xs=3e3;async function Wt(e){let t=new AbortController,r=setTimeout(()=>t.abort(),xs);try{return (await fetch(`${e}/health`,{method:"GET",signal:t.signal})).ok}catch{return false}finally{clearTimeout(r);}}async function hr(e){return new Promise(t=>setTimeout(t,e))}async function fr(e){try{let r=(await e.json()).error;if(r&&typeof r.message=="string"){let n=r.details;if(Array.isArray(n)&&n.length>0){let s=n.map(a=>`${a.field}: ${a.message}`).join(", ");return `${r.message} (${s})`}return r.message}}catch{}return `HTTP ${e.status}`}async function Jt(e,t,r){let n=new AbortController,s=setTimeout(()=>n.abort(),r);try{let a=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(a.ok){let i=await a.json();return {accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn,orgId:i.orgId,orgName:i.orgName,userId:i.userId,userName:i.userName}}if(a.status===429){let i=a.headers.get("Retry-After"),l=i?parseInt(i,10)*1e3:5e3;if(!isNaN(l)&&l>0){await hr(l);let d=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(d.ok){let c=await d.json();return {accessToken:c.accessToken,refreshToken:c.refreshToken,expiresIn:c.expiresIn,orgId:c.orgId,orgName:c.orgName,userId:c.userId,userName:c.userName}}}return {code:"rate_limited",message:"Rate limited during token exchange.",statusCode:429}}return a.status===400?{code:"validation_error",message:await fr(a),statusCode:400}:a.status===401?{code:"invalid_key",message:"API key is invalid or has been revoked.",statusCode:401}:a.status===403?{code:"expired_key",message:"API key has expired.",statusCode:403}:{code:"server_error",message:await fr(a),statusCode:a.status}}catch(a){return a instanceof DOMException&&a.name==="AbortError"?{code:"timeout",message:"Token exchange timed out.",statusCode:null}:{code:"network_error",message:"Failed to reach cloud for token exchange.",statusCode:null}}finally{clearTimeout(s);}}function Kt(e){return "code"in e&&typeof e.code=="string"&&["invalid_key","expired_key","validation_error","rate_limited","server_error","network_error","timeout"].includes(e.code)}async function mr(e,t,r){let n=new AbortController,s=setTimeout(()=>n.abort(),r);try{let a=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal});if(a.status===429){let i=a.headers.get("Retry-After"),l=i?parseInt(i,10)*1e3:5e3;!isNaN(l)&&l>0&&(await hr(l),a=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal}));}if(!a.ok)return null;let o=await a.json();return {accessToken:o.accessToken,refreshToken:o.refreshToken,expiresIn:o.expiresIn}}catch{return null}finally{clearTimeout(s);}}async function vr(e,t,r,n,s,a){let o=new AbortController,i=setTimeout(()=>o.abort(),s);try{let l={gitId:r,displayName:n};a&&(l.branch=a);let d=await fetch(`${e}/repos/resolve`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(l),signal:o.signal});if(!d.ok)return null;let c=await d.json();return {repoId:c.repoId,displayName:c.displayName}}catch{return null}finally{clearTimeout(i);}}var Rs=5e3;function P(e,t){try{return child_process.execSync(e,{cwd:t,timeout:Rs,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}function yr(e){let t=P("git rev-parse --abbrev-ref HEAD",e),r=P("git rev-parse --short HEAD",e),n=P("git log -1 --pretty=%s",e),s=P("git log -1 --format=%an",e)??P("git config user.name",e),a=As(e),o=a?Q(a):null;return {branch:t,commitSha:r,commitMessage:n,commitAuthor:s,remoteUrl:o}}function As(e){let t=P("git remote get-url origin",e);if(t)return t;let r=P("git remote",e);if(!r)return null;let n=r.split(`
2560
+ `)[0]?.trim();return n?P(`git remote get-url ${n}`,e):null}function Q(e){let t=e.trim();return t=t.replace(/^[a-z+]+:\/\//,""),t=t.replace(/^[^@]+@/,""),t=t.replace(/:(?!\d)/,"/"),t=t.replace(/\.git$/,""),t=t.replace(/\/+$/,""),t=t.replace(/^[^@/]+@/,""),t.toLowerCase()}function br(e){let t=e.split("/").filter(Boolean);return t[t.length-1]??e}function Yt(e){try{let t=fs$1.readFileSync(path.join(e,"package.json"),"utf-8"),r=JSON.parse(t);return typeof r.name=="string"&&r.name.length>0?r.name:null}catch{return null}}function X(e){let t=Yt(e);return t||`local/${path.basename(e)}`}var Es="1.0.0",wr=10;function tt(e,t,r,n,s,a,o,i){try{fs$1.mkdirSync(e,{recursive:!0});let l=Date.now(),d=`${l}-${t}-${r}.json`,c=path.join(e,d),p={version:Es,queuedAt:new Date(l).toISOString(),reason:n,retryCount:0,targetEndpoint:s,method:a,payload:o,headers:i},f=c+".tmp";fs$1.writeFileSync(f,JSON.stringify(p,null,2),"utf-8"),fs$1.renameSync(f,c);}catch(l){l.code==="ENOSPC"?process.stderr.write(`\u26A0 TestRelic: Disk full \u2014 unable to queue upload data.
2561
2561
  `):process.stderr.write(`\u26A0 TestRelic: Unable to queue upload data.
2562
2562
  `);}}async function Cr(e,t,r){let n;try{n=fs$1.readdirSync(e).filter(a=>a.endsWith(".json")&&!a.endsWith(".tmp")).sort();}catch{return}if(n.length===0)return;let s=[];for(let a=0;a<n.length;a+=wr)s.push(n.slice(a,a+wr));for(let a of s)for(let o of a){let i=path.join(e,o);try{if(!fs$1.statSync(i).isFile())continue;let d=fs$1.readFileSync(i,"utf-8"),c=JSON.parse(d);if(!core.isValidQueueEntry(c)){process.stderr.write(`\u26A0 TestRelic: Corrupted queue file deleted: ${o}
2563
2563
  `),fs$1.unlinkSync(i);continue}let p=c;if((await fetch(p.targetEndpoint,{method:p.method,headers:{...p.headers,Authorization:`Bearer ${r}`},body:JSON.stringify(p.payload)})).ok)fs$1.unlinkSync(i);else return}catch{return}}}function Tr(e,t){try{let r=fs$1.readdirSync(e).filter(s=>s.endsWith(".json")&&!s.endsWith(".tmp")),n=Date.now();for(let s of r){let a=path.join(e,s);try{let o=fs$1.readFileSync(a,"utf-8"),l=JSON.parse(o).queuedAt;if(typeof l=="string"){let d=new Date(l).getTime();n-d>t&&fs$1.unlinkSync(a);}}catch{try{fs$1.unlinkSync(a);}catch{}}}}catch{}}var Hs=3e5,Us=864e5,zs=6e4,Sr=3e4,Xt="https://platform.testrelic.ai/settings/api-keys",ut=class{constructor(t){this.gitMetadata=null;this.repoId=null;this.failureReason=null;this.flushPromise=null;this.healthCheckTimer=null;this.config=t,this.authState={mode:"pending",accessToken:null,refreshToken:null,expiresAt:null,orgId:null,orgName:null,userId:null,userName:null};}async initialize(){if(!this.config||!this.config.apiKey){this.setLocalMode("no_api_key"),process.stderr.write(`\u2139 TestRelic: No API key configured. Running in local mode.
@@ -2576,12 +2576,12 @@ ${s}
2576
2576
  `);break;default:this.setLocalMode(`auth_error_${r??"unknown"}`),process.stderr.write(`\u26A0 TestRelic: Cloud authentication failed. Running in local mode.
2577
2577
  `);break}}async resolveRepoId(){if(!this.config||!this.authState.accessToken)return;let t=this.gitMetadata?.remoteUrl?Q(this.gitMetadata.remoteUrl):null,r=t?br(t):this.config.projectName??X(process.cwd()),n=t??this.config.projectName??X(process.cwd()),s=this.readRepoCache(n);if(s){this.repoId=s.repoId;return}try{let a=await vr(this.config.endpoint,this.authState.accessToken,n,r,this.config.timeout,this.gitMetadata?.branch);a&&(this.repoId=a.repoId,this.writeRepoCache(n,a.repoId,a.displayName));}catch{}!t&&!this.config.projectName&&!Yt(process.cwd())&&process.stderr.write(`\u2139 TestRelic: No git remote or package.json detected. Set project.name in .testrelic for stable project identity.
2578
2578
  `);}readRepoCache(t){if(!this.config)return null;let r=path.join(this.config.queueDirectory,"..","cache","repo.json");try{if(!fs$1.existsSync(r))return null;let n=fs$1.readFileSync(r,"utf-8"),s=JSON.parse(n);if(s.gitId!==t||Date.now()-s.resolvedAt>Us)return null;let a=this.hashApiKey();return a&&s.apiKeyHash!==a?null:s}catch{return null}}writeRepoCache(t,r,n){if(!this.config)return;let s=path.join(this.config.queueDirectory,"..","cache"),a=path.join(s,"repo.json");try{fs$1.mkdirSync(s,{recursive:!0});let o={repoId:r,gitId:t,displayName:n,resolvedAt:Date.now(),apiKeyHash:this.hashApiKey()??""},i=a+".tmp";fs$1.writeFileSync(i,JSON.stringify(o,null,2),"utf-8"),fs$1.renameSync(i,a);}catch{}}hashApiKey(){return this.config?.apiKey?crypto.createHash("sha256").update(this.config.apiKey).digest("hex").substring(0,16):null}startBackgroundFlush(){if(!this.config||!this.authState.accessToken)return;let t=this.authState.accessToken,r=this.config.queueDirectory,n=this.config.endpoint;this.flushPromise=Promise.race([Cr(r,n,t),new Promise(s=>setTimeout(s,Sr))]).catch(()=>{});}startHealthCheck(){if(!this.config)return;let t=this.config.endpoint;this.healthCheckTimer=setInterval(async()=>{if(!this.isCloudMode()&&!(!this.failureReason||!["cloud_unreachable","auth_timeout","network_error"].includes(this.failureReason)))try{if(!await Wt(t))return;if(this.config?.apiKey){let n=await Jt(this.config.endpoint,this.config.apiKey,this.config.timeout);if(!Kt(n)){let s=n;this.authState={mode:"cloud",accessToken:s.accessToken,refreshToken:s.refreshToken,expiresAt:Date.now()+s.expiresIn*1e3,orgId:s.orgId,orgName:s.orgName,userId:s.userId,userName:s.userName},this.failureReason=null,process.stderr.write(`\u2713 TestRelic: Cloud connectivity restored.
2579
- `),this.startBackgroundFlush();}}}catch{}},zs);}};var js=1048576,pt=[1e3,3e3,9e3],ft=3;function te(e,t,r,n,s){return {runId:e.testRunId,repoGitId:t,startedAt:e.startedAt,summary:e.summary,timeline:e.timeline,...{},...r?.branch?{branch:r.branch}:{},...r?.commitSha?{commit:r.commitSha}:{},...r?.commitMessage?{commitMessage:r.commitMessage}:{},...e.completedAt?{finishedAt:e.completedAt}:{},...e.totalDuration?{duration:e.totalDuration}:{},...n?.provider?{ciProvider:n.provider}:{},...n?.runUrl?{ciRunUrl:n.runUrl}:{}}}async function gt(e){return new Promise(t=>setTimeout(t,e))}function Vs(e){let t={};for(let[r,n]of Object.entries(e))n!=null&&(t[r]=n);return t}async function Rr(e,t,r){for(let n=0;n<ft;n++)try{let s=await fetch(e,t);if(s.ok)return s;if(s.status===401&&r&&n===0){let a=await r();if(a){let o={...t,headers:{...t.headers,Authorization:`Bearer ${a}`}},i=await fetch(e,o);if(i.ok)return i}return null}if(s.status===429&&n<ft-1){let a=s.headers.get("Retry-After"),o=a?parseInt(a,10)*1e3:pt[n];!isNaN(o)&&o>0?await gt(o):await gt(pt[n]);continue}if(s.status>=500&&n<ft-1){await gt(pt[n]);continue}return s}catch{if(n<ft-1){await gt(pt[n]);continue}return null}return null}function Gs(e){let t=JSON.stringify(e),r={"Content-Type":"application/json"};if(Buffer.byteLength(t,"utf-8")>js){let n=zlib.gzipSync(Buffer.from(t,"utf-8"));return r["Content-Encoding"]="gzip",{body:n,headers:r}}return {body:t,headers:r}}async function Ar(e,t,r,n){let s=`${e}/runs`,{body:a,headers:o}=Gs(r);o.Authorization=`Bearer ${t}`;let i=await Rr(s,{method:"POST",headers:o,body:a},n);return i?.ok?{success:true,statusCode:i.status,error:null}:i?.status===409?{success:true,statusCode:409,error:null}:{success:false,reason:i?`Upload failed with status ${i.status}`:"Upload failed after retries",statusCode:i?.status??null,payload:r,targetEndpoint:s,method:"POST"}}async function _r(e,t,r){let n=`${e}/runs/init`;try{let s=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(Vs(r))});return s.ok?{runId:(await s.json()).runId}:null}catch{return null}}function Ir(e,t,r,n){let s=`${e}/runs/${r}/tests`;fetch(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(n)}).catch(()=>{});}async function Lr(e,t,r,n){let s=`${e}/runs/${r}/finalize`;return (await Rr(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(n)}))?.ok??false}function ee(e,t,r,n){let s=`${e}/runs/${r}/finalize`,a=new Date,o={finishedAt:a.toISOString(),duration:a.getTime()-new Date(n).getTime(),summary:{}};fetch(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(o)}).catch(()=>{});}function Mr(e,t,r,n){let s=[],a=[],o=null,i=0,l=null,d=0,c=null,p=0,f=e.filter(h=>h.name===core.ATTACHMENT_NAME&&h.body),u=false;if(f.length>0)for(let h of f)try{let m=JSON.parse(h.body.toString());if(core.isTestRelicFilePayload(m)){s=s.concat(m.navigations),a=a.concat(m.apiAssertions),m.networkRequestsFile&&(o=m.networkRequestsFile,i+=m.networkRequestsCount),m.consoleLogsFile&&(l=m.consoleLogsFile,d+=m.consoleLogsCount),m.apiCallsFile&&(c=m.apiCallsFile,p+=m.apiCallsCount),u=!0;continue}if(core.isTestRelicDataPayload(m)){s=s.concat(m.navigations),Array.isArray(m.apiAssertions)&&(a=a.concat(m.apiAssertions)),i+=m.networkRequests?.length??0,p+=m.apiCalls?.length??0;let y=m.consoleLogs;Array.isArray(y)&&(d+=y.length),u=!0;}}catch{process.stderr.write(`[testrelic] Warning: Corrupt attachment for test "${r}"
2579
+ `),this.startBackgroundFlush();}}}catch{}},zs);}};var js=1048576,pt=[1e3,3e3,9e3],ft=3;function te(e,t,r,n,s){return {runId:e.testRunId,repoGitId:t,startedAt:e.startedAt,summary:e.summary,timeline:e.timeline,...{},...r?.branch?{branch:r.branch}:{},...r?.commitSha?{commit:r.commitSha}:{},...r?.commitMessage?{commitMessage:r.commitMessage}:{},...r?.commitAuthor?{commitAuthor:r.commitAuthor}:{},...e.completedAt?{finishedAt:e.completedAt}:{},...e.totalDuration?{duration:e.totalDuration}:{},...n?.provider?{ciProvider:n.provider}:{},...n?.runUrl?{ciRunUrl:n.runUrl}:{}}}async function gt(e){return new Promise(t=>setTimeout(t,e))}function Vs(e){let t={};for(let[r,n]of Object.entries(e))n!=null&&(t[r]=n);return t}async function Rr(e,t,r){for(let n=0;n<ft;n++)try{let s=await fetch(e,t);if(s.ok)return s;if(s.status===401&&r&&n===0){let a=await r();if(a){let o={...t,headers:{...t.headers,Authorization:`Bearer ${a}`}},i=await fetch(e,o);if(i.ok)return i}return null}if(s.status===429&&n<ft-1){let a=s.headers.get("Retry-After"),o=a?parseInt(a,10)*1e3:pt[n];!isNaN(o)&&o>0?await gt(o):await gt(pt[n]);continue}if(s.status>=500&&n<ft-1){await gt(pt[n]);continue}return s}catch{if(n<ft-1){await gt(pt[n]);continue}return null}return null}function Gs(e){let t=JSON.stringify(e),r={"Content-Type":"application/json"};if(Buffer.byteLength(t,"utf-8")>js){let n=zlib.gzipSync(Buffer.from(t,"utf-8"));return r["Content-Encoding"]="gzip",{body:n,headers:r}}return {body:t,headers:r}}async function Ar(e,t,r,n){let s=`${e}/runs`,{body:a,headers:o}=Gs(r);o.Authorization=`Bearer ${t}`;let i=await Rr(s,{method:"POST",headers:o,body:a},n);return i?.ok?{success:true,statusCode:i.status,error:null}:i?.status===409?{success:true,statusCode:409,error:null}:{success:false,reason:i?`Upload failed with status ${i.status}`:"Upload failed after retries",statusCode:i?.status??null,payload:r,targetEndpoint:s,method:"POST"}}async function _r(e,t,r){let n=`${e}/runs/init`;try{let s=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(Vs(r))});return s.ok?{runId:(await s.json()).runId}:null}catch{return null}}function Ir(e,t,r,n){let s=`${e}/runs/${r}/tests`;fetch(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(n)}).catch(()=>{});}async function Lr(e,t,r,n){let s=`${e}/runs/${r}/finalize`;return (await Rr(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(n)}))?.ok??false}function ee(e,t,r,n){let s=`${e}/runs/${r}/finalize`,a=new Date,o={finishedAt:a.toISOString(),duration:a.getTime()-new Date(n).getTime(),summary:{}};fetch(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(o)}).catch(()=>{});}function Mr(e,t,r,n){let s=[],a=[],o=null,i=0,l=null,d=0,c=null,p=0,f=e.filter(h=>h.name===core.ATTACHMENT_NAME&&h.body),u=false;if(f.length>0)for(let h of f)try{let m=JSON.parse(h.body.toString());if(core.isTestRelicFilePayload(m)){s=s.concat(m.navigations),a=a.concat(m.apiAssertions),m.networkRequestsFile&&(o=m.networkRequestsFile,i+=m.networkRequestsCount),m.consoleLogsFile&&(l=m.consoleLogsFile,d+=m.consoleLogsCount),m.apiCallsFile&&(c=m.apiCallsFile,p+=m.apiCallsCount),u=!0;continue}if(core.isTestRelicDataPayload(m)){s=s.concat(m.navigations),Array.isArray(m.apiAssertions)&&(a=a.concat(m.apiAssertions)),i+=m.networkRequests?.length??0,p+=m.apiCalls?.length??0;let y=m.consoleLogs;Array.isArray(y)&&(d+=y.length),u=!0;}}catch{process.stderr.write(`[testrelic] Warning: Corrupt attachment for test "${r}"
2580
2580
  `);}return u||(s=t.filter(h=>h.type==="lambdatest-navigation"&&h.description).map(h=>{try{return JSON.parse(h.description)}catch{return null}}).filter(h=>h!==null)),s.length===0&&i===0&&p===0&&!n&&!u&&process.stderr.write(`[testrelic] Warning: No data found for test "${r}". Make sure your tests import { test, expect } from '@testrelic/playwright-analytics/fixture' instead of '@playwright/test'. Without the TestRelic fixture, network logs, video sync, and timeline data cannot be captured.
2581
- `),{navigations:s,apiAssertions:a,networkRequestsFile:o,networkRequestsCount:i,consoleLogsFile:l,consoleLogsCount:d,apiCallsFile:c,apiCallsCount:p}}var ta=5,ht=[1e3,3e3,9e3],H=3,ea={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".webm":"video/webm",".mp4":"video/mp4",".zip":"application/zip"},re=0,ne=[];async function ra(){re>=ta&&await new Promise(e=>ne.push(e)),re++;}function na(){re--,ne.length>0&&ne.shift()();}async function mt(e){return new Promise(t=>setTimeout(t,e))}function sa(e){let t=e.substring(e.lastIndexOf(".")).toLowerCase();return ea[t]??"application/octet-stream"}function aa(e){try{return fs$1.statSync(e).size}catch{return 0}}async function ia(e,t,r,n,s){let a=`${e}/artifacts/upload-url`,o=JSON.stringify({runId:r.runId,testId:r.testId,fileName:path.basename(r.filePath),contentType:s,type:r.type,sizeBytes:n});for(let i=0;i<H;i++)try{let l=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:o});if(l.ok)return await l.json();if(l.status>=500&&i<H-1){await mt(ht[i]);continue}return null}catch{if(i<H-1){await mt(ht[i]);continue}return null}return null}async function oa(e,t,r,n){for(let s=0;s<H;s++)try{let a=fs$1.createReadStream(t),o=stream.Readable.toWeb(a),i=await fetch(e,{method:"PUT",headers:{"Content-Type":r,"Content-Length":String(n)},body:o,duplex:"half"});if(i.ok)return !0;if(i.status>=500&&s<H-1){await mt(ht[s]);continue}return !1}catch{if(s<H-1){await mt(ht[s]);continue}return false}return false}async function la(e,t,r){let n=`${e}/artifacts/confirm`;try{return (await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({artifactId:r})})).ok}catch{return false}}async function da(e,t,r,n){let s=aa(r.filePath);if(s===0)return {success:false,storageKey:null,artifactId:null,error:"file_not_found_or_empty"};if(s>n*1024*1024)return {success:false,storageKey:null,artifactId:null,error:"file_too_large"};let a=sa(r.filePath);await ra();try{let o=await ia(e,t,r,s,a);if(!o)return {success:!1,storageKey:null,artifactId:null,error:"upload_url_request_failed"};if(!await oa(o.uploadUrl,r.filePath,a,s))return {success:!1,storageKey:o.storageKey,artifactId:o.artifactId,error:"presigned_put_failed"};let l=await la(e,t,o.artifactId);return {success:l,storageKey:o.storageKey,artifactId:o.artifactId,error:l?null:"confirm_failed"}}finally{na();}}async function Nr(e,t,r,n){let s=new Map,a=r.map(async o=>{let i=await da(e,t,o,n);s.set(o.filePath,i);});return await Promise.allSettled(a),s}function se(e){let r=e.getGitMetadata()?.remoteUrl;return r?Q(r):e.getConfig()?.projectName??X(process.cwd())}async function Pr(e,t,r,n){if(!e.isCloudMode()||t!=="realtime"&&t!=="both"||!await e.ensureValidToken())return null;let a=e.getGitMetadata(),o=D();return (await _r(e.getEndpoint(),e.getAccessToken(),{runId:r,repoGitId:se(e),branch:a?.branch??null,commit:a?.commitSha??null,commitMessage:a?.commitMessage??null,startedAt:n,totalTests:null,ciProvider:o?.provider??null,ciRunUrl:o?.runUrl??null}))?.runId??null}async function ca(e,t,r,n){let s=new Map;if(!t.uploadArtifacts||!await e.ensureValidToken())return s;let o=[],i=new Map;for(let p of n){if(p.artifacts.screenshot){let f=path.join(p.outputDir,p.artifacts.screenshot);o.push({filePath:f,runId:r,testId:p.testId,type:"screenshot"}),i.set(f,{testId:p.testId,field:"screenshot"});}if(p.artifacts.video){let f=path.join(p.outputDir,p.artifacts.video);o.push({filePath:f,runId:r,testId:p.testId,type:"video"}),i.set(f,{testId:p.testId,field:"video"});}}if(o.length===0)return s;let l=await Nr(e.getEndpoint(),e.getAccessToken(),o,t.artifactMaxSizeMb),d=new Map;for(let[p,f]of l){if(!f.success||!f.storageKey)continue;let u=i.get(p);if(!u)continue;let g=d.get(u.testId)??{};u.field==="screenshot"&&(g.screenshotKey=f.storageKey),u.field==="video"&&(g.videoKey=f.storageKey),d.set(u.testId,g);}for(let p of n){let f=d.get(p.testId);s.set(p.testId,{...p.artifacts,...f?.screenshotKey?{screenshotKey:f.screenshotKey}:{},...f?.videoKey?{videoKey:f.videoKey}:{}});}let c=Array.from(l.values()).filter(p=>p.success).length;return c>0&&process.stderr.write(`\u2713 TestRelic: Uploaded ${c} artifact(s) to cloud storage.
2582
- `),s}async function ae(e,t,r,n,s,a,o,i,l,d){try{if(e.isCloudMode()&&s&&(r==="realtime"||r==="both")){let p=await e.ensureValidToken(),f=e.getGitMetadata(),u={finishedAt:o,duration:i,summary:l,...f?.commitMessage?{commitMessage:f.commitMessage}:{}};if(p){if(!await Lr(e.getEndpoint(),e.getAccessToken(),s,u)){let h=t?.queueDirectory??".testrelic/queue";tt(h,n,"finalize","finalize_failed_after_retries",`${e.getEndpoint()}/runs/${s}/finalize`,"POST",u,{"Content-Type":"application/json"});}}else {let g=t?.queueDirectory??".testrelic/queue";tt(g,n,"finalize",e.getFailureReason()??"token_invalid",`${e.getEndpoint()}/runs/${s}/finalize`,"POST",u,{"Content-Type":"application/json"});}}let c=new Map;if(e.isCloudMode()&&t&&d&&d.length>0&&(c=await ca(e,t,n,d)),e.isCloudMode()&&(!r||r==="batch"||r==="both"))if(await e.ensureValidToken()){let f=e.getGitMetadata(),u=D(),g=se(e),h=ua(a,c),m=te(h,g,f,u),y=await Ar(e.getEndpoint(),e.getAccessToken(),m,async()=>await e.ensureValidToken()?e.getAccessToken():null);if(!y.success){let k=y,w=t?.queueDirectory??".testrelic/queue";tt(w,n,"batch",k.reason,k.targetEndpoint,k.method,k.payload,{"Content-Type":"application/json"});}}else {let f=t?.queueDirectory??".testrelic/queue",u=e.getGitMetadata(),g=D(),h=se(e),m=te(a,h,u,g);tt(f,n,"batch",e.getFailureReason()??"token_invalid",`${e.getEndpoint()}/runs`,"POST",m,{"Content-Type":"application/json"});}await e.dispose();}catch{try{await e.dispose();}catch{}}}function ua(e,t){if(t.size===0)return e;let r=e.timeline.map(n=>{let s=n.testId;if(!s)return n;let a=t.get(s);return a?{...n,...a.screenshotKey?{screenshotKey:a.screenshotKey}:{},...a.videoKey?{videoKey:a.videoKey}:{}}:n});return {...e,timeline:r}}function vt(e){try{return fs$1.readFileSync(e,"utf-8").split(`
2581
+ `),{navigations:s,apiAssertions:a,networkRequestsFile:o,networkRequestsCount:i,consoleLogsFile:l,consoleLogsCount:d,apiCallsFile:c,apiCallsCount:p}}var ta=5,ht=[1e3,3e3,9e3],H=3,ea={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".webm":"video/webm",".mp4":"video/mp4",".zip":"application/zip"},re=0,ne=[];async function ra(){re>=ta&&await new Promise(e=>ne.push(e)),re++;}function na(){re--,ne.length>0&&ne.shift()();}async function mt(e){return new Promise(t=>setTimeout(t,e))}function sa(e){let t=e.substring(e.lastIndexOf(".")).toLowerCase();return ea[t]??"application/octet-stream"}function aa(e){try{return fs$1.statSync(e).size}catch{return 0}}async function ia(e,t,r,n,s){let a=`${e}/artifacts/upload-url`,o=JSON.stringify({runId:r.runId,testId:r.testId,fileName:path.basename(r.filePath),contentType:s,type:r.type,sizeBytes:n});for(let i=0;i<H;i++)try{let l=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:o});if(l.ok)return await l.json();if(l.status>=500&&i<H-1){await mt(ht[i]);continue}return null}catch{if(i<H-1){await mt(ht[i]);continue}return null}return null}async function oa(e,t,r,n){for(let s=0;s<H;s++)try{let a=fs$1.createReadStream(t),o=stream.Readable.toWeb(a),i=await fetch(e,{method:"PUT",headers:{"Content-Type":r,"Content-Length":String(n)},body:o,duplex:"half"});if(i.ok)return !0;if(i.status>=500&&s<H-1){await mt(ht[s]);continue}return !1}catch{if(s<H-1){await mt(ht[s]);continue}return false}return false}async function la(e,t,r){let n=`${e}/artifacts/confirm`;try{return (await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({artifactId:r})})).ok}catch{return false}}async function da(e,t,r,n){let s=aa(r.filePath);if(s===0)return {success:false,storageKey:null,artifactId:null,error:"file_not_found_or_empty"};if(s>n*1024*1024)return {success:false,storageKey:null,artifactId:null,error:"file_too_large"};let a=sa(r.filePath);await ra();try{let o=await ia(e,t,r,s,a);if(!o)return {success:!1,storageKey:null,artifactId:null,error:"upload_url_request_failed"};if(!await oa(o.uploadUrl,r.filePath,a,s))return {success:!1,storageKey:o.storageKey,artifactId:o.artifactId,error:"presigned_put_failed"};let l=await la(e,t,o.artifactId);return {success:l,storageKey:o.storageKey,artifactId:o.artifactId,error:l?null:"confirm_failed"}}finally{na();}}async function Nr(e,t,r,n){let s=new Map,a=r.map(async o=>{let i=await da(e,t,o,n);s.set(o.filePath,i);});return await Promise.allSettled(a),s}function se(e){let r=e.getGitMetadata()?.remoteUrl;return r?Q(r):e.getConfig()?.projectName??X(process.cwd())}async function Pr(e,t,r,n){if(!e.isCloudMode()||t!=="realtime"&&t!=="both"||!await e.ensureValidToken())return null;let a=e.getGitMetadata(),o=B();return (await _r(e.getEndpoint(),e.getAccessToken(),{runId:r,repoGitId:se(e),branch:a?.branch??null,commit:a?.commitSha??null,commitMessage:a?.commitMessage??null,commitAuthor:a?.commitAuthor??null,startedAt:n,totalTests:null,ciProvider:o?.provider??null,ciRunUrl:o?.runUrl??null}))?.runId??null}async function ca(e,t,r,n){let s=new Map;if(!t.uploadArtifacts||!await e.ensureValidToken())return s;let o=[],i=new Map;for(let p of n){if(p.artifacts.screenshot){let f=path.join(p.outputDir,p.artifacts.screenshot);o.push({filePath:f,runId:r,testId:p.testId,type:"screenshot"}),i.set(f,{testId:p.testId,field:"screenshot"});}if(p.artifacts.video){let f=path.join(p.outputDir,p.artifacts.video);o.push({filePath:f,runId:r,testId:p.testId,type:"video"}),i.set(f,{testId:p.testId,field:"video"});}}if(o.length===0)return s;let l=await Nr(e.getEndpoint(),e.getAccessToken(),o,t.artifactMaxSizeMb),d=new Map;for(let[p,f]of l){if(!f.success||!f.storageKey)continue;let u=i.get(p);if(!u)continue;let g=d.get(u.testId)??{};u.field==="screenshot"&&(g.screenshotKey=f.storageKey),u.field==="video"&&(g.videoKey=f.storageKey),d.set(u.testId,g);}for(let p of n){let f=d.get(p.testId);s.set(p.testId,{...p.artifacts,...f?.screenshotKey?{screenshotKey:f.screenshotKey}:{},...f?.videoKey?{videoKey:f.videoKey}:{}});}let c=Array.from(l.values()).filter(p=>p.success).length;return c>0&&process.stderr.write(`\u2713 TestRelic: Uploaded ${c} artifact(s) to cloud storage.
2582
+ `),s}async function ae(e,t,r,n,s,a,o,i,l,d){try{if(e.isCloudMode()&&s&&(r==="realtime"||r==="both")){let p=await e.ensureValidToken(),f=e.getGitMetadata(),u={finishedAt:o,duration:i,summary:l,...f?.commitMessage?{commitMessage:f.commitMessage}:{}};if(p){if(!await Lr(e.getEndpoint(),e.getAccessToken(),s,u)){let h=t?.queueDirectory??".testrelic/queue";tt(h,n,"finalize","finalize_failed_after_retries",`${e.getEndpoint()}/runs/${s}/finalize`,"POST",u,{"Content-Type":"application/json"});}}else {let g=t?.queueDirectory??".testrelic/queue";tt(g,n,"finalize",e.getFailureReason()??"token_invalid",`${e.getEndpoint()}/runs/${s}/finalize`,"POST",u,{"Content-Type":"application/json"});}}let c=new Map;if(e.isCloudMode()&&t&&d&&d.length>0&&(c=await ca(e,t,n,d)),e.isCloudMode()&&(!r||r==="batch"||r==="both"))if(await e.ensureValidToken()){let f=e.getGitMetadata(),u=B(),g=se(e),h=ua(a,c),m=te(h,g,f,u),y=await Ar(e.getEndpoint(),e.getAccessToken(),m,async()=>await e.ensureValidToken()?e.getAccessToken():null);if(!y.success){let k=y,w=t?.queueDirectory??".testrelic/queue";tt(w,n,"batch",k.reason,k.targetEndpoint,k.method,k.payload,{"Content-Type":"application/json"});}}else {let f=t?.queueDirectory??".testrelic/queue",u=e.getGitMetadata(),g=B(),h=se(e),m=te(a,h,u,g);tt(f,n,"batch",e.getFailureReason()??"token_invalid",`${e.getEndpoint()}/runs`,"POST",m,{"Content-Type":"application/json"});}await e.dispose();}catch{try{await e.dispose();}catch{}}}function ua(e,t){if(t.size===0)return e;let r=e.timeline.map(n=>{let s=n.testId;if(!s)return n;let a=t.get(s);return a?{...n,...a.screenshotKey?{screenshotKey:a.screenshotKey}:{},...a.videoKey?{videoKey:a.videoKey}:{}}:n});return {...e,timeline:r}}function vt(e){try{return fs$1.readFileSync(e,"utf-8").split(`
2583
2583
  `).filter(r=>r.length>0).map(r=>{try{return JSON.parse(r)}catch{return null}}).filter(r=>r!==null)}catch{return []}}function oe(e){switch(e){case "passed":return "passed";case "failed":return "failed";case "timedOut":return "timedout";case "skipped":return "skipped";case "interrupted":return "failed";default:return "failed"}}function va(e,t,r){let n=`${e}::${t}::${r}`;return crypto.createHash("sha256").update(n).digest("hex").substring(0,16)}function ya(e){return e.length<=4?"":e[e.length-2]}function ba(e){let t=e.findIndex(r=>r.status==="passed");return t>0?`passed on retry ${t}`:null}function wa(e,t){let r=["e2e","api","unit"];for(let s of r)if(e.some(a=>a===`@${s}`||a===s))return s;let n=t.replace(/\\/g,"/");for(let s of r)if(n.includes(`/${s}/`))return s;return "unknown"}var xa="__testrelic_api_config";function ka(e){return JSON.stringify(e,(t,r)=>r instanceof RegExp?{__regexp:true,source:r.source,flags:r.flags}:r)}var yt=class{constructor(t){this.rootDir="";this.startedAt="";this.testRunId="";this.collectedTests=[];this.fixtureDataReceived=false;this.testCount=0;this.cloudClient=null;this.cloudRunId=null;this.runTimestamp="";this.pendingArtifactEntries=[];this.activeReportMode="embedded";this.streamingWriter=null;this.testIndex=[];this.summaryCounters={total:0,passed:0,failed:0,flaky:0,skipped:0,timedOut:0,interrupted:0,totalApiCalls:0,totalAssertions:0,totalNavigations:0,totalNetworkRequests:0,totalConsoleLogs:0,totalActionSteps:0};this.config=Se(t),this.apiConfig=Te(t);}async onBegin(t,r){try{if(this.rootDir=t.rootDir,this.startedAt=new Date().toISOString(),this.testRunId=this.config.testRunId??crypto.randomUUID(),this.config.reportMode==="auto"){let s=r.allTests().length;this.activeReportMode=s>=this.config.streamingThreshold?"streaming":"embedded";}else this.activeReportMode=this.config.reportMode;let n=r.allTests().length;if(process.stderr.write(`[testrelic] Report mode: ${this.activeReportMode} (${n} tests)
2584
- `),this.activeReportMode==="streaming"){let s=path.dirname(this.config.outputPath);this.streamingWriter=new W(s);let a=()=>{if(this.streamingWriter){try{this.streamingWriter.writeIndex(this.testIndex);let o={testRunId:this.testRunId??"",startedAt:this.startedAt,completedAt:new Date().toISOString(),totalDuration:Date.now()-new Date(this.startedAt).getTime(),...this.summaryCounters,metadata:null,reportMode:"streaming",files:[],enrichedSummary:null,validation:null,writeErrors:this.streamingWriter.getWriteErrors()};this.streamingWriter.writeSummary(o);}catch{}this.streamingWriter.dispose();}try{if(this.cloudClient?.isCloudMode()&&this.cloudRunId){let o=this.cloudClient.getAccessToken();o&&ee(this.cloudClient.getEndpoint(),o,this.cloudRunId,this.startedAt);}}catch{}};process.on("SIGTERM",a),process.on("SIGINT",a);}if(this.config.includeArtifacts){let s=path.dirname(this.config.outputPath);this.runTimestamp=rr(path.join(s,"artifacts"));try{or(path.join(s,"artifacts"));}catch{}}try{this.cloudClient=new ut(this.config.cloud),await this.cloudClient.initialize(),this.cloudRunId=await Pr(this.cloudClient,this.config.cloud?.uploadStrategy,this.testRunId,this.startedAt);}catch{this.cloudClient?.switchToLocalMode("init_error");}if(this.activeReportMode!=="streaming"){let s=()=>{try{if(this.cloudClient?.isCloudMode()&&this.cloudRunId){let a=this.cloudClient.getAccessToken();a&&ee(this.cloudClient.getEndpoint(),a,this.cloudRunId,this.startedAt);}}catch{}};process.on("SIGTERM",s),process.on("SIGINT",s);}}catch{}}onTestBegin(t,r){try{t.annotations.push({type:xa,description:ka(this.apiConfig)});}catch{}}onTestEnd(t,r){try{let n=r,s=t.outcome(),a;s==="flaky"?a="flaky":s==="skipped"?a="skipped":a=oe(n.status);let o=n.startTime.toISOString(),i=new Date(n.startTime.getTime()+n.duration).toISOString(),l=t.tags?[...t.tags]:t.annotations.filter(S=>S.type==="tag").map(S=>S.description??""),d=Mr(n.attachments,t.annotations,t.title,a==="skipped");(d.navigations.length>0||d.networkRequestsCount>0||d.apiCallsCount>0)&&(this.fixtureDataReceived=!0);let c=null;if(a==="failed"||a==="flaky"){let R=(a==="flaky"?t.results.find(F=>F.status!=="passed")?.errors??[]:n.errors)[0];if(R){let F=Ae(this.config.redactPatterns),j=R.location?.line??null,V=null;this.config.includeCodeSnippets&&j!==null&&R.location?.file&&(V=Re(R.location.file,j,this.config.codeContextLines),V&&(V=F(V))),c={message:F(R.message??"Unknown error"),line:j,code:V,stack:this.config.includeStackTrace&&R.stack?F(R.stack):null};}}let p=t.titlePath().filter(Boolean),f=path.relative(this.rootDir||".",t.location.file),u=ya(p),g=p.join(" > "),h=f,m=va(h,u,g),y=wa(l,h),k=s==="flaky",w=ba(t.results),b=oe(t.expectedStatus),T=oe(n.status),v=null;if(this.config.includeArtifacts&&a!=="skipped"&&n.attachments){let S=path.dirname(this.config.outputPath),R=p[p.length-1]??t.title;v=nr(n.attachments,R,n.retry,S,this.runTimestamp||void 0);}let C=this.config.includeActionSteps&&n.steps?pr(n.steps,n.startTime):null,A={titlePath:p,title:g,status:a,duration:n.duration,startedAt:o,completedAt:i,retryCount:t.results.length-1,retry:n.retry,tags:l,failure:c,specFile:f,navigations:d.navigations,testId:m,filePath:h,suiteName:u,testType:y,isFlaky:k,retryStatus:w,expectedStatus:b,actualStatus:T,artifacts:v,apiAssertions:d.apiAssertions,actions:C,networkRequestsFile:d.networkRequestsFile,networkRequestsCount:d.networkRequestsCount,consoleLogsFile:d.consoleLogsFile,consoleLogsCount:d.consoleLogsCount,apiCallsFile:d.apiCallsFile,apiCallsCount:d.apiCallsCount};try{let S=this.config.cloud?.uploadStrategy;if(this.cloudClient?.isCloudMode()&&this.cloudRunId&&(S==="realtime"||S==="both")){let R=this.cloudClient.getAccessToken();R&&Ir(this.cloudClient.getEndpoint(),R,this.cloudRunId,this.buildCloudTestPayload(A));}}catch{}if(this.activeReportMode==="streaming"&&this.streamingWriter){let S=kt(h,p,t.id??"",n.retry),R=n.retry===t.results.length-1,F={id:S,navigations:d.navigations,apiAssertions:d.apiAssertions,actions:C??[],artifacts:v,failureDiagnostic:c,hasNetworkFile:d.networkRequestsFile!==null,networkRequestsCount:d.networkRequestsCount,hasConsoleFile:d.consoleLogsFile!==null,consoleLogsCount:d.consoleLogsCount,hasApiCallsFile:d.apiCallsFile!==null,apiCallsCount:d.apiCallsCount,startedAt:o};this.streamingWriter.writeTestDetail(S,F,{networkRequestsFile:d.networkRequestsFile,consoleLogsFile:d.consoleLogsFile,apiCallsFile:d.apiCallsFile});let j={id:S,title:p[p.length-1]??t.title,titlePath:p,filePath:h,status:a,duration:n.duration,project:p[1]??"",retryIndex:n.retry,tags:l,hasNetworkData:d.networkRequestsCount>0,hasConsoleData:d.consoleLogsCount>0,hasArtifacts:v!==null,hasActionSteps:(C?.length??0)>0,errorMessage:c?.message?.split(`
2584
+ `),this.activeReportMode==="streaming"){let s=path.dirname(this.config.outputPath);this.streamingWriter=new W(s);let a=()=>{if(this.streamingWriter){try{this.streamingWriter.writeIndex(this.testIndex);let o={testRunId:this.testRunId??"",startedAt:this.startedAt,completedAt:new Date().toISOString(),totalDuration:Date.now()-new Date(this.startedAt).getTime(),...this.summaryCounters,metadata:null,reportMode:"streaming",files:[],enrichedSummary:null,validation:null,writeErrors:this.streamingWriter.getWriteErrors()};this.streamingWriter.writeSummary(o);}catch{}this.streamingWriter.dispose();}try{if(this.cloudClient?.isCloudMode()&&this.cloudRunId){let o=this.cloudClient.getAccessToken();o&&ee(this.cloudClient.getEndpoint(),o,this.cloudRunId,this.startedAt);}}catch{}};process.on("SIGTERM",a),process.on("SIGINT",a);}if(this.config.includeArtifacts){let s=path.dirname(this.config.outputPath);this.runTimestamp=rr(path.join(s,"artifacts"));try{or(path.join(s,"artifacts"));}catch{}}try{this.cloudClient=new ut(this.config.cloud),await this.cloudClient.initialize(),this.cloudRunId=await Pr(this.cloudClient,this.config.cloud?.uploadStrategy,this.testRunId,this.startedAt);}catch{this.cloudClient?.switchToLocalMode("init_error");}if(this.activeReportMode!=="streaming"){let s=()=>{try{if(this.cloudClient?.isCloudMode()&&this.cloudRunId){let a=this.cloudClient.getAccessToken();a&&ee(this.cloudClient.getEndpoint(),a,this.cloudRunId,this.startedAt);}}catch{}};process.on("SIGTERM",s),process.on("SIGINT",s);}}catch{}}onTestBegin(t,r){try{t.annotations.push({type:xa,description:ka(this.apiConfig)});}catch{}}onTestEnd(t,r){try{let n=r,s=t.outcome(),a;s==="flaky"?a="flaky":s==="skipped"?a="skipped":a=oe(n.status);let o=n.startTime.toISOString(),i=new Date(n.startTime.getTime()+n.duration).toISOString(),l=t.tags?[...t.tags]:t.annotations.filter(S=>S.type==="tag").map(S=>S.description??""),d=Mr(n.attachments,t.annotations,t.title,a==="skipped");(d.navigations.length>0||d.networkRequestsCount>0||d.apiCallsCount>0)&&(this.fixtureDataReceived=!0);let c=null;if(a==="failed"||a==="flaky"){let R=(a==="flaky"?t.results.find(D=>D.status!=="passed")?.errors??[]:n.errors)[0];if(R){let D=Ae(this.config.redactPatterns),j=R.location?.line??null,V=null;this.config.includeCodeSnippets&&j!==null&&R.location?.file&&(V=Re(R.location.file,j,this.config.codeContextLines),V&&(V=D(V))),c={message:D(R.message??"Unknown error"),line:j,code:V,stack:this.config.includeStackTrace&&R.stack?D(R.stack):null};}}let p=t.titlePath().filter(Boolean),f=path.relative(this.rootDir||".",t.location.file),u=ya(p),g=p.join(" > "),h=f,m=va(h,u,g),y=wa(l,h),k=s==="flaky",w=ba(t.results),b=oe(t.expectedStatus),T=oe(n.status),v=null;if(this.config.includeArtifacts&&a!=="skipped"&&n.attachments){let S=path.dirname(this.config.outputPath),R=p[p.length-1]??t.title;v=nr(n.attachments,R,n.retry,S,this.runTimestamp||void 0);}let C=this.config.includeActionSteps&&n.steps?pr(n.steps,n.startTime):null,A={titlePath:p,title:g,status:a,duration:n.duration,startedAt:o,completedAt:i,retryCount:t.results.length-1,retry:n.retry,tags:l,failure:c,specFile:f,navigations:d.navigations,testId:m,filePath:h,suiteName:u,testType:y,isFlaky:k,retryStatus:w,expectedStatus:b,actualStatus:T,artifacts:v,apiAssertions:d.apiAssertions,actions:C,networkRequestsFile:d.networkRequestsFile,networkRequestsCount:d.networkRequestsCount,consoleLogsFile:d.consoleLogsFile,consoleLogsCount:d.consoleLogsCount,apiCallsFile:d.apiCallsFile,apiCallsCount:d.apiCallsCount};try{let S=this.config.cloud?.uploadStrategy;if(this.cloudClient?.isCloudMode()&&this.cloudRunId&&(S==="realtime"||S==="both")){let R=this.cloudClient.getAccessToken();R&&Ir(this.cloudClient.getEndpoint(),R,this.cloudRunId,this.buildCloudTestPayload(A));}}catch{}if(this.activeReportMode==="streaming"&&this.streamingWriter){let S=kt(h,p,t.id??"",n.retry),R=n.retry===t.results.length-1,D={id:S,navigations:d.navigations,apiAssertions:d.apiAssertions,actions:C??[],artifacts:v,failureDiagnostic:c,hasNetworkFile:d.networkRequestsFile!==null,networkRequestsCount:d.networkRequestsCount,hasConsoleFile:d.consoleLogsFile!==null,consoleLogsCount:d.consoleLogsCount,hasApiCallsFile:d.apiCallsFile!==null,apiCallsCount:d.apiCallsCount,startedAt:o};this.streamingWriter.writeTestDetail(S,D,{networkRequestsFile:d.networkRequestsFile,consoleLogsFile:d.consoleLogsFile,apiCallsFile:d.apiCallsFile});let j={id:S,title:p[p.length-1]??t.title,titlePath:p,filePath:h,status:a,duration:n.duration,project:p[1]??"",retryIndex:n.retry,tags:l,hasNetworkData:d.networkRequestsCount>0,hasConsoleData:d.consoleLogsCount>0,hasArtifacts:v!==null,hasActionSteps:(C?.length??0)>0,errorMessage:c?.message?.split(`
2585
2585
  `)[0]??null,networkCount:d.networkRequestsCount,consoleCount:d.consoleLogsCount,actionCount:C?.length??0,isRetry:!R};if(this.testIndex.push(j),R)switch(this.summaryCounters.total++,a){case "passed":this.summaryCounters.passed++;break;case "failed":this.summaryCounters.failed++;break;case "flaky":this.summaryCounters.flaky++;break;case "skipped":this.summaryCounters.skipped++;break;case "timedout":this.summaryCounters.timedOut++;break;default:this.summaryCounters.interrupted++;break}this.summaryCounters.totalApiCalls+=d.apiCallsCount,this.summaryCounters.totalAssertions+=d.apiAssertions.length,this.summaryCounters.totalNavigations+=d.navigations.length,this.summaryCounters.totalNetworkRequests+=d.networkRequestsCount,this.summaryCounters.totalConsoleLogs+=d.consoleLogsCount,this.summaryCounters.totalActionSteps+=C?.length??0,v&&this.pendingArtifactEntries.push({testId:m,artifacts:v,outputDir:path.dirname(this.config.outputPath)}),A.actions=null,A.apiAssertions=null,A.navigations=[],A.artifacts=null,A.failure=null,A.networkRequestsFile=null,A.consoleLogsFile=null,A.apiCallsFile=null;}this.activeReportMode!=="streaming"&&this.collectedTests.push(A),this.testCount++,this.checkMemoryPressure();}catch{}}async onEnd(t){try{let r=new Date().toISOString(),n=new Date(this.startedAt).getTime(),a=new Date(r).getTime()-n,o=this.activeReportMode==="streaming"?this.testIndex.some(l=>l.status!=="skipped"):this.collectedTests.some(l=>l.status!=="skipped");!this.fixtureDataReceived&&o&&process.stderr.write(`
2586
2586
  \u26A0 TestRelic: No fixture data received from any test.
2587
2587
  To enable network logs, video sync, and timeline tracking, import the TestRelic fixture:
@@ -2589,12 +2589,12 @@ ${s}
2589
2589
  instead of:
2590
2590
  import { test, expect } from '@playwright/test';
2591
2591
 
2592
- `),await er();let i=null;if(this.config.includeArtifacts&&this.runTimestamp)try{let l=path.dirname(this.config.outputPath);i=ar(l,this.runTimestamp);let d=path.join(l,"artifact-manifest.json"),c=JSON.stringify(i),p=d+".tmp";fs$1.writeFileSync(p,c,"utf-8"),fs$1.renameSync(p,d);}catch{}if(this.activeReportMode==="streaming"&&this.streamingWriter)await this.finalizeStreamingReport(r,a,t,i);else {let l=this.buildTimeline(),d=new Map;for(let u of this.collectedTests){let g=d.get(u.testId);(!g||u.retry>g.retry)&&d.set(u.testId,u);}let c=Array.from(d.values()),p=ur(c,l.length),f={schemaVersion:et,testRunId:this.testRunId,startedAt:this.startedAt,completedAt:r,totalDuration:a,summary:p,ci:D(),metadata:this.config.metadata,timeline:l,shardRunIds:null};if(this.writeReport(f),await Ot(f,this.config,i),Vt(p,this.config.outputPath,this.config.htmlReportPath,this.config.quiet),this.cloudClient){let u=this.collectArtifactEntries();await ae(this.cloudClient,this.config.cloud,this.config.cloud?.uploadStrategy,this.testRunId,this.cloudRunId,f,r,a,p,u);}}}catch{}}collectArtifactEntries(){if(this.activeReportMode==="streaming")return this.pendingArtifactEntries;let t=path.dirname(this.config.outputPath),r=[];for(let n of this.collectedTests)n.artifacts&&r.push({testId:n.testId,artifacts:n.artifacts,outputDir:t});return r}async finalizeStreamingReport(t,r,n,s){if(!this.streamingWriter)return;let{totalApiCalls:a,totalAssertions:o,totalNavigations:i,totalNetworkRequests:l,totalConsoleLogs:d,totalActionSteps:c}=this.summaryCounters;this.summaryCounters={total:0,passed:0,failed:0,flaky:0,skipped:0,timedOut:0,interrupted:0,totalApiCalls:a,totalAssertions:o,totalNavigations:i,totalNetworkRequests:l,totalConsoleLogs:d,totalActionSteps:c};let p=new Map,f=new Map;for(let b of this.testIndex){let T=`${b.filePath}::${b.titlePath.join(" > ")}`,v=p.get(T);(v===void 0||b.retryIndex>v)&&p.set(T,b.retryIndex);}let u=0;for(let b of this.testIndex){let T=`${b.filePath}::${b.titlePath.join(" > ")}`,v=p.get(T);if(b.isRetry=b.retryIndex<v,b.isRetry)continue;switch(u++,this.summaryCounters.total++,b.status){case "passed":this.summaryCounters.passed++;break;case "failed":this.summaryCounters.failed++;break;case "flaky":this.summaryCounters.flaky++;break;case "skipped":this.summaryCounters.skipped++;break;case "timedout":this.summaryCounters.timedOut++;break;default:this.summaryCounters.interrupted++;break}let C=f.get(b.filePath);switch(C||(C={filePath:b.filePath,total:0,passed:0,failed:0,flaky:0,skipped:0,timedOut:0},f.set(b.filePath,C)),C.total++,b.status){case "passed":C.passed++;break;case "failed":C.failed++;break;case "flaky":C.flaky++;break;case "skipped":C.skipped++;break;case "timedout":C.timedOut++;break}}let g=Array.from(f.values());this.streamingWriter.writeIndex(this.testIndex),this.streamingWriter.writeCompactIndex(this.testIndex);let h={reporterTotal:this.summaryCounters.total,indexTotal:u,playwrightStatus:n.status,isValid:this.summaryCounters.total===u};h.isValid||process.stderr.write(`[testrelic] WARNING: Summary count mismatch \u2014 reporter: ${h.reporterTotal}, index: ${h.indexTotal}
2592
+ `),await er();let i=null;if(this.config.includeArtifacts&&this.runTimestamp)try{let l=path.dirname(this.config.outputPath);i=ar(l,this.runTimestamp);let d=path.join(l,"artifact-manifest.json"),c=JSON.stringify(i),p=d+".tmp";fs$1.writeFileSync(p,c,"utf-8"),fs$1.renameSync(p,d);}catch{}if(this.activeReportMode==="streaming"&&this.streamingWriter)await this.finalizeStreamingReport(r,a,t,i);else {let l=this.buildTimeline(),d=new Map;for(let u of this.collectedTests){let g=d.get(u.testId);(!g||u.retry>g.retry)&&d.set(u.testId,u);}let c=Array.from(d.values()),p=ur(c,l.length),f={schemaVersion:et,testRunId:this.testRunId,startedAt:this.startedAt,completedAt:r,totalDuration:a,summary:p,ci:B(),metadata:this.config.metadata,timeline:l,shardRunIds:null};if(this.writeReport(f),await Ot(f,this.config,i),Vt(p,this.config.outputPath,this.config.htmlReportPath,this.config.quiet),this.cloudClient){let u=this.collectArtifactEntries();await ae(this.cloudClient,this.config.cloud,this.config.cloud?.uploadStrategy,this.testRunId,this.cloudRunId,f,r,a,p,u);}}}catch{}}collectArtifactEntries(){if(this.activeReportMode==="streaming")return this.pendingArtifactEntries;let t=path.dirname(this.config.outputPath),r=[];for(let n of this.collectedTests)n.artifacts&&r.push({testId:n.testId,artifacts:n.artifacts,outputDir:t});return r}async finalizeStreamingReport(t,r,n,s){if(!this.streamingWriter)return;let{totalApiCalls:a,totalAssertions:o,totalNavigations:i,totalNetworkRequests:l,totalConsoleLogs:d,totalActionSteps:c}=this.summaryCounters;this.summaryCounters={total:0,passed:0,failed:0,flaky:0,skipped:0,timedOut:0,interrupted:0,totalApiCalls:a,totalAssertions:o,totalNavigations:i,totalNetworkRequests:l,totalConsoleLogs:d,totalActionSteps:c};let p=new Map,f=new Map;for(let b of this.testIndex){let T=`${b.filePath}::${b.titlePath.join(" > ")}`,v=p.get(T);(v===void 0||b.retryIndex>v)&&p.set(T,b.retryIndex);}let u=0;for(let b of this.testIndex){let T=`${b.filePath}::${b.titlePath.join(" > ")}`,v=p.get(T);if(b.isRetry=b.retryIndex<v,b.isRetry)continue;switch(u++,this.summaryCounters.total++,b.status){case "passed":this.summaryCounters.passed++;break;case "failed":this.summaryCounters.failed++;break;case "flaky":this.summaryCounters.flaky++;break;case "skipped":this.summaryCounters.skipped++;break;case "timedout":this.summaryCounters.timedOut++;break;default:this.summaryCounters.interrupted++;break}let C=f.get(b.filePath);switch(C||(C={filePath:b.filePath,total:0,passed:0,failed:0,flaky:0,skipped:0,timedOut:0},f.set(b.filePath,C)),C.total++,b.status){case "passed":C.passed++;break;case "failed":C.failed++;break;case "flaky":C.flaky++;break;case "skipped":C.skipped++;break;case "timedout":C.timedOut++;break}}let g=Array.from(f.values());this.streamingWriter.writeIndex(this.testIndex),this.streamingWriter.writeCompactIndex(this.testIndex);let h={reporterTotal:this.summaryCounters.total,indexTotal:u,playwrightStatus:n.status,isValid:this.summaryCounters.total===u};h.isValid||process.stderr.write(`[testrelic] WARNING: Summary count mismatch \u2014 reporter: ${h.reporterTotal}, index: ${h.indexTotal}
2593
2593
  `);let m={total:this.summaryCounters.total,passed:this.summaryCounters.passed,failed:this.summaryCounters.failed,flaky:this.summaryCounters.flaky,skipped:this.summaryCounters.skipped,timedout:this.summaryCounters.timedOut,totalApiCalls:this.summaryCounters.totalApiCalls,uniqueApiUrls:0,apiCallsByMethod:{},apiCallsByStatusRange:{"2xx":0,"3xx":0,"4xx":0,"5xx":0,error:0},apiResponseTime:null,totalAssertions:this.summaryCounters.totalAssertions,passedAssertions:0,failedAssertions:0,totalNavigations:this.summaryCounters.totalNavigations,uniqueNavigationUrls:0,totalTimelineSteps:this.testIndex.length,totalActionSteps:this.summaryCounters.totalActionSteps,actionStepsByCategory:{}},y={testRunId:this.testRunId,startedAt:this.startedAt,completedAt:t,totalDuration:r,...this.summaryCounters,metadata:this.config.metadata,reportMode:"streaming",files:g,enrichedSummary:m,validation:h,writeErrors:this.streamingWriter.getWriteErrors()};this.streamingWriter.writeSummary(y);let k={schemaVersion:"2.0",generatedAt:new Date().toISOString(),reportMode:"streaming",summaryFile:"summary.json",indexFile:"index.json",testsDir:"tests",artifactsDir:"artifacts",testCount:this.testIndex.length,totalSizeBytes:this.streamingWriter.computeTotalSize()};this.streamingWriter.writeManifest(k),await Ot(this.buildStreamingReport(y,m,t,r),this.config,s),Vt(m,this.config.outputPath,this.config.htmlReportPath,this.config.quiet);let w=this.streamingWriter.getReportDir();if(process.stderr.write(`[testrelic] Streaming report written to ${w}
2594
2594
  [testrelic] ${this.testIndex.length} test detail files on disk
2595
2595
  [testrelic] View report: npx testrelic serve ${w}
2596
2596
  `),this.streamingWriter.getWriteErrors().length>0&&process.stderr.write(`[testrelic] WARNING: ${this.streamingWriter.getWriteErrors().length} write error(s) during streaming
2597
- `),this.streamingWriter.dispose(),this.cloudClient){let b=this.buildStreamingReport(y,m,t,r),T=this.collectArtifactEntries();await ae(this.cloudClient,this.config.cloud,this.config.cloud?.uploadStrategy,this.testRunId,this.cloudRunId,b,t,r,m,T);}this.testIndex.length=0,this.collectedTests.length=0,this.pendingArtifactEntries.length=0,this.streamingWriter=null,this.cloudClient=null;}buildStreamingReport(t,r,n,s){return {schemaVersion:et,testRunId:this.testRunId,startedAt:this.startedAt,completedAt:n,totalDuration:s,summary:r,ci:D(),metadata:this.config.metadata,timeline:[],shardRunIds:null}}printsToStdio(){return false}checkMemoryPressure(){try{let t=process.memoryUsage(),r=t.heapUsed/1024/1024;if(r<200)return;let n=t.heapUsed/t.heapTotal;n>.9&&this.activeReportMode==="embedded"?(process.stderr.write(`[testrelic] WARNING: High memory (${Math.round(r)} MB). Auto-switching to streaming mode.
2597
+ `),this.streamingWriter.dispose(),this.cloudClient){let b=this.buildStreamingReport(y,m,t,r),T=this.collectArtifactEntries();await ae(this.cloudClient,this.config.cloud,this.config.cloud?.uploadStrategy,this.testRunId,this.cloudRunId,b,t,r,m,T);}this.testIndex.length=0,this.collectedTests.length=0,this.pendingArtifactEntries.length=0,this.streamingWriter=null,this.cloudClient=null;}buildStreamingReport(t,r,n,s){return {schemaVersion:et,testRunId:this.testRunId,startedAt:this.startedAt,completedAt:n,totalDuration:s,summary:r,ci:B(),metadata:this.config.metadata,timeline:[],shardRunIds:null}}printsToStdio(){return false}checkMemoryPressure(){try{let t=process.memoryUsage(),r=t.heapUsed/1024/1024;if(r<200)return;let n=t.heapUsed/t.heapTotal;n>.9&&this.activeReportMode==="embedded"?(process.stderr.write(`[testrelic] WARNING: High memory (${Math.round(r)} MB). Auto-switching to streaming mode.
2598
2598
  `),this.switchToStreamingMode()):n>.8&&process.stderr.write(`[testrelic] WARNING: Memory pressure detected (${Math.round(r)} MB used).
2599
2599
  `);}catch{}}switchToStreamingMode(){try{if(this.activeReportMode==="streaming")return;this.activeReportMode="streaming";let t=path.dirname(this.config.outputPath);this.streamingWriter=new W(t);for(let r of this.collectedTests){let n=kt(r.filePath,r.titlePath,r.testId,r.retry),s={id:n,navigations:r.navigations??[],apiAssertions:r.apiAssertions??[],actions:r.actions??[],artifacts:r.artifacts,failureDiagnostic:r.failure,hasNetworkFile:r.networkRequestsFile!==null,networkRequestsCount:r.networkRequestsCount,hasConsoleFile:r.consoleLogsFile!==null,consoleLogsCount:r.consoleLogsCount,hasApiCallsFile:r.apiCallsFile!==null,apiCallsCount:r.apiCallsCount,startedAt:r.startedAt};this.streamingWriter.writeTestDetail(n,s,{networkRequestsFile:r.networkRequestsFile,consoleLogsFile:r.consoleLogsFile,apiCallsFile:r.apiCallsFile});let a={id:n,title:r.titlePath[r.titlePath.length-1]??r.title,titlePath:r.titlePath,filePath:r.filePath,status:r.status,duration:r.duration,project:r.titlePath[1]??"",retryIndex:r.retry,tags:r.tags,hasNetworkData:r.networkRequestsCount>0,hasConsoleData:r.consoleLogsCount>0,hasArtifacts:r.artifacts!==null,hasActionSteps:(r.actions?.length??0)>0,errorMessage:r.failure?.message?.split(`
2600
2600
  `)[0]??null,networkCount:r.networkRequestsCount,consoleCount:r.consoleLogsCount,actionCount:r.actions?.length??0,isRetry:!1};switch(this.testIndex.push(a),this.summaryCounters.total++,r.status){case "passed":this.summaryCounters.passed++;break;case "failed":this.summaryCounters.failed++;break;case "flaky":this.summaryCounters.flaky++;break;case "skipped":this.summaryCounters.skipped++;break;case "timedout":this.summaryCounters.timedOut++;break;default:this.summaryCounters.interrupted++;break}this.summaryCounters.totalApiCalls+=r.apiCallsCount,this.summaryCounters.totalAssertions+=r.apiAssertions?.length??0,this.summaryCounters.totalNavigations+=r.navigations?.length??0,this.summaryCounters.totalNetworkRequests+=r.networkRequestsCount,this.summaryCounters.totalConsoleLogs+=r.consoleLogsCount,this.summaryCounters.totalActionSteps+=r.actions?.length??0;}this.collectedTests.length=0;}catch{}}buildTimeline(){let t=this.collectedTests.map(r=>({titlePath:r.titlePath,title:r.title,status:r.status,duration:r.duration,startedAt:r.startedAt,completedAt:r.completedAt,retryCount:r.retryCount,retry:r.retry,tags:r.tags,failure:r.failure,specFile:r.specFile,navigations:r.navigations,apiCalls:null,apiAssertions:r.apiAssertions,testId:r.testId,filePath:r.filePath,suiteName:r.suiteName,testType:r.testType,isFlaky:r.isFlaky,retryStatus:r.retryStatus,expectedStatus:r.expectedStatus,actualStatus:r.actualStatus,artifacts:r.artifacts,networkRequests:null,actions:r.actions,consoleLogs:null}));return cr(t,{navigationTypes:this.config.navigationTypes})}readJsonlFile(t){if(!t)return null;let r=vt(t);return r.length>0?r:null}toTestResult(t,r){let n=null,s=null,a=null;return r?.loadFiles&&(n=this.readJsonlFile(t.networkRequestsFile),s=this.readJsonlFile(t.consoleLogsFile),a=this.readJsonlFile(t.apiCallsFile)),{title:t.title,status:t.status,duration:t.duration,startedAt:t.startedAt,completedAt:t.completedAt,retryCount:t.retryCount,tags:t.tags,failure:t.failure,testId:t.testId,filePath:t.filePath,suiteName:t.suiteName,testType:t.testType,isFlaky:t.isFlaky,retryStatus:t.retryStatus,expectedStatus:t.expectedStatus,actualStatus:t.actualStatus,artifacts:t.artifacts,networkRequests:n,apiCalls:a,apiAssertions:t.apiAssertions,actions:t.actions??null,consoleLogs:s}}buildCloudTestPayload(t){let r={title:t.title,status:t.status,duration:t.duration,startedAt:t.startedAt,completedAt:t.completedAt,retryCount:t.retryCount,tags:t.tags,failure:t.failure,testId:t.testId,filePath:t.filePath,suiteName:t.suiteName,testType:t.testType,isFlaky:t.isFlaky,retryStatus:t.retryStatus,expectedStatus:t.expectedStatus,actualStatus:t.actualStatus,artifacts:t.artifacts,apiAssertions:t.apiAssertions,actions:t.actions??[],navigations:t.navigations??[],steps:t.actions??[]};if(t.consoleLogsFile&&(r.consoleLogs=vt(t.consoleLogsFile)),t.networkRequestsFile&&(r.networkRequests=vt(t.networkRequestsFile)),t.apiCallsFile){let n=vt(t.apiCallsFile);r.apiCalls=n,(!r.networkRequests||r.networkRequests.length===0)&&(r.networkRequests=n.map(s=>{let a=s;return {method:a.method??"GET",url:a.url??"",status:a.responseStatusCode??0,statusCode:a.responseStatusCode??0,type:"xhr",size:typeof a.responseBody=="string"?a.responseBody.length:0,duration:a.responseTimeMs??0,responseTimeMs:a.responseTimeMs??0,requestHeaders:a.requestHeaders??null,responseHeaders:a.responseHeaders??null,requestBody:a.requestBody??null,responseBody:a.responseBody??null,timestamp:a.timestamp??new Date().toISOString(),startedAt:a.timestamp??new Date().toISOString()}}));}return r}writeReport(t){try{let r=JSON.stringify(t),n=this.config.outputPath,s=path.dirname(n);fs$1.mkdirSync(s,{recursive:!0});let a=n+".tmp";fs$1.writeFileSync(a,r,"utf-8"),fs$1.renameSync(a,n);}catch(r){process.stderr.write(`[testrelic] Failed to write report: ${r instanceof Error?r.message:String(r)}