@testrelic/playwright-analytics 2.3.2 → 2.3.3
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/api-fixture.cjs +2 -1
- package/dist/api-fixture.cjs.map +1 -1
- package/dist/api-fixture.js +2 -1
- package/dist/api-fixture.js.map +1 -1
- package/dist/cli.cjs +134 -42
- package/dist/fixture.cjs +2 -1
- package/dist/fixture.cjs.map +1 -1
- package/dist/fixture.js +2 -1
- package/dist/fixture.js.map +1 -1
- package/dist/index.cjs +149 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +149 -79
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
package/dist/api-fixture.cjs
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
'use strict';var perf_hooks=require('perf_hooks');require('fs');var core=require('@testrelic/core'),test=require('@playwright/test');var B=Symbol.for("__testrelic_call_id"),H="__testrelic_api_assertions",T=new WeakMap,C=class{constructor(){this.assertions=[];this.currentCallId=null;}recordAssertion(t){this.assertions.push(t);}getAssertions(){return this.assertions}setCurrentCallId(t){this.currentCallId=t;}getCurrentCallId(){return this.currentCallId}getData(){return [...this.assertions]}flushLegacyAnnotations(t){this.assertions.length!==0&&t.annotations.push({type:H,description:JSON.stringify(this.assertions)});}dispose(){this.assertions=[],this.currentCallId=null;}};var I="[REDACTED]";function S(r,t){if(r===null||t.length===0)return r;let e=new Set(t.map(s=>s.toLowerCase())),n={};for(let s of Object.keys(r))Object.hasOwn(r,s)&&(n[s]=e.has(s.toLowerCase())?I:r[s]);return n}function v(r,t){if(r===null||t.length===0)return r;let e;try{e=JSON.parse(r);}catch{return r}if(typeof e!="object"||e===null)return r;let n=new Set(t),s=b(e,n);return JSON.stringify(s)}function b(r,t){if(Array.isArray(r))return r.map(e=>b(e,t));if(typeof r=="object"&&r!==null){let e={};for(let n of Object.keys(r)){if(!Object.hasOwn(r,n))continue;let s=r[n];t.has(n)?e[n]=I:e[n]=b(s,t);}return e}return r}function L(r,t,e){if(e.length>0){for(let n of e)if(P(r,n))return false}if(t.length>0){for(let n of t)if(P(r,n))return true;return false}return true}function P(r,t){try{return t instanceof RegExp?t.test(r):j(t).test(r)}catch{return console.warn(`[testrelic] Invalid URL filter pattern: ${String(t)}`),false}}function j(r){let t="",e=0;for(;e<r.length;){let n=r[e];n==="*"&&r[e+1]==="*"?(t+=".*",e+=2,r[e]==="/"&&e++):n==="*"?(t+="[^/]*",e++):n==="?"?(t+="[^/]",e++):".+^${}()|[]\\".includes(n)?(t+="\\"+n,e++):(t+=n,e++);}return new RegExp(t)}var F=["get","post","put","patch","delete","head","fetch"],U=["text/","application/json","application/xml","application/javascript","application/x-www-form-urlencoded","application/graphql"],J="__testrelic_api_calls";function G(r){let t=r.toLowerCase();return U.some(e=>t.includes(e))}function W(r){if(!r)return null;if(r.data!==void 0&&r.data!==null){let t=r.data;return typeof t=="string"?t:Buffer.isBuffer(t)?t.toString("base64"):JSON.stringify(t)}if(r.form!==void 0&&r.form!==null)return JSON.stringify(r.form);if(r.multipart!==void 0&&r.multipart!==null){let t=r.multipart,e={};for(let[n,s]of Object.entries(t))typeof s=="string"||typeof s=="number"||typeof s=="boolean"?e[n]=String(s):s&&typeof s=="object"&&"name"in s?e[n]=`[file: ${s.name}]`:e[n]="[binary]";return JSON.stringify(e)}return null}var N=class N{constructor(t,e,n){this.originals=new Map;this.capturedCalls=[];this.callCounter=0;this.disposed=false;this._lastCallId=null;this.primitiveCallIds=new Map;this.context=t,this.assertionTracker=e??null,this.apiConfig=n??N.DEFAULT_API_CONFIG;}get lastCallId(){return this._lastCallId}getCallIdForValue(t){return t!=null&&typeof t=="object"?T.get(t)??null:this.primitiveCallIds.get(t)??null}intercept(){for(let e of F){let n=this.context[e].bind(this.context);this.originals.set(e,n),this.context[e]=this.createWrapper(e,n);}let t=this.context.dispose.bind(this.context);this.originals.set("dispose",t),this.context.dispose=async e=>(this.disposed=true,t(e));}getData(){return [...this.capturedCalls]}flushLegacyAnnotations(t){this.capturedCalls.length!==0&&t.annotations.push({type:J,description:JSON.stringify(this.capturedCalls)});}dispose(){for(let[t,e]of this.originals)this.context[t]=e;this.originals.clear(),this.capturedCalls=[],this.callCounter=0,this._lastCallId=null,this.primitiveCallIds.clear();}get isDisposed(){return this.disposed}getCapturedCalls(){return this.capturedCalls}tagResponseMethods(t,e){let n=this,s=t.headers.bind(t);t.headers=function(){let a=s();return T.set(a,e),a};let l=t.headersArray.bind(t);t.headersArray=function(){let a=l();return T.set(a,e),a};let d=t.json.bind(t);t.json=async function(){let a=await d();return a!=null&&typeof a=="object"&&T.set(a,e),a};let c=t.status.bind(t);t.status=function(){let a=c();return n.primitiveCallIds.set(a,e),a};let o=t.statusText.bind(t);t.statusText=function(){let a=o();return n.primitiveCallIds.set(a,e),a};let u=t.ok.bind(t);t.ok=function(){let a=u();return n.primitiveCallIds.set(a,e),a};let i=t.text.bind(t);t.text=async function(){let a=await i();return n.primitiveCallIds.set(a,e),a};let p=t.body.bind(t);t.body=async function(){let a=await p();return T.set(a,e),a};}createWrapper(t,e){let n=this;return async function(l,d){if(!L(l,n.apiConfig.apiIncludeUrls,n.apiConfig.apiExcludeUrls))return e(l,d);let c=`api-call-${n.callCounter++}`,o=new Date().toISOString(),u=t==="fetch"?(d?.method??"GET").toUpperCase():t.toUpperCase(),i=W(d),p=perf_hooks.performance.now();n._lastCallId=c,n.assertionTracker&&n.assertionTracker.setCurrentCallId(c);let g;try{g=await e(l,d);}catch(a){let k=perf_hooks.performance.now();try{let y=n.apiConfig.captureRequestBody?v(i,n.apiConfig.redactBodyFields):null,m={id:c,timestamp:o,method:u,url:l,requestHeaders:null,requestBody:y,responseStatusCode:null,responseStatusText:null,responseHeaders:null,responseBody:null,responseTimeMs:Math.round((k-p)*100)/100,isBinary:!1,error:a instanceof Error?a.message:String(a)};n.capturedCalls.push(m);}catch{}throw a}try{let a=perf_hooks.performance.now(),k=g.headers(),y=k["content-type"]??null,m=y?!G(y):!1,f=null;n.apiConfig.captureRequestHeaders&&d?.headers&&(f=d.headers);let h=null;n.apiConfig.captureResponseHeaders&&(h=k);let R=n.apiConfig.captureRequestBody?i:null,w=null;if(n.apiConfig.captureResponseBody)try{m?w=(await g.body()).toString("base64"):w=await g.text();}catch{}f=S(f,n.apiConfig.redactHeaders),h=S(h,n.apiConfig.redactHeaders),R=v(R,n.apiConfig.redactBodyFields),w=v(w,n.apiConfig.redactBodyFields);let M={id:c,timestamp:o,method:u,url:g.url(),requestHeaders:f,requestBody:R,responseStatusCode:g.status(),responseStatusText:g.statusText(),responseHeaders:h,responseBody:w,responseTimeMs:Math.round((a-p)*100)/100,isBinary:m,error:null};n.capturedCalls.push(M);}catch{}try{g[B]=c,n.tagResponseMethods(g,c);}catch{}return g}}};N.DEFAULT_API_CONFIG=Object.freeze({trackApiCalls:true,captureRequestHeaders:true,captureResponseHeaders:true,captureRequestBody:true,captureResponseBody:true,captureAssertions:true,redactHeaders:["authorization","cookie","set-cookie","x-api-key"],redactBodyFields:["password","secret","token","apiKey","api_key"],apiIncludeUrls:[],apiExcludeUrls:[]});var A=N;var Y=["text/","application/json","application/xml","application/javascript","application/x-www-form-urlencoded","application/graphql"];function $(r){let t=r.toLowerCase();return Y.some(e=>t.includes(e))}var q=class r{constructor(t,e){this.page=t;this.records=[];this.listeners=[];this.currentNetworkCounter=null;this.pendingRequests=new Map;this.capturedRequests=[];this.pendingBodyReads=[];this.requestIdCounter=0;this.consoleLogs=[];this.includeNetworkStats=e?.includeNetworkStats??true,this.origGoto=t.goto.bind(t),this.origGoBack=t.goBack.bind(t),this.origGoForward=t.goForward.bind(t),this.origReload=t.reload.bind(t),this.interceptMethods(),this.attachListeners();}async init(){await this.injectSPADetection();}async getCapturedRequests(){await Promise.allSettled(this.pendingBodyReads),this.pendingBodyReads=[];for(let[t,e]of this.pendingRequests)this.capturedRequests.push({url:e.url,method:e.method,resourceType:e.resourceType,statusCode:0,responseTimeMs:Date.now()-e.startTimeMs,startedAt:e.startedAt,requestHeaders:e.headers,requestBody:e.postData,responseBody:null,responseHeaders:null,contentType:null,responseSize:0,requestBodyTruncated:e.postDataTruncated,responseBodyTruncated:false,isBinary:false,error:"incomplete"}),this.pendingRequests.delete(t);return [...this.capturedRequests].sort((t,e)=>t.startedAt.localeCompare(e.startedAt))}static mapConsoleType(t){switch(t){case "log":return "log";case "warning":return "warn";case "error":return "error";case "info":return "info";case "debug":return "debug";default:return "log"}}async getData(){this.includeNetworkStats&&this.currentNetworkCounter&&this.records.length>0&&(this.records[this.records.length-1].networkStats={totalRequests:this.currentNetworkCounter.totalRequests,failedRequests:this.currentNetworkCounter.failedRequests,failedRequestUrls:[...this.currentNetworkCounter.failedRequestUrls],totalBytes:this.currentNetworkCounter.totalBytes,byType:{...this.currentNetworkCounter.byType}});let t=this.records.map(n=>({url:n.url,navigationType:n.navigationType,timestamp:n.timestamp,domContentLoadedAt:n.domContentLoadedAt,networkIdleAt:n.networkIdleAt,networkStats:n.networkStats})),e=this.includeNetworkStats?await this.getCapturedRequests():[];return {navigations:t,networkRequests:e,consoleLogs:[...this.consoleLogs]}}async flushLegacyAnnotations(t){this.includeNetworkStats&&this.currentNetworkCounter&&this.records.length>0&&(this.records[this.records.length-1].networkStats={totalRequests:this.currentNetworkCounter.totalRequests,failedRequests:this.currentNetworkCounter.failedRequests,failedRequestUrls:[...this.currentNetworkCounter.failedRequestUrls],totalBytes:this.currentNetworkCounter.totalBytes,byType:{...this.currentNetworkCounter.byType}});for(let e of this.records){let n={url:e.url,navigationType:e.navigationType,timestamp:e.timestamp,domContentLoadedAt:e.domContentLoadedAt,networkIdleAt:e.networkIdleAt,networkStats:e.networkStats};t.annotations.push({type:"lambdatest-navigation",description:JSON.stringify(n)});}if(this.includeNetworkStats){let e=await this.getCapturedRequests();e.length>0&&t.annotations.push({type:"__testrelic_network_requests",description:JSON.stringify(e)});}}dispose(){this.page.goto=this.origGoto,this.page.goBack=this.origGoBack,this.page.goForward=this.origGoForward,this.page.reload=this.origReload;for(let{event:t,handler:e}of this.listeners)this.page.off(t,e);this.listeners=[],this.records=[],this.pendingRequests.clear(),this.capturedRequests=[],this.pendingBodyReads=[];}getRecords(){return this.records}interceptMethods(){let t=this,e=this.page;e.goto=async function(n,s){return t.recordNavigation(n,"goto"),t.origGoto(n,s)},e.goBack=async function(n){let s=await t.origGoBack(n);return t.recordNavigation(e.url(),"back"),s},e.goForward=async function(n){let s=await t.origGoForward(n);return t.recordNavigation(e.url(),"forward"),s},e.reload=async function(n){return t.recordNavigation(e.url(),"refresh"),t.origReload(n)};}attachListeners(){let t=()=>{this.lastDomContentLoaded=new Date().toISOString(),this.records.length>0&&(this.records[this.records.length-1].domContentLoadedAt=this.lastDomContentLoaded);};this.page.on("domcontentloaded",t),this.listeners.push({event:"domcontentloaded",handler:t});let e=s=>{try{let l=s;if(typeof l.parentFrame=="function"&&l.parentFrame()!==null)return;let d=l.url(),c=this.records[this.records.length-1];if(c&&Date.now()-new Date(c.timestamp).getTime()<50&&c.url===d)return;this.recordNavigation(d,"navigation");}catch{}};this.page.on("framenavigated",e),this.listeners.push({event:"framenavigated",handler:e});let n=s=>{try{let l=s,d=l.type(),c=l.text();if(d==="debug"&&c.startsWith("__testrelic_nav:")){try{let o=JSON.parse(c.slice(16));o.type&&o.url&&this.recordNavigation(o.url,o.type);}catch{}return}{let o=null;try{let i=l.location();i&&i.url&&(o=`${i.url}:${i.lineNumber}:${i.columnNumber}`);}catch{}let u=r.mapConsoleType(d);this.consoleLogs.push({level:u,text:c,timestamp:new Date().toISOString(),location:o});}}catch{}};if(this.page.on("console",n),this.listeners.push({event:"console",handler:n}),this.includeNetworkStats){let s=c=>{this.currentNetworkCounter&&this.currentNetworkCounter.totalRequests++;try{let o=c,u=String(this.requestIdCounter++),i=o.postData()??null,p={url:o.url(),method:o.method(),resourceType:this.mapResourceType(o.resourceType()),headers:o.headers(),postData:i,postDataTruncated:!1,startedAt:new Date().toISOString(),startTimeMs:Date.now()};this.pendingRequests.set(u,p),c.__testrelic_id=u;}catch{}};this.page.on("request",s),this.listeners.push({event:"request",handler:s});let l=c=>{try{let o=c;if(this.currentNetworkCounter){let f=o.status();f>=400&&(this.currentNetworkCounter.failedRequests++,this.currentNetworkCounter.failedRequestUrls.push(f+" "+o.url()));let h=o.headers()["content-length"];h&&(this.currentNetworkCounter.totalBytes+=parseInt(h,10)||0);let R=o.request().resourceType(),w=this.mapResourceType(R);this.currentNetworkCounter.byType[w]++;}let u=o.request().__testrelic_id;if(!u)return;let i=this.pendingRequests.get(u);if(!i)return;this.pendingRequests.delete(u);let p=Date.now()-i.startTimeMs,g=o.headers(),a=g["content-type"]??null,k=parseInt(g["content-length"]??"0",10)||0,y=a?!$(a):!1,m=(async()=>{let f=null;if(!y)try{f=(await o.body()).toString("utf-8");}catch{}let h={url:i.url,method:i.method,resourceType:i.resourceType,statusCode:o.status(),responseTimeMs:p,startedAt:i.startedAt,requestHeaders:i.headers,requestBody:i.postData,responseBody:f,responseHeaders:g,contentType:a,responseSize:k,requestBodyTruncated:i.postDataTruncated,responseBodyTruncated:!1,isBinary:y,error:null};this.capturedRequests.push(h);})();this.pendingBodyReads.push(m);}catch{}};this.page.on("response",l),this.listeners.push({event:"response",handler:l});let d=c=>{if(this.currentNetworkCounter){this.currentNetworkCounter.failedRequests++;try{let o=c;this.currentNetworkCounter.failedRequestUrls.push("ERR "+o.url());}catch{}}try{let o=c,u=o.__testrelic_id;if(!u)return;let i=this.pendingRequests.get(u);if(!i)return;this.pendingRequests.delete(u);let p={url:i.url,method:i.method,resourceType:i.resourceType,statusCode:0,responseTimeMs:Date.now()-i.startTimeMs,startedAt:i.startedAt,requestHeaders:i.headers,requestBody:i.postData,responseBody:null,responseHeaders:null,contentType:null,responseSize:0,requestBodyTruncated:i.postDataTruncated,responseBodyTruncated:!1,isBinary:!1,error:o.failure()?.errorText??"Unknown error"};this.capturedRequests.push(p);}catch{}};this.page.on("requestfailed",d),this.listeners.push({event:"requestfailed",handler:d});}}async injectSPADetection(){try{await this.page.addInitScript(()=>{let t=history.pushState.bind(history),e=history.replaceState.bind(history);history.pushState=function(...n){t(...n),console.debug("__testrelic_nav:"+JSON.stringify({type:"spa_route",url:location.href}));},history.replaceState=function(...n){e(...n),console.debug("__testrelic_nav:"+JSON.stringify({type:"spa_replace",url:location.href}));},window.addEventListener("popstate",()=>{console.debug("__testrelic_nav:"+JSON.stringify({type:"popstate",url:location.href}));}),window.addEventListener("hashchange",()=>{console.debug("__testrelic_nav:"+JSON.stringify({type:"hash_change",url:location.href}));});});}catch{}}recordNavigation(t,e){this.includeNetworkStats&&this.currentNetworkCounter&&this.records.length>0&&(this.records[this.records.length-1].networkStats={totalRequests:this.currentNetworkCounter.totalRequests,failedRequests:this.currentNetworkCounter.failedRequests,failedRequestUrls:[...this.currentNetworkCounter.failedRequestUrls],totalBytes:this.currentNetworkCounter.totalBytes,byType:{...this.currentNetworkCounter.byType}}),this.records.push({url:t,navigationType:e,timestamp:new Date().toISOString()}),this.includeNetworkStats&&(this.currentNetworkCounter=this.createNetworkCounter());}createNetworkCounter(){return {totalRequests:0,failedRequests:0,failedRequestUrls:[],totalBytes:0,byType:{xhr:0,document:0,script:0,stylesheet:0,image:0,font:0,other:0}}}mapResourceType(t){switch(t){case "xhr":case "fetch":return "xhr";case "document":return "document";case "script":return "script";case "stylesheet":return "stylesheet";case "image":return "image";case "font":return "font";default:return "other"}}};var K="__testrelic_api_config",V="__testrelic_config_trackApiCalls";function x(r){let t=r.annotations.find(n=>n.type===K&&n.description!==void 0);if(t)try{return JSON.parse(t.description,X)}catch{}let e=r.annotations.find(n=>n.type===V&&n.description!==void 0);return e?{trackApiCalls:e.description!=="false",captureRequestHeaders:true,captureResponseHeaders:true,captureRequestBody:true,captureResponseBody:true,captureAssertions:true,redactHeaders:["authorization","cookie","set-cookie","x-api-key"],redactBodyFields:["password","secret","token","apiKey","api_key"],apiIncludeUrls:[],apiExcludeUrls:[]}:{trackApiCalls:true,captureRequestHeaders:true,captureResponseHeaders:true,captureRequestBody:true,captureResponseBody:true,captureAssertions:true,redactHeaders:["authorization","cookie","set-cookie","x-api-key"],redactBodyFields:["password","secret","token","apiKey","api_key"],apiIncludeUrls:[],apiExcludeUrls:[]}}function X(r,t){if(typeof t=="object"&&t!==null&&t.__regexp===true&&typeof t.source=="string"){let{source:e,flags:n}=t;return new RegExp(e,n)}return t}var Q={page:async({page:r},t,e)=>{let n=new q(r);try{await n.init();}catch{}await t(r);try{let{navigations:s,networkRequests:l,consoleLogs:d}=await n.getData(),c={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:s,networkRequests:l,apiCalls:[],apiAssertions:[],consoleLogs:d};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(c)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}try{await n.flushLegacyAnnotations(e);}catch{}n.dispose();},request:async({request:r},t,e)=>{let n=x(e);if(!n.trackApiCalls){await t(r);return}let s=new C,l=new A(r,s,n);l.intercept(),await t(r);try{let d=l.getData(),c=n.captureAssertions?s.getData():[],o={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:[],networkRequests:[],apiCalls:d,apiAssertions:c,consoleLogs:[]};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(o)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}try{l.flushLegacyAnnotations(e);}catch{}try{s.flushLegacyAnnotations(e);}catch{}l.dispose(),s.dispose();}};test.test.extend(Q);var bt={request:async({request:r},t,e)=>{let n=x(e);if(!n.trackApiCalls){await t(r);return}let s=new C,l=new A(r,s,n);l.intercept();let d=[],c=process.stdout.write,o=process.stderr.write;process.stdout.write=function(u,...i){try{let p=typeof u=="string"?u:Buffer.isBuffer(u)?u.toString("utf-8"):String(u);!p.startsWith("[testrelic]")&&!p.startsWith("\u2139 TestRelic")&&!p.startsWith("\u2713 TestRelic")&&!p.startsWith("\u26A0 TestRelic")&&d.push({level:"stdout",text:p.replace(/\n$/,""),timestamp:new Date().toISOString(),location:null});}catch{}return c.apply(process.stdout,[u,...i])},process.stderr.write=function(u,...i){try{let p=typeof u=="string"?u:Buffer.isBuffer(u)?u.toString("utf-8"):String(u);!p.startsWith("[testrelic]")&&!p.startsWith("\u26A0 TestRelic")&&d.push({level:"stderr",text:p.replace(/\n$/,""),timestamp:new Date().toISOString(),location:null});}catch{}return o.apply(process.stderr,[u,...i])};try{await t(r);}finally{process.stdout.write=c,process.stderr.write=o;}try{let u=l.getData(),i=n.captureAssertions?s.getData():[],p={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:[],networkRequests:[],apiCalls:u,apiAssertions:i,consoleLogs:d};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(p)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}try{l.flushLegacyAnnotations(e);}catch{}try{s.flushLegacyAnnotations(e);}catch{}l.dispose(),s.dispose();}};exports.testRelicApiFixture=bt;//# sourceMappingURL=api-fixture.cjs.map
|
|
1
|
+
'use strict';var perf_hooks=require('perf_hooks'),fs=require('fs'),path=require('path'),os=require('os'),crypto=require('crypto');require('readline');var core=require('@testrelic/core'),test=require('@playwright/test');var I=path.join(os.tmpdir(),"testrelic-data"),y=class{constructor(t){this.count=0;this.closed=false;fs.mkdirSync(I,{recursive:true}),this.filePath=path.join(I,`${t}-${crypto.randomUUID().substring(0,8)}.jsonl`),this.fd=fs.openSync(this.filePath,"w");}append(t){if(this.closed)return;let e=JSON.stringify(t)+`
|
|
2
|
+
`;fs.writeSync(this.fd,e),this.count++;}getPath(){return this.filePath}getCount(){return this.count}close(){if(!this.closed){this.closed=true;try{fs.closeSync(this.fd);}catch{}}}cleanup(){try{fs.unlinkSync(this.filePath);}catch{}}};var L=Symbol.for("__testrelic_call_id"),K="__testrelic_api_assertions",A=new WeakMap,T=class{constructor(){this.assertions=[];this.currentCallId=null;}recordAssertion(t){this.assertions.push(t);}getAssertions(){return this.assertions}setCurrentCallId(t){this.currentCallId=t;}getCurrentCallId(){return this.currentCallId}getData(){return [...this.assertions]}flushLegacyAnnotations(t){this.assertions.length!==0&&t.annotations.push({type:K,description:JSON.stringify(this.assertions)});}dispose(){this.assertions=[],this.currentCallId=null;}};var F="[REDACTED]";function _(r,t){if(r===null||t.length===0)return r;let e=new Set(t.map(o=>o.toLowerCase())),n={};for(let o of Object.keys(r))Object.hasOwn(r,o)&&(n[o]=e.has(o.toLowerCase())?F:r[o]);return n}function b(r,t){if(r===null||t.length===0)return r;let e;try{e=JSON.parse(r);}catch{return r}if(typeof e!="object"||e===null)return r;let n=new Set(t),o=S(e,n);return JSON.stringify(o)}function S(r,t){if(Array.isArray(r))return r.map(e=>S(e,t));if(typeof r=="object"&&r!==null){let e={};for(let n of Object.keys(r)){if(!Object.hasOwn(r,n))continue;let o=r[n];t.has(n)?e[n]=F:e[n]=S(o,t);}return e}return r}function D(r,t,e){if(e.length>0){for(let n of e)if(O(r,n))return false}if(t.length>0){for(let n of t)if(O(r,n))return true;return false}return true}function O(r,t){try{return t instanceof RegExp?t.test(r):V(t).test(r)}catch{return console.warn(`[testrelic] Invalid URL filter pattern: ${String(t)}`),false}}function V(r){let t="",e=0;for(;e<r.length;){let n=r[e];n==="*"&&r[e+1]==="*"?(t+=".*",e+=2,r[e]==="/"&&e++):n==="*"?(t+="[^/]*",e++):n==="?"?(t+="[^/]",e++):".+^${}()|[]\\".includes(n)?(t+="\\"+n,e++):(t+=n,e++);}return new RegExp(t)}var X=["get","post","put","patch","delete","head","fetch"],Q=["text/","application/json","application/xml","application/javascript","application/x-www-form-urlencoded","application/graphql"];function Z(r){let t=r.toLowerCase();return Q.some(e=>t.includes(e))}function tt(r){if(!r)return null;if(r.data!==void 0&&r.data!==null){let t=r.data;return typeof t=="string"?t:Buffer.isBuffer(t)?t.toString("base64"):JSON.stringify(t)}if(r.form!==void 0&&r.form!==null)return JSON.stringify(r.form);if(r.multipart!==void 0&&r.multipart!==null){let t=r.multipart,e={};for(let[n,o]of Object.entries(t))typeof o=="string"||typeof o=="number"||typeof o=="boolean"?e[n]=String(o):o&&typeof o=="object"&&"name"in o?e[n]=`[file: ${o.name}]`:e[n]="[binary]";return JSON.stringify(e)}return null}var N=class N{constructor(t,e,n){this.originals=new Map;this.apiCallWriter=null;this.callCounter=0;this.apiCallCount=0;this.disposed=false;this._lastCallId=null;this.primitiveCallIds=new Map;this.context=t,this.assertionTracker=e??null,this.apiConfig=n??N.DEFAULT_API_CONFIG;try{this.apiCallWriter=new y("api-calls");}catch{}}get lastCallId(){return this._lastCallId}getCallIdForValue(t){return t!=null&&typeof t=="object"?A.get(t)??null:this.primitiveCallIds.get(t)??null}intercept(){for(let e of X){let n=this.context[e].bind(this.context);this.originals.set(e,n),this.context[e]=this.createWrapper(e,n);}let t=this.context.dispose.bind(this.context);this.originals.set("dispose",t),this.context.dispose=async e=>(this.disposed=true,t(e));}getFileData(){return this.apiCallWriter?.close(),{apiCallsFile:this.apiCallWriter?.getCount()?this.apiCallWriter.getPath():null,apiCallsCount:this.apiCallWriter?.getCount()??0}}flushLegacyAnnotations(t){}dispose(){for(let[t,e]of this.originals)this.context[t]=e;this.originals.clear(),this.apiCallWriter?.close(),this.callCounter=0,this.apiCallCount=0,this._lastCallId=null,this.primitiveCallIds.clear();}get isDisposed(){return this.disposed}getCapturedCallCount(){return this.apiCallCount}tagResponseMethods(t,e){let n=this,o=t.headers.bind(t);t.headers=function(){let a=o();return A.set(a,e),a};let d=t.headersArray.bind(t);t.headersArray=function(){let a=d();return A.set(a,e),a};let c=t.json.bind(t);t.json=async function(){let a=await c();return a!=null&&typeof a=="object"&&A.set(a,e),a};let u=t.status.bind(t);t.status=function(){let a=u();return n.primitiveCallIds.set(a,e),a};let i=t.statusText.bind(t);t.statusText=function(){let a=i();return n.primitiveCallIds.set(a,e),a};let p=t.ok.bind(t);t.ok=function(){let a=p();return n.primitiveCallIds.set(a,e),a};let s=t.text.bind(t);t.text=async function(){let a=await s();return n.primitiveCallIds.set(a,e),a};let g=t.body.bind(t);t.body=async function(){let a=await g();return A.set(a,e),a};}createWrapper(t,e){let n=this;return async function(d,c){if(!D(d,n.apiConfig.apiIncludeUrls,n.apiConfig.apiExcludeUrls))return e(d,c);let u=`api-call-${n.callCounter++}`,i=new Date().toISOString(),p=t==="fetch"?(c?.method??"GET").toUpperCase():t.toUpperCase(),s=tt(c),g=perf_hooks.performance.now();n._lastCallId=u,n.assertionTracker&&n.assertionTracker.setCurrentCallId(u);let l;try{l=await e(d,c);}catch(a){let m=perf_hooks.performance.now();try{let w=n.apiConfig.captureRequestBody?b(s,n.apiConfig.redactBodyFields):null,C={id:u,timestamp:i,method:p,url:d,requestHeaders:null,requestBody:w,responseStatusCode:null,responseStatusText:null,responseHeaders:null,responseBody:null,responseTimeMs:Math.round((m-g)*100)/100,isBinary:!1,error:a instanceof Error?a.message:String(a)};n.apiCallWriter&&(n.apiCallWriter.append(C),n.apiCallCount++);}catch{}throw a}try{let a=perf_hooks.performance.now(),m=l.headers(),w=m["content-type"]??null,C=w?!Z(w):!1,f=null;n.apiConfig.captureRequestHeaders&&c?.headers&&(f=c.headers);let h=null;n.apiConfig.captureResponseHeaders&&(h=m);let R=n.apiConfig.captureRequestBody?s:null,k=null;if(n.apiConfig.captureResponseBody)try{C?k=(await l.body()).toString("base64"):k=await l.text();}catch{}f=_(f,n.apiConfig.redactHeaders),h=_(h,n.apiConfig.redactHeaders),R=b(R,n.apiConfig.redactBodyFields),k=b(k,n.apiConfig.redactBodyFields);let j={id:u,timestamp:i,method:p,url:l.url(),requestHeaders:f,requestBody:R,responseStatusCode:l.status(),responseStatusText:l.statusText(),responseHeaders:h,responseBody:k,responseTimeMs:Math.round((a-g)*100)/100,isBinary:C,error:null};n.apiCallWriter&&(n.apiCallWriter.append(j),n.apiCallCount++);}catch{}try{l[L]=u,n.tagResponseMethods(l,u);}catch{}return l}}};N.DEFAULT_API_CONFIG=Object.freeze({trackApiCalls:true,captureRequestHeaders:true,captureResponseHeaders:true,captureRequestBody:true,captureResponseBody:true,captureAssertions:true,redactHeaders:["authorization","cookie","set-cookie","x-api-key"],redactBodyFields:["password","secret","token","apiKey","api_key"],apiIncludeUrls:[],apiExcludeUrls:[]});var v=N;var et=["text/","application/json","application/xml","application/javascript","application/x-www-form-urlencoded","application/graphql"];function nt(r){let t=r.toLowerCase();return et.some(e=>t.includes(e))}var q=class r{constructor(t,e){this.page=t;this.records=[];this.listeners=[];this.currentNetworkCounter=null;this.pendingRequests=new Map;this.networkWriter=null;this.consoleWriter=null;this.pendingBodyReads=[];this.requestIdCounter=0;this.networkRequestCount=0;this.consoleLogCount=0;this.includeNetworkStats=e?.includeNetworkStats??true,this.origGoto=t.goto.bind(t),this.origGoBack=t.goBack.bind(t),this.origGoForward=t.goForward.bind(t),this.origReload=t.reload.bind(t);try{this.includeNetworkStats&&(this.networkWriter=new y("network")),this.consoleWriter=new y("console");}catch{}this.interceptMethods(),this.attachListeners();}async init(){await this.injectSPADetection();}async finalizeCapturedRequests(){await Promise.allSettled(this.pendingBodyReads),this.pendingBodyReads=[];for(let[,t]of this.pendingRequests)this.networkWriter&&(this.networkWriter.append({url:t.url,method:t.method,resourceType:t.resourceType,statusCode:0,responseTimeMs:Date.now()-t.startTimeMs,startedAt:t.startedAt,requestHeaders:t.headers,requestBody:t.postData,responseBody:null,responseHeaders:null,contentType:null,responseSize:0,requestBodyTruncated:t.postDataTruncated,responseBodyTruncated:false,isBinary:false,error:"incomplete"}),this.networkRequestCount++);this.pendingRequests.clear(),this.networkWriter?.close(),this.consoleWriter?.close();}static mapConsoleType(t){switch(t){case "log":return "log";case "warning":return "warn";case "error":return "error";case "info":return "info";case "debug":return "debug";default:return "log"}}async getFileData(){this.includeNetworkStats&&this.currentNetworkCounter&&this.records.length>0&&(this.records[this.records.length-1].networkStats={totalRequests:this.currentNetworkCounter.totalRequests,failedRequests:this.currentNetworkCounter.failedRequests,failedRequestUrls:[...this.currentNetworkCounter.failedRequestUrls],totalBytes:this.currentNetworkCounter.totalBytes,byType:{...this.currentNetworkCounter.byType}});let t=this.records.map(e=>({url:e.url,navigationType:e.navigationType,timestamp:e.timestamp,domContentLoadedAt:e.domContentLoadedAt,networkIdleAt:e.networkIdleAt,networkStats:e.networkStats}));return this.includeNetworkStats?await this.finalizeCapturedRequests():this.consoleWriter?.close(),{navigations:t,networkRequestsFile:this.networkWriter?.getCount()?this.networkWriter.getPath():null,networkRequestsCount:this.networkWriter?.getCount()??0,consoleLogsFile:this.consoleWriter?.getCount()?this.consoleWriter.getPath():null,consoleLogsCount:this.consoleWriter?.getCount()??0}}async flushLegacyAnnotations(t){}dispose(){this.page.goto=this.origGoto,this.page.goBack=this.origGoBack,this.page.goForward=this.origGoForward,this.page.reload=this.origReload;for(let{event:t,handler:e}of this.listeners)this.page.off(t,e);this.listeners=[],this.records=[],this.pendingRequests.clear(),this.pendingBodyReads=[],this.networkWriter?.close(),this.consoleWriter?.close();}getRecords(){return this.records}interceptMethods(){let t=this,e=this.page;e.goto=async function(n,o){return t.recordNavigation(n,"goto"),t.origGoto(n,o)},e.goBack=async function(n){let o=await t.origGoBack(n);return t.recordNavigation(e.url(),"back"),o},e.goForward=async function(n){let o=await t.origGoForward(n);return t.recordNavigation(e.url(),"forward"),o},e.reload=async function(n){return t.recordNavigation(e.url(),"refresh"),t.origReload(n)};}attachListeners(){let t=()=>{this.lastDomContentLoaded=new Date().toISOString(),this.records.length>0&&(this.records[this.records.length-1].domContentLoadedAt=this.lastDomContentLoaded);};this.page.on("domcontentloaded",t),this.listeners.push({event:"domcontentloaded",handler:t});let e=o=>{try{let d=o;if(typeof d.parentFrame=="function"&&d.parentFrame()!==null)return;let c=d.url(),u=this.records[this.records.length-1];if(u&&Date.now()-new Date(u.timestamp).getTime()<50&&u.url===c)return;this.recordNavigation(c,"navigation");}catch{}};this.page.on("framenavigated",e),this.listeners.push({event:"framenavigated",handler:e});let n=o=>{try{let d=o,c=d.type(),u=d.text();if(c==="debug"&&u.startsWith("__testrelic_nav:")){try{let i=JSON.parse(u.slice(16));i.type&&i.url&&this.recordNavigation(i.url,i.type);}catch{}return}{let i=null;try{let s=d.location();s&&s.url&&(i=`${s.url}:${s.lineNumber}:${s.columnNumber}`);}catch{}let p=r.mapConsoleType(c);this.consoleWriter&&(this.consoleWriter.append({level:p,text:u,timestamp:new Date().toISOString(),location:i}),this.consoleLogCount++);}}catch{}};if(this.page.on("console",n),this.listeners.push({event:"console",handler:n}),this.includeNetworkStats){let o=u=>{this.currentNetworkCounter&&this.currentNetworkCounter.totalRequests++;try{let i=u,p=String(this.requestIdCounter++),s=i.postData()??null,g={url:i.url(),method:i.method(),resourceType:this.mapResourceType(i.resourceType()),headers:i.headers(),postData:s,postDataTruncated:!1,startedAt:new Date().toISOString(),startTimeMs:Date.now()};this.pendingRequests.set(p,g),u.__testrelic_id=p;}catch{}};this.page.on("request",o),this.listeners.push({event:"request",handler:o});let d=u=>{try{let i=u;if(this.currentNetworkCounter){let f=i.status();f>=400&&(this.currentNetworkCounter.failedRequests++,this.currentNetworkCounter.failedRequestUrls.push(f+" "+i.url()));let h=i.headers()["content-length"];h&&(this.currentNetworkCounter.totalBytes+=parseInt(h,10)||0);let R=i.request().resourceType(),k=this.mapResourceType(R);this.currentNetworkCounter.byType[k]++;}let p=i.request().__testrelic_id;if(!p)return;let s=this.pendingRequests.get(p);if(!s)return;this.pendingRequests.delete(p);let g=Date.now()-s.startTimeMs,l=i.headers(),a=l["content-type"]??null,m=parseInt(l["content-length"]??"0",10)||0,w=a?!nt(a):!1,C=(async()=>{let f=null;if(!w)try{f=(await i.body()).toString("utf-8");}catch{}let h={url:s.url,method:s.method,resourceType:s.resourceType,statusCode:i.status(),responseTimeMs:g,startedAt:s.startedAt,requestHeaders:s.headers,requestBody:s.postData,responseBody:f,responseHeaders:l,contentType:a,responseSize:m,requestBodyTruncated:s.postDataTruncated,responseBodyTruncated:!1,isBinary:w,error:null};this.networkWriter&&(this.networkWriter.append(h),this.networkRequestCount++);})();this.pendingBodyReads.push(C);}catch{}};this.page.on("response",d),this.listeners.push({event:"response",handler:d});let c=u=>{if(this.currentNetworkCounter){this.currentNetworkCounter.failedRequests++;try{let i=u;this.currentNetworkCounter.failedRequestUrls.push("ERR "+i.url());}catch{}}try{let i=u,p=i.__testrelic_id;if(!p)return;let s=this.pendingRequests.get(p);if(!s)return;this.pendingRequests.delete(p);let g={url:s.url,method:s.method,resourceType:s.resourceType,statusCode:0,responseTimeMs:Date.now()-s.startTimeMs,startedAt:s.startedAt,requestHeaders:s.headers,requestBody:s.postData,responseBody:null,responseHeaders:null,contentType:null,responseSize:0,requestBodyTruncated:s.postDataTruncated,responseBodyTruncated:!1,isBinary:!1,error:i.failure()?.errorText??"Unknown error"};this.networkWriter&&(this.networkWriter.append(g),this.networkRequestCount++);}catch{}};this.page.on("requestfailed",c),this.listeners.push({event:"requestfailed",handler:c});}}async injectSPADetection(){try{await this.page.addInitScript(()=>{let t=history.pushState.bind(history),e=history.replaceState.bind(history);history.pushState=function(...n){t(...n),console.debug("__testrelic_nav:"+JSON.stringify({type:"spa_route",url:location.href}));},history.replaceState=function(...n){e(...n),console.debug("__testrelic_nav:"+JSON.stringify({type:"spa_replace",url:location.href}));},window.addEventListener("popstate",()=>{console.debug("__testrelic_nav:"+JSON.stringify({type:"popstate",url:location.href}));}),window.addEventListener("hashchange",()=>{console.debug("__testrelic_nav:"+JSON.stringify({type:"hash_change",url:location.href}));});});}catch{}}recordNavigation(t,e){this.includeNetworkStats&&this.currentNetworkCounter&&this.records.length>0&&(this.records[this.records.length-1].networkStats={totalRequests:this.currentNetworkCounter.totalRequests,failedRequests:this.currentNetworkCounter.failedRequests,failedRequestUrls:[...this.currentNetworkCounter.failedRequestUrls],totalBytes:this.currentNetworkCounter.totalBytes,byType:{...this.currentNetworkCounter.byType}}),this.records.push({url:t,navigationType:e,timestamp:new Date().toISOString()}),this.includeNetworkStats&&(this.currentNetworkCounter=this.createNetworkCounter());}createNetworkCounter(){return {totalRequests:0,failedRequests:0,failedRequestUrls:[],totalBytes:0,byType:{xhr:0,document:0,script:0,stylesheet:0,image:0,font:0,other:0}}}mapResourceType(t){switch(t){case "xhr":case "fetch":return "xhr";case "document":return "document";case "script":return "script";case "stylesheet":return "stylesheet";case "image":return "image";case "font":return "font";default:return "other"}}};var st="__testrelic_api_config",ot="__testrelic_config_trackApiCalls";function P(r){let t=r.annotations.find(n=>n.type===st&&n.description!==void 0);if(t)try{return JSON.parse(t.description,it)}catch{}let e=r.annotations.find(n=>n.type===ot&&n.description!==void 0);return e?{trackApiCalls:e.description!=="false",captureRequestHeaders:true,captureResponseHeaders:true,captureRequestBody:true,captureResponseBody:true,captureAssertions:true,redactHeaders:["authorization","cookie","set-cookie","x-api-key"],redactBodyFields:["password","secret","token","apiKey","api_key"],apiIncludeUrls:[],apiExcludeUrls:[]}:{trackApiCalls:true,captureRequestHeaders:true,captureResponseHeaders:true,captureRequestBody:true,captureResponseBody:true,captureAssertions:true,redactHeaders:["authorization","cookie","set-cookie","x-api-key"],redactBodyFields:["password","secret","token","apiKey","api_key"],apiIncludeUrls:[],apiExcludeUrls:[]}}function it(r,t){if(typeof t=="object"&&t!==null&&t.__regexp===true&&typeof t.source=="string"){let{source:e,flags:n}=t;return new RegExp(e,n)}return t}var at={page:async({page:r},t,e)=>{let n=new q(r);try{await n.init();}catch{}await t(r);try{let{navigations:o,networkRequestsFile:d,networkRequestsCount:c,consoleLogsFile:u,consoleLogsCount:i}=await n.getFileData(),p={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:o,apiAssertions:[],networkRequestsFile:d,networkRequestsCount:c,consoleLogsFile:u,consoleLogsCount:i,apiCallsFile:null,apiCallsCount:0};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(p)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}n.dispose();},request:async({request:r},t,e)=>{let n=P(e);if(!n.trackApiCalls){await t(r);return}let o=new T,d=new v(r,o,n);d.intercept(),await t(r);try{let{apiCallsFile:c,apiCallsCount:u}=d.getFileData(),i=n.captureAssertions?o.getData():[],p={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:[],apiAssertions:i,networkRequestsFile:null,networkRequestsCount:0,consoleLogsFile:null,consoleLogsCount:0,apiCallsFile:c,apiCallsCount:u};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(p)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}d.dispose(),o.dispose();}};test.test.extend(at);var Yt={request:async({request:r},t,e)=>{let n=P(e);if(!n.trackApiCalls){await t(r);return}let o=new T,d=new v(r,o,n);d.intercept();let c=null;try{c=new y("api-console");}catch{}let u=0,i=process.stdout.write,p=process.stderr.write;process.stdout.write=function(s,...g){try{let l=typeof s=="string"?s:Buffer.isBuffer(s)?s.toString("utf-8"):String(s);!l.startsWith("[testrelic]")&&!l.startsWith("\u2139 TestRelic")&&!l.startsWith("\u2713 TestRelic")&&!l.startsWith("\u26A0 TestRelic")&&c&&(c.append({level:"stdout",text:l.replace(/\n$/,""),timestamp:new Date().toISOString(),location:null}),u++);}catch{}return i.apply(process.stdout,[s,...g])},process.stderr.write=function(s,...g){try{let l=typeof s=="string"?s:Buffer.isBuffer(s)?s.toString("utf-8"):String(s);!l.startsWith("[testrelic]")&&!l.startsWith("\u26A0 TestRelic")&&c&&(c.append({level:"stderr",text:l.replace(/\n$/,""),timestamp:new Date().toISOString(),location:null}),u++);}catch{}return p.apply(process.stderr,[s,...g])};try{await t(r);}finally{process.stdout.write=i,process.stderr.write=p;}try{c?.close();let{apiCallsFile:s,apiCallsCount:g}=d.getFileData(),l=n.captureAssertions?o.getData():[],a={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:[],apiAssertions:l,networkRequestsFile:null,networkRequestsCount:0,consoleLogsFile:u>0?c?.getPath()??null:null,consoleLogsCount:u,apiCallsFile:s,apiCallsCount:g};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(a)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}d.dispose(),o.dispose();}};exports.testRelicApiFixture=Yt;//# sourceMappingURL=api-fixture.cjs.map
|
|
2
3
|
//# sourceMappingURL=api-fixture.cjs.map
|