@testrelic/playwright-analytics 2.2.4 → 2.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -3
- package/dist/api-fixture.cjs +1 -1
- package/dist/api-fixture.cjs.map +1 -1
- package/dist/api-fixture.js +1 -1
- package/dist/api-fixture.js.map +1 -1
- package/dist/fixture.cjs +1 -1
- package/dist/fixture.cjs.map +1 -1
- package/dist/fixture.js +1 -1
- package/dist/fixture.js.map +1 -1
- package/dist/index.cjs +146 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -2
- package/dist/index.d.ts +31 -2
- package/dist/index.js +146 -45
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,8 +13,10 @@ When you run your Playwright tests with the TestRelic reporter and fixture, you
|
|
|
13
13
|
- **Failure diagnostics** — Error messages, source code snippets pointing to the exact failure line, and optional stack traces
|
|
14
14
|
- **CI metadata** — Auto-detection of GitHub Actions, GitLab CI, Jenkins, and CircleCI with build ID, commit SHA, and branch
|
|
15
15
|
- **Sensitive data redaction** — Automatically scrubs AWS keys, Bearer tokens, private keys, credential URLs, and sensitive API headers/body fields
|
|
16
|
-
- **Action steps** — Captures Playwright test steps (
|
|
17
|
-
- **
|
|
16
|
+
- **Action steps** — Captures Playwright test steps (actions, assertions, custom steps) with video timestamp sync
|
|
17
|
+
- **Console log capture** — Collects browser console messages (log, warn, error) per test
|
|
18
|
+
- **Screenshots & videos** — Automatically captures screenshots and video recordings, organized per test in an `artifacts/` folder alongside the report
|
|
19
|
+
- **HTML report** — Self-contained interactive HTML report with test grid, filter bar, and expandable drawer showing navigation timeline, API call details, and artifacts
|
|
18
20
|
|
|
19
21
|
## Quick Start
|
|
20
22
|
|
|
@@ -26,6 +28,30 @@ npm install @testrelic/playwright-analytics
|
|
|
26
28
|
|
|
27
29
|
### 2. Add the reporter to your Playwright config
|
|
28
30
|
|
|
31
|
+
**Option A: Use `defineConfig` (recommended)** — automatically enables video, screenshots, trace capture, and the TestRelic reporter:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// playwright.config.ts
|
|
35
|
+
import { defineConfig } from '@testrelic/playwright-analytics';
|
|
36
|
+
|
|
37
|
+
export default defineConfig({
|
|
38
|
+
testDir: './tests',
|
|
39
|
+
// video: 'on', screenshot: 'on', trace: 'on', and the TestRelic reporter
|
|
40
|
+
// are all configured automatically. Override any of these in `use:` if needed.
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
You can pass reporter-specific options as a second argument:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
export default defineConfig(
|
|
48
|
+
{ testDir: './tests' },
|
|
49
|
+
{ includeStackTrace: true, includeCodeSnippets: true },
|
|
50
|
+
);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Option B: Manual setup** — configure Playwright and the reporter separately:
|
|
54
|
+
|
|
29
55
|
```typescript
|
|
30
56
|
// playwright.config.ts
|
|
31
57
|
import { defineConfig } from '@playwright/test';
|
|
@@ -43,6 +69,8 @@ export default defineConfig({
|
|
|
43
69
|
});
|
|
44
70
|
```
|
|
45
71
|
|
|
72
|
+
> **Note:** When using `defineConfig` from `@testrelic/playwright-analytics`, Playwright's default `list` reporter is preserved automatically so CLI commands like `npx playwright test --list` continue to work.
|
|
73
|
+
|
|
46
74
|
### 3. Use the fixture in your tests
|
|
47
75
|
|
|
48
76
|
TestRelic provides two fixture modes depending on your testing needs:
|
|
@@ -168,12 +196,13 @@ All options are passed as the second element of the reporter tuple:
|
|
|
168
196
|
| `codeContextLines` | `number` | `3` | Lines of context above/below the failure line |
|
|
169
197
|
| `includeNetworkStats` | `boolean` | `true` | Track network requests and bytes per navigation |
|
|
170
198
|
| `includeArtifacts` | `boolean` | `true` | Include screenshots and video in the report |
|
|
199
|
+
| `includeActionSteps` | `boolean` | `true` | Capture Playwright test steps (actions, assertions, custom steps) with video sync |
|
|
200
|
+
| `captureConsoleLogs` | `boolean` | `true` | Capture browser console messages (log, warn, error) per test |
|
|
171
201
|
| `navigationTypes` | `NavigationType[] \| null` | `null` (all) | Filter timeline to specific navigation types |
|
|
172
202
|
| `redactPatterns` | `(string \| RegExp)[]` | Built-in patterns | Additional patterns to redact from error output |
|
|
173
203
|
| `testRunId` | `string \| null` | `null` (auto UUID) | Override the test run ID |
|
|
174
204
|
| `metadata` | `Record<string, unknown> \| null` | `null` | Attach custom metadata to the report |
|
|
175
205
|
| `openReport` | `boolean` | `true` | Auto-open the HTML report after test run |
|
|
176
|
-
| `includeActionSteps` | `boolean` | `true` | Capture Playwright test steps (actions, assertions, custom steps) with video sync |
|
|
177
206
|
| `quiet` | `boolean` | `false` | Suppress TestRelic banner output |
|
|
178
207
|
|
|
179
208
|
### API Tracking Options
|
|
@@ -255,6 +284,81 @@ reporter: [
|
|
|
255
284
|
]
|
|
256
285
|
```
|
|
257
286
|
|
|
287
|
+
## Screenshots & Videos
|
|
288
|
+
|
|
289
|
+
When using `defineConfig` from `@testrelic/playwright-analytics`, video recording and screenshot capture are enabled by default (`video: 'on'`, `screenshot: 'on'`). If using manual config, enable them in Playwright's `use` section:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
export default defineConfig({
|
|
293
|
+
use: {
|
|
294
|
+
video: 'on',
|
|
295
|
+
screenshot: 'on',
|
|
296
|
+
},
|
|
297
|
+
reporter: [['list'], ['@testrelic/playwright-analytics']],
|
|
298
|
+
});
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Artifacts are automatically copied to an `artifacts/` folder next to your report:
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
test-results/
|
|
305
|
+
├── analytics-timeline.json
|
|
306
|
+
├── analytics-timeline.html
|
|
307
|
+
└── artifacts/
|
|
308
|
+
├── homepage-loads-correctly/
|
|
309
|
+
│ ├── screenshot.png
|
|
310
|
+
│ └── video.webm
|
|
311
|
+
└── search-works--retry-1/
|
|
312
|
+
├── screenshot.png
|
|
313
|
+
└── video.webm
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
- Screenshots are captured at the end of each test (`.png`)
|
|
317
|
+
- Videos record the full browser session (`.webm`)
|
|
318
|
+
- Retried tests get separate folders with a `--retry-N` suffix
|
|
319
|
+
- The HTML report embeds links to these artifacts with inline image/video viewers
|
|
320
|
+
- Disable artifact collection with `includeArtifacts: false`
|
|
321
|
+
|
|
322
|
+
## Action Steps
|
|
323
|
+
|
|
324
|
+
TestRelic captures Playwright test steps — actions (`click`, `fill`, `goto`), assertions (`expect`), and custom steps (`test.step()`). Steps are timestamped and synced with the video timeline so you can jump to the exact moment in the recording.
|
|
325
|
+
|
|
326
|
+
Enable/disable with the `includeActionSteps` option (default: `true`):
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
['@testrelic/playwright-analytics', {
|
|
330
|
+
includeActionSteps: true,
|
|
331
|
+
}]
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
In the HTML report, action steps appear in the test drawer alongside the navigation timeline, showing:
|
|
335
|
+
- Step category (action, assertion, or custom)
|
|
336
|
+
- Step title and duration
|
|
337
|
+
- Video timestamp for playback sync
|
|
338
|
+
|
|
339
|
+
## Console Log Capture
|
|
340
|
+
|
|
341
|
+
TestRelic captures browser console messages (`log`, `warn`, `error`) per test. Useful for debugging test failures without re-running.
|
|
342
|
+
|
|
343
|
+
Enable/disable with the `captureConsoleLogs` option (default: `true`):
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
['@testrelic/playwright-analytics', {
|
|
347
|
+
captureConsoleLogs: true,
|
|
348
|
+
}]
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Network Statistics
|
|
352
|
+
|
|
353
|
+
Each navigation in the timeline includes detailed network statistics:
|
|
354
|
+
|
|
355
|
+
- **Total requests** — number of network requests during the navigation
|
|
356
|
+
- **Failed requests** — count and URLs of failed requests (useful for spotting broken assets)
|
|
357
|
+
- **Bytes transferred** — total bytes received
|
|
358
|
+
- **Resource breakdown** — requests grouped by type: `xhr`, `document`, `script`, `stylesheet`, `image`, `font`, `other`
|
|
359
|
+
|
|
360
|
+
Disable with `includeNetworkStats: false`.
|
|
361
|
+
|
|
258
362
|
## Merging Shard Reports
|
|
259
363
|
|
|
260
364
|
When running Playwright with sharding, each shard produces its own report. Merge them with the CLI:
|
package/dist/api-fixture.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var perf_hooks=require('perf_hooks');require('fs');var core=require('@testrelic/core'),test=require('@playwright/test');var I=Symbol.for("__testrelic_call_id"),F="__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:F,description:JSON.stringify(this.assertions)});}dispose(){this.assertions=[],this.currentCallId=null;}};var O="[REDACTED]";function x(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())?O:r[s]);return n}function N(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=S(e,n);return JSON.stringify(s)}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 s=r[n];t.has(n)?e[n]=O:e[n]=S(s,t);}return e}return r}function E(r,t,e){if(e.length>0){for(let n of e)if(D(r,n))return false}if(t.length>0){for(let n of t)if(D(r,n))return true;return false}return true}function D(r,t){try{return t instanceof RegExp?t.test(r):U(t).test(r)}catch{return console.warn(`[testrelic] Invalid URL filter pattern: ${String(t)}`),false}}function U(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 J=["get","post","put","patch","delete","head","fetch"],G=["text/","application/json","application/xml","application/javascript","application/x-www-form-urlencoded","application/graphql"],Y="__testrelic_api_calls";function z(r){let t=r.toLowerCase();return G.some(e=>t.includes(e))}function X(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 q=class q{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??q.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 J){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:Y,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 o=s();return T.set(o,e),o};let c=t.headersArray.bind(t);t.headersArray=function(){let o=c();return T.set(o,e),o};let d=t.json.bind(t);t.json=async function(){let o=await d();return o!=null&&typeof o=="object"&&T.set(o,e),o};let i=t.status.bind(t);t.status=function(){let o=i();return n.primitiveCallIds.set(o,e),o};let a=t.statusText.bind(t);t.statusText=function(){let o=a();return n.primitiveCallIds.set(o,e),o};let p=t.ok.bind(t);t.ok=function(){let o=p();return n.primitiveCallIds.set(o,e),o};let u=t.text.bind(t);t.text=async function(){let o=await u();return n.primitiveCallIds.set(o,e),o};let g=t.body.bind(t);t.body=async function(){let o=await g();return T.set(o,e),o};}createWrapper(t,e){let n=this;return async function(c,d){if(!E(c,n.apiConfig.apiIncludeUrls,n.apiConfig.apiExcludeUrls))return e(c,d);let i=`api-call-${n.callCounter++}`,a=new Date().toISOString(),p=t==="fetch"?(d?.method??"GET").toUpperCase():t.toUpperCase(),u=X(d),g=perf_hooks.performance.now();n._lastCallId=i,n.assertionTracker&&n.assertionTracker.setCurrentCallId(i);let l;try{l=await e(c,d);}catch(o){let m=perf_hooks.performance.now();try{let w=n.apiConfig.captureRequestBody?N(u,n.apiConfig.redactBodyFields):null,R={id:i,timestamp:a,method:p,url:c,requestHeaders:null,requestBody:w,responseStatusCode:null,responseStatusText:null,responseHeaders:null,responseBody:null,responseTimeMs:Math.round((m-g)*100)/100,isBinary:!1,error:o instanceof Error?o.message:String(o)};n.capturedCalls.push(R);}catch{}throw o}try{let o=perf_hooks.performance.now(),m=l.headers(),w=m["content-type"]??null,R=w?!z(w):!1,f=null;n.apiConfig.captureRequestHeaders&&d?.headers&&(f=d.headers);let h=null;n.apiConfig.captureResponseHeaders&&(h=m);let k=n.apiConfig.captureRequestBody?u:null,y=null;if(n.apiConfig.captureResponseBody)try{R?y=(await l.body()).toString("base64"):y=await l.text();}catch{}f=x(f,n.apiConfig.redactHeaders),h=x(h,n.apiConfig.redactHeaders),k=N(k,n.apiConfig.redactBodyFields),y=N(y,n.apiConfig.redactBodyFields);let _={id:i,timestamp:a,method:p,url:l.url(),requestHeaders:f,requestBody:k,responseStatusCode:l.status(),responseStatusText:l.statusText(),responseHeaders:h,responseBody:y,responseTimeMs:Math.round((o-g)*100)/100,isBinary:R,error:null};n.capturedCalls.push(_);}catch{}try{l[I]=i,n.tagResponseMethods(l,i);}catch{}return l}}};q.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=q;var W=["text/","application/json","application/xml","application/javascript","application/x-www-form-urlencoded","application/graphql"];function K(r){let t=r.toLowerCase();return W.some(e=>t.includes(e))}function L(r,t){let e=new TextEncoder().encode(r);return e.length<=t?{text:r,truncated:false}:{text:new TextDecoder().decode(e.slice(0,t)),truncated:true}}var v=class{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.requestCaptureCount=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),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))}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}}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=[],this.requestCaptureCount=0;}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 c=s;if(typeof c.parentFrame=="function"&&c.parentFrame()!==null)return;let d=c.url(),i=this.records[this.records.length-1];if(i&&Date.now()-new Date(i.timestamp).getTime()<50&&i.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 c=s;if(c.type()!=="debug")return;let d=c.text();if(!d.startsWith("__testrelic_nav:"))return;let i=JSON.parse(d.slice(16));i.type&&i.url&&this.recordNavigation(i.url,i.type);}catch{}};if(this.page.on("console",n),this.listeners.push({event:"console",handler:n}),this.includeNetworkStats){let s=i=>{if(this.currentNetworkCounter&&this.currentNetworkCounter.totalRequests++,!(this.requestCaptureCount>=500)){this.requestCaptureCount++;try{let a=i,p=String(this.requestIdCounter++),u=a.postData()??null,g=!1;if(u!==null){let o=L(u,10240);u=o.text,g=o.truncated;}let l={url:a.url(),method:a.method(),resourceType:this.mapResourceType(a.resourceType()),headers:a.headers(),postData:u,postDataTruncated:g,startedAt:new Date().toISOString(),startTimeMs:Date.now()};this.pendingRequests.set(p,l),i.__testrelic_id=p;}catch{}}};this.page.on("request",s),this.listeners.push({event:"request",handler:s});let c=i=>{try{let a=i;if(this.currentNetworkCounter){let f=a.status();f>=400&&(this.currentNetworkCounter.failedRequests++,this.currentNetworkCounter.failedRequestUrls.push(f+" "+a.url()));let h=a.headers()["content-length"];h&&(this.currentNetworkCounter.totalBytes+=parseInt(h,10)||0);let k=a.request().resourceType(),y=this.mapResourceType(k);this.currentNetworkCounter.byType[y]++;}let p=a.request().__testrelic_id;if(!p)return;let u=this.pendingRequests.get(p);if(!u)return;this.pendingRequests.delete(p);let g=Date.now()-u.startTimeMs,l=a.headers(),o=l["content-type"]??null,m=parseInt(l["content-length"]??"0",10)||0,w=o?!K(o):!1,R=(async()=>{let f=null,h=!1;if(!w)try{let _=(await a.body()).toString("utf-8"),b=L(_,10240);f=b.text,h=b.truncated;}catch{}let k={url:u.url,method:u.method,resourceType:u.resourceType,statusCode:a.status(),responseTimeMs:g,startedAt:u.startedAt,requestHeaders:u.headers,requestBody:u.postData,responseBody:f,responseHeaders:l,contentType:o,responseSize:m,requestBodyTruncated:u.postDataTruncated,responseBodyTruncated:h,isBinary:w,error:null};this.capturedRequests.push(k);})();this.pendingBodyReads.push(R);}catch{}};this.page.on("response",c),this.listeners.push({event:"response",handler:c});let d=i=>{if(this.currentNetworkCounter){this.currentNetworkCounter.failedRequests++;try{let a=i;this.currentNetworkCounter.failedRequestUrls.push("ERR "+a.url());}catch{}}try{let a=i,p=a.__testrelic_id;if(!p)return;let u=this.pendingRequests.get(p);if(!u)return;this.pendingRequests.delete(p);let g={url:u.url,method:u.method,resourceType:u.resourceType,statusCode:0,responseTimeMs:Date.now()-u.startTimeMs,startedAt:u.startedAt,requestHeaders:u.headers,requestBody:u.postData,responseBody:null,responseHeaders:null,contentType:null,responseSize:0,requestBodyTruncated:u.postDataTruncated,responseBodyTruncated:!1,isBinary:!1,error:a.failure()?.errorText??"Unknown error"};this.capturedRequests.push(g);}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 $="__testrelic_api_config",Z="__testrelic_config_trackApiCalls";function P(r){let t=r.annotations.find(n=>n.type===$&&n.description!==void 0);if(t)try{return JSON.parse(t.description,Q)}catch{}let e=r.annotations.find(n=>n.type===Z&&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 Q(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 tt={page:async({page:r},t,e)=>{let n=new v(r);try{await n.init();}catch{}await t(r);try{let{navigations:s,networkRequests:c}=await n.getData(),d={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:s,networkRequests:c,apiCalls:[],apiAssertions:[]};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(d)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}try{await n.flushLegacyAnnotations(e);}catch{}n.dispose();},request:async({request:r},t,e)=>{let n=P(e);if(!n.trackApiCalls){await t(r);return}let s=new C,c=new A(r,s,n);c.intercept(),await t(r);try{let d=c.getData(),i=n.captureAssertions?s.getData():[],a={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:[],networkRequests:[],apiCalls:d,apiAssertions:i};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(a)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}try{c.flushLegacyAnnotations(e);}catch{}try{s.flushLegacyAnnotations(e);}catch{}c.dispose(),s.dispose();}};test.test.extend(tt);var bt={request:async({request:r},t,e)=>{let n=P(e);if(!n.trackApiCalls){await t(r);return}let s=new C,c=new A(r,s,n);c.intercept(),await t(r);try{let d=c.getData(),i=n.captureAssertions?s.getData():[],a={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:[],networkRequests:[],apiCalls:d,apiAssertions:i};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(a)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}try{c.flushLegacyAnnotations(e);}catch{}try{s.flushLegacyAnnotations(e);}catch{}c.dispose(),s.dispose();}};exports.testRelicApiFixture=bt;//# sourceMappingURL=api-fixture.cjs.map
|
|
1
|
+
'use strict';var perf_hooks=require('perf_hooks');require('fs');var core=require('@testrelic/core'),test=require('@playwright/test');var P=Symbol.for("__testrelic_call_id"),F="__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:F,description:JSON.stringify(this.assertions)});}dispose(){this.assertions=[],this.currentCallId=null;}};var L="[REDACTED]";function x(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())?L: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=_(e,n);return JSON.stringify(s)}function _(r,t){if(Array.isArray(r))return r.map(e=>_(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]=L:e[n]=_(s,t);}return e}return r}function O(r,t,e){if(e.length>0){for(let n of e)if(E(r,n))return false}if(t.length>0){for(let n of t)if(E(r,n))return true;return false}return true}function E(r,t){try{return t instanceof RegExp?t.test(r):U(t).test(r)}catch{return console.warn(`[testrelic] Invalid URL filter pattern: ${String(t)}`),false}}function U(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 J=["get","post","put","patch","delete","head","fetch"],G=["text/","application/json","application/xml","application/javascript","application/x-www-form-urlencoded","application/graphql"],W="__testrelic_api_calls";function Y(r){let t=r.toLowerCase();return G.some(e=>t.includes(e))}function $(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 J){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:W,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 i=s();return T.set(i,e),i};let l=t.headersArray.bind(t);t.headersArray=function(){let i=l();return T.set(i,e),i};let d=t.json.bind(t);t.json=async function(){let i=await d();return i!=null&&typeof i=="object"&&T.set(i,e),i};let c=t.status.bind(t);t.status=function(){let i=c();return n.primitiveCallIds.set(i,e),i};let a=t.statusText.bind(t);t.statusText=function(){let i=a();return n.primitiveCallIds.set(i,e),i};let u=t.ok.bind(t);t.ok=function(){let i=u();return n.primitiveCallIds.set(i,e),i};let o=t.text.bind(t);t.text=async function(){let i=await o();return n.primitiveCallIds.set(i,e),i};let g=t.body.bind(t);t.body=async function(){let i=await g();return T.set(i,e),i};}createWrapper(t,e){let n=this;return async function(l,d){if(!O(l,n.apiConfig.apiIncludeUrls,n.apiConfig.apiExcludeUrls))return e(l,d);let c=`api-call-${n.callCounter++}`,a=new Date().toISOString(),u=t==="fetch"?(d?.method??"GET").toUpperCase():t.toUpperCase(),o=$(d),g=perf_hooks.performance.now();n._lastCallId=c,n.assertionTracker&&n.assertionTracker.setCurrentCallId(c);let p;try{p=await e(l,d);}catch(i){let m=perf_hooks.performance.now();try{let w=n.apiConfig.captureRequestBody?v(o,n.apiConfig.redactBodyFields):null,R={id:c,timestamp:a,method:u,url:l,requestHeaders:null,requestBody:w,responseStatusCode:null,responseStatusText:null,responseHeaders:null,responseBody:null,responseTimeMs:Math.round((m-g)*100)/100,isBinary:!1,error:i instanceof Error?i.message:String(i)};n.capturedCalls.push(R);}catch{}throw i}try{let i=perf_hooks.performance.now(),m=p.headers(),w=m["content-type"]??null,R=w?!Y(w):!1,f=null;n.apiConfig.captureRequestHeaders&&d?.headers&&(f=d.headers);let h=null;n.apiConfig.captureResponseHeaders&&(h=m);let k=n.apiConfig.captureRequestBody?o:null,y=null;if(n.apiConfig.captureResponseBody)try{R?y=(await p.body()).toString("base64"):y=await p.text();}catch{}f=x(f,n.apiConfig.redactHeaders),h=x(h,n.apiConfig.redactHeaders),k=v(k,n.apiConfig.redactBodyFields),y=v(y,n.apiConfig.redactBodyFields);let b={id:c,timestamp:a,method:u,url:p.url(),requestHeaders:f,requestBody:k,responseStatusCode:p.status(),responseStatusText:p.statusText(),responseHeaders:h,responseBody:y,responseTimeMs:Math.round((i-g)*100)/100,isBinary:R,error:null};n.capturedCalls.push(b);}catch{}try{p[P]=c,n.tagResponseMethods(p,c);}catch{}return p}}};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 z=["text/","application/json","application/xml","application/javascript","application/x-www-form-urlencoded","application/graphql"];function X(r){let t=r.toLowerCase();return z.some(e=>t.includes(e))}function D(r,t){let e=new TextEncoder().encode(r);return e.length<=t?{text:r,truncated:false}:{text:new TextDecoder().decode(e.slice(0,t)),truncated:true}}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.requestCaptureCount=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=[],this.requestCaptureCount=0;}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 a=JSON.parse(c.slice(16));a.type&&a.url&&this.recordNavigation(a.url,a.type);}catch{}return}{let a=null;try{let o=l.location();o&&o.url&&(a=`${o.url}:${o.lineNumber}:${o.columnNumber}`);}catch{}let u=r.mapConsoleType(d);this.consoleLogs.push({level:u,text:c,timestamp:new Date().toISOString(),location:a});}}catch{}};if(this.page.on("console",n),this.listeners.push({event:"console",handler:n}),this.includeNetworkStats){let s=c=>{if(this.currentNetworkCounter&&this.currentNetworkCounter.totalRequests++,!(this.requestCaptureCount>=500)){this.requestCaptureCount++;try{let a=c,u=String(this.requestIdCounter++),o=a.postData()??null,g=!1;if(o!==null){let i=D(o,10240);o=i.text,g=i.truncated;}let p={url:a.url(),method:a.method(),resourceType:this.mapResourceType(a.resourceType()),headers:a.headers(),postData:o,postDataTruncated:g,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 a=c;if(this.currentNetworkCounter){let f=a.status();f>=400&&(this.currentNetworkCounter.failedRequests++,this.currentNetworkCounter.failedRequestUrls.push(f+" "+a.url()));let h=a.headers()["content-length"];h&&(this.currentNetworkCounter.totalBytes+=parseInt(h,10)||0);let k=a.request().resourceType(),y=this.mapResourceType(k);this.currentNetworkCounter.byType[y]++;}let u=a.request().__testrelic_id;if(!u)return;let o=this.pendingRequests.get(u);if(!o)return;this.pendingRequests.delete(u);let g=Date.now()-o.startTimeMs,p=a.headers(),i=p["content-type"]??null,m=parseInt(p["content-length"]??"0",10)||0,w=i?!X(i):!1,R=(async()=>{let f=null,h=!1;if(!w)try{let b=(await a.body()).toString("utf-8"),S=D(b,10240);f=S.text,h=S.truncated;}catch{}let k={url:o.url,method:o.method,resourceType:o.resourceType,statusCode:a.status(),responseTimeMs:g,startedAt:o.startedAt,requestHeaders:o.headers,requestBody:o.postData,responseBody:f,responseHeaders:p,contentType:i,responseSize:m,requestBodyTruncated:o.postDataTruncated,responseBodyTruncated:h,isBinary:w,error:null};this.capturedRequests.push(k);})();this.pendingBodyReads.push(R);}catch{}};this.page.on("response",l),this.listeners.push({event:"response",handler:l});let d=c=>{if(this.currentNetworkCounter){this.currentNetworkCounter.failedRequests++;try{let a=c;this.currentNetworkCounter.failedRequestUrls.push("ERR "+a.url());}catch{}}try{let a=c,u=a.__testrelic_id;if(!u)return;let o=this.pendingRequests.get(u);if(!o)return;this.pendingRequests.delete(u);let g={url:o.url,method:o.method,resourceType:o.resourceType,statusCode:0,responseTimeMs:Date.now()-o.startTimeMs,startedAt:o.startedAt,requestHeaders:o.headers,requestBody:o.postData,responseBody:null,responseHeaders:null,contentType:null,responseSize:0,requestBodyTruncated:o.postDataTruncated,responseBodyTruncated:!1,isBinary:!1,error:a.failure()?.errorText??"Unknown error"};this.capturedRequests.push(g);}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 V="__testrelic_api_config",Z="__testrelic_config_trackApiCalls";function I(r){let t=r.annotations.find(n=>n.type===V&&n.description!==void 0);if(t)try{return JSON.parse(t.description,Q)}catch{}let e=r.annotations.find(n=>n.type===Z&&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 Q(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 tt={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=I(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():[],a={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:[],networkRequests:[],apiCalls:d,apiAssertions:c,consoleLogs:[]};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(a)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}try{l.flushLegacyAnnotations(e);}catch{}try{s.flushLegacyAnnotations(e);}catch{}l.dispose(),s.dispose();}};test.test.extend(tt);var St={request:async({request:r},t,e)=>{let n=I(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,a=process.stderr.write;process.stdout.write=function(u,...o){try{let g=typeof u=="string"?u:Buffer.isBuffer(u)?u.toString("utf-8"):String(u);!g.startsWith("[testrelic]")&&!g.startsWith("\u2139 TestRelic")&&!g.startsWith("\u2713 TestRelic")&&!g.startsWith("\u26A0 TestRelic")&&d.push({level:"stdout",text:g.replace(/\n$/,""),timestamp:new Date().toISOString(),location:null});}catch{}return c.apply(process.stdout,[u,...o])},process.stderr.write=function(u,...o){try{let g=typeof u=="string"?u:Buffer.isBuffer(u)?u.toString("utf-8"):String(u);!g.startsWith("[testrelic]")&&!g.startsWith("\u26A0 TestRelic")&&d.push({level:"stderr",text:g.replace(/\n$/,""),timestamp:new Date().toISOString(),location:null});}catch{}return a.apply(process.stderr,[u,...o])};try{await t(r);}finally{process.stdout.write=c,process.stderr.write=a;}try{let u=l.getData(),o=n.captureAssertions?s.getData():[],g={testRelicData:!0,version:core.PAYLOAD_VERSION,navigations:[],networkRequests:[],apiCalls:u,apiAssertions:o,consoleLogs:d};await e.attach(core.ATTACHMENT_NAME,{body:Buffer.from(JSON.stringify(g)),contentType:core.ATTACHMENT_CONTENT_TYPE});}catch{}try{l.flushLegacyAnnotations(e);}catch{}try{s.flushLegacyAnnotations(e);}catch{}l.dispose(),s.dispose();}};exports.testRelicApiFixture=St;//# sourceMappingURL=api-fixture.cjs.map
|
|
2
2
|
//# sourceMappingURL=api-fixture.cjs.map
|