@appsurify-testmap/rrweb-playwright-plugin 3.5.0-alpha.1 → 3.10.0-alpha.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.js +131 -40
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +131 -40
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var P=Object.create;var f=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var F=Object.getPrototypeOf,U=Object.prototype.hasOwnProperty;var z=(t,e)=>{for(var n in e)f(t,n,{get:e[n],enumerable:!0})},$=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of L(e))!U.call(t,s)&&s!==n&&f(t,s,{get:()=>e[s],enumerable:!(r=D(e,s))||r.enumerable});return t};var b=(t,e,n)=>(n=t!=null?P(F(t)):{},$(e||!t||!t.__esModule?f(n,"default",{value:t,enumerable:!0}):n,t)),B=t=>$(f({},"__esModule",{value:!0}),t);var q={};z(q,{expect:()=>y.expect,test:()=>k});module.exports=B(q);var y=require("@playwright/test");var w=b(require("os")),p=b(require("path")),
|
|
1
|
+
"use strict";var P=Object.create;var f=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var F=Object.getPrototypeOf,U=Object.prototype.hasOwnProperty;var z=(t,e)=>{for(var n in e)f(t,n,{get:e[n],enumerable:!0})},$=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of L(e))!U.call(t,s)&&s!==n&&f(t,s,{get:()=>e[s],enumerable:!(r=D(e,s))||r.enumerable});return t};var b=(t,e,n)=>(n=t!=null?P(F(t)):{},$(e||!t||!t.__esModule?f(n,"default",{value:t,enumerable:!0}):n,t)),B=t=>$(f({},"__esModule",{value:!0}),t);var q={};z(q,{expect:()=>y.expect,test:()=>k});module.exports=B(q);var y=require("@playwright/test");var w=b(require("os")),p=b(require("path")),u=b(require("fs")),W="test-results/playwright/ui",C=!1;function j(t,e){let n=p.default.dirname(t),r=p.default.join(n,`.${p.default.basename(t)}.tmp-${process.pid}-${Date.now()}`);u.default.mkdirSync(n,{recursive:!0}),u.default.writeFileSync(r,e,"utf-8"),u.default.renameSync(r,t)}function V(t){try{if(!u.default.existsSync(t))return[];let e=u.default.readFileSync(t,"utf-8").trim();if(!e)return[];let n=JSON.parse(e);return Array.isArray(n)?n:[]}catch{return[]}}function _(t,e){let n=e!==void 0?e:W,r=v(t.spec.name),s=v(t.test.suite?.title),o=v(t.test.title),i=t.browser.name,c=`${s?s+"-":""}${o}.json`,d=p.default.join(n,r,i,c),h={events:t.recorderEvents,metadata:{runner:t.runner,spec:t.spec,suite:t.test.suite,test:t.test,browser:t.browser}};u.default.mkdirSync(n,{recursive:!0}),u.default.mkdirSync(p.default.dirname(d),{recursive:!0}),u.default.writeFileSync(d,JSON.stringify(h,null,2),"utf-8"),console.log(`[ui-coverage] Saved report to ${d}`);try{let a=p.default.join(n,"ui-coverage-aggregated.json"),l=C?V(a):[];C=!0,l.push(h),j(a,JSON.stringify(l,null,2)),console.log(`[ui-coverage] Updated aggregate: ${a}`)}catch(a){console.warn("[ui-coverage] Failed to update aggregate report:",a)}}function v(t){return(t??"").trim().replace(/[\s:/\\<>|"'?*]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function E(t,e){let n=t.browserType(),r=t.version(),s=n.name(),o=e.file,i=o.replace(process.cwd(),"").replace(/^[/\\]/,""),c=i.split(/[\\/]/).pop()??"",[d,h]=c.split(/\.(?=[^\\.]+$)/),a=e.titlePath.slice(1,-1),l=a.join(" > ")||"Root Suite";return{runner:{source:"playwright",type:"unknown",version:e.config.version,platform:w.default.platform(),arch:w.default.arch(),recorder:{scriptVersion:"unknown",libVersion:"unknown"}},spec:{name:c,relative:i,absolute:o,baseName:c,fileName:d,fileExtension:h,id:i},test:{suite:{id:a.join("::")||"root",invocationDetails:{absoluteFile:o,column:e.column??0,line:e.line??0,fileUrl:void 0,function:void 0,originalFile:void 0,relativeFile:i},pending:!1,root:a.length===0,title:l,type:"unknown"},id:e.testId,title:e.title,titlePath:e.titlePath.slice(1),fullTitle:e.titlePath.slice(1).join(" "),file:e.file,invocationDetails:{absoluteFile:o,column:e.column,line:e.line,fileUrl:"",relativeFile:i},state:e.status,duration:e.duration,pending:!1,sync:!1,timedOut:void 0,type:""},browser:{name:s,family:s,version:r,majorVersion:parseInt(r.split(".")[0],10),displayName:e.project.use?.channel?.toUpperCase?.()??s.charAt(0).toUpperCase()+s.slice(1),channel:e.project.use?.channel??"",path:n.executablePath()},recorderEvents:[]}}function S(t,e){let n={...t};for(let r in e){let s=e[r],o=t[r];s&&typeof s=="object"&&!Array.isArray(s)&&o&&typeof o=="object"&&!Array.isArray(o)?n[r]=S(o,s):s!==void 0&&(n[r]=s)}return n}async function I(t,e=500){let n=Date.now(),r=t.getEvents().length;return new Promise(s=>{let o=setInterval(()=>{let i=t.getEvents().length;(i===r||Date.now()-n>e)&&(clearInterval(o),s()),r=i},50)})}async function R(t){await t.evaluate(()=>new Promise(e=>requestAnimationFrame(()=>e())))}var H={i8:Int8Array,ui8:Uint8Array,ui8c:Uint8ClampedArray,i16:Int16Array,ui16:Uint16Array,i32:Int32Array,ui32:Uint32Array,f32:Float32Array,f64:Float64Array,bi64:BigInt64Array,bui64:BigUint64Array},J=new Map(Object.entries(H).map(([t,e])=>[e,t]));var T=`(function (g, f) {if ("object" == typeof exports && "object" == typeof module) {module.exports = f();} else if ("function" == typeof define && define.amd) {define("rrweb", [], f);} else if ("object" == typeof exports) {exports["rrweb"] = f();} else {g["rrweb"] = f();}}(typeof self !== 'undefined' ? self : typeof globalThis !== 'undefined' ? globalThis : this, () => {var exports = {};var module = { exports };
|
|
2
2
|
"use strict";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __defProps = Object.defineProperties;
|
|
@@ -14367,7 +14367,8 @@ function initInputObserver({
|
|
|
14367
14367
|
maskInputOptions,
|
|
14368
14368
|
maskInputFn,
|
|
14369
14369
|
sampling,
|
|
14370
|
-
userTriggeredOnInput
|
|
14370
|
+
userTriggeredOnInput,
|
|
14371
|
+
trustSyntheticInput
|
|
14371
14372
|
}) {
|
|
14372
14373
|
function eventHandler(event) {
|
|
14373
14374
|
let target = getEventTarget(event);
|
|
@@ -14417,34 +14418,53 @@ function initInputObserver({
|
|
|
14417
14418
|
function cbWithDedup(target, v2) {
|
|
14418
14419
|
const lastInputValue = lastInputValueMap.get(target);
|
|
14419
14420
|
const el = target;
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
|
|
14428
|
-
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
|
|
14433
|
-
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
|
|
14437
|
-
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
|
|
14443
|
-
|
|
14444
|
-
|
|
14445
|
-
|
|
14446
|
-
|
|
14447
|
-
|
|
14421
|
+
if (trustSyntheticInput) {
|
|
14422
|
+
const isInitialEmpty = !v2.userTriggered && el.value === "" && !v2.isChecked && !lastInputValue;
|
|
14423
|
+
const isSelectDefaultSelection = el.tagName === "SELECT" && !v2.userTriggered && !lastInputValue && el.selectedIndex === 0;
|
|
14424
|
+
if (isInitialEmpty || isSelectDefaultSelection) {
|
|
14425
|
+
console.debug(
|
|
14426
|
+
\`[\${nowTimestamp()}] [rrweb:record/observer] phantom input ignored (trust mode)\`,
|
|
14427
|
+
{
|
|
14428
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
|
|
14429
|
+
node: index.describeNode(el),
|
|
14430
|
+
tag: el.tagName,
|
|
14431
|
+
value: el.value,
|
|
14432
|
+
isInitialEmpty,
|
|
14433
|
+
isSelectDefaultSelection
|
|
14434
|
+
}
|
|
14435
|
+
);
|
|
14436
|
+
return;
|
|
14437
|
+
}
|
|
14438
|
+
} else {
|
|
14439
|
+
const hasPlaceholder = el.hasAttribute("placeholder");
|
|
14440
|
+
const isEmpty = el.value === "";
|
|
14441
|
+
const isDefaultEmpty = typeof el.defaultValue === "string" ? el.defaultValue === "" : true;
|
|
14442
|
+
const isNonUser = !v2.userTriggered;
|
|
14443
|
+
const isRepeatEmpty = !lastInputValue || lastInputValue.text === "";
|
|
14444
|
+
const isLikelyPhantom = hasPlaceholder && isEmpty && isDefaultEmpty && isRepeatEmpty && isNonUser && !v2.isChecked && el.type !== "hidden" && INPUT_TAGS.includes(el.tagName);
|
|
14445
|
+
const isRenderDrivenTextInput = el.tagName === "INPUT" && el.type === "text" && !v2.userTriggered && v2.text === el.defaultValue && !lastInputValue && el.hasAttribute("placeholder");
|
|
14446
|
+
const isValueFromDefault = !v2.userTriggered && el.value === el.defaultValue && !lastInputValue && el.hasAttribute("placeholder") && !v2.isChecked && el.type !== "hidden" && INPUT_TAGS.includes(el.tagName);
|
|
14447
|
+
const isPhantomCheckbox = el.type === "checkbox" && !v2.userTriggered && !v2.isChecked && !lastInputValue;
|
|
14448
|
+
const isPhantomRadio = el.type === "radio" && !v2.userTriggered && !v2.isChecked && !lastInputValue;
|
|
14449
|
+
if (isLikelyPhantom || isRenderDrivenTextInput || isValueFromDefault || isPhantomCheckbox || isPhantomRadio) {
|
|
14450
|
+
console.debug(
|
|
14451
|
+
\`[\${nowTimestamp()}] [rrweb:record/observer] \\u26D4 phantom input ignored\`,
|
|
14452
|
+
{
|
|
14453
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
|
|
14454
|
+
node: index.describeNode(el),
|
|
14455
|
+
tag: el.tagName,
|
|
14456
|
+
nodeType: el.nodeType,
|
|
14457
|
+
attribute: el.attributes,
|
|
14458
|
+
value: el.value,
|
|
14459
|
+
isLikelyPhantom,
|
|
14460
|
+
isRenderDrivenTextInput,
|
|
14461
|
+
isValueFromDefault,
|
|
14462
|
+
isPhantomCheckbox,
|
|
14463
|
+
isPhantomRadio
|
|
14464
|
+
}
|
|
14465
|
+
);
|
|
14466
|
+
return;
|
|
14467
|
+
}
|
|
14448
14468
|
}
|
|
14449
14469
|
if (!lastInputValue || lastInputValue.text !== v2.text || lastInputValue.isChecked !== v2.isChecked) {
|
|
14450
14470
|
lastInputValueMap.set(target, v2);
|
|
@@ -16508,8 +16528,15 @@ class NavigationManager {
|
|
|
16508
16528
|
return;
|
|
16509
16529
|
if (this.locked)
|
|
16510
16530
|
return;
|
|
16511
|
-
this.
|
|
16512
|
-
|
|
16531
|
+
if (this.pendingNavigation) {
|
|
16532
|
+
this.cancelTimers();
|
|
16533
|
+
this.disconnectSettlingObserver();
|
|
16534
|
+
this.pendingNavigation = null;
|
|
16535
|
+
this.onSnapshot(true);
|
|
16536
|
+
} else {
|
|
16537
|
+
this.cancelTimers();
|
|
16538
|
+
this.disconnectSettlingObserver();
|
|
16539
|
+
}
|
|
16513
16540
|
this.pendingNavigation = data;
|
|
16514
16541
|
if (this.frozen) {
|
|
16515
16542
|
return;
|
|
@@ -16723,7 +16750,7 @@ class ProcessedNodeManager {
|
|
|
16723
16750
|
destroy() {
|
|
16724
16751
|
}
|
|
16725
16752
|
}
|
|
16726
|
-
const version$1 = "3.
|
|
16753
|
+
const version$1 = "3.10.0-alpha.1";
|
|
16727
16754
|
let wrappedEmit;
|
|
16728
16755
|
let takeFullSnapshot$1;
|
|
16729
16756
|
let canvasManager;
|
|
@@ -16772,6 +16799,7 @@ function record(options = {}) {
|
|
|
16772
16799
|
recordAfter = options.recordAfter === "DOMContentLoaded" ? options.recordAfter : "load",
|
|
16773
16800
|
flushCustomEvent = options.flushCustomEvent !== void 0 ? options.flushCustomEvent : "after",
|
|
16774
16801
|
userTriggeredOnInput = false,
|
|
16802
|
+
trustSyntheticInput = false,
|
|
16775
16803
|
collectFonts = false,
|
|
16776
16804
|
inlineImages = false,
|
|
16777
16805
|
plugins,
|
|
@@ -16846,6 +16874,11 @@ function record(options = {}) {
|
|
|
16846
16874
|
let checkoutPending = false;
|
|
16847
16875
|
let checkoutDebounceTimer = null;
|
|
16848
16876
|
let checkoutFreezeTimestamp = null;
|
|
16877
|
+
let lastScrollEmitTime = 0;
|
|
16878
|
+
const scrollSettleTime = (sampling.scroll || 100) * 2;
|
|
16879
|
+
let lastSignificantMutationTime = 0;
|
|
16880
|
+
const mutationGracePeriod = 500;
|
|
16881
|
+
let hadVisibilityCheckoutInGrace = false;
|
|
16849
16882
|
const eventProcessor = (e2) => {
|
|
16850
16883
|
for (const plugin3 of plugins || []) {
|
|
16851
16884
|
if (plugin3.eventProcessor) {
|
|
@@ -16936,6 +16969,13 @@ function record(options = {}) {
|
|
|
16936
16969
|
}
|
|
16937
16970
|
};
|
|
16938
16971
|
const wrappedMutationEmit = (m) => {
|
|
16972
|
+
var _a3, _b2;
|
|
16973
|
+
var _a2, _b;
|
|
16974
|
+
const totalChanges = ((_a3 = (_a2 = m.adds) == null ? void 0 : _a2.length) != null ? _a3 : 0) + ((_b2 = (_b = m.removes) == null ? void 0 : _b.length) != null ? _b2 : 0);
|
|
16975
|
+
if (totalChanges > 10) {
|
|
16976
|
+
lastSignificantMutationTime = nowTimestamp();
|
|
16977
|
+
hadVisibilityCheckoutInGrace = false;
|
|
16978
|
+
}
|
|
16939
16979
|
wrappedEmit({
|
|
16940
16980
|
type: EventType.IncrementalSnapshot,
|
|
16941
16981
|
data: __spreadValues({
|
|
@@ -16951,12 +16991,15 @@ function record(options = {}) {
|
|
|
16951
16991
|
}, v2)
|
|
16952
16992
|
});
|
|
16953
16993
|
};
|
|
16954
|
-
const wrappedScrollEmit = (p) =>
|
|
16955
|
-
|
|
16956
|
-
|
|
16957
|
-
|
|
16958
|
-
|
|
16959
|
-
|
|
16994
|
+
const wrappedScrollEmit = (p) => {
|
|
16995
|
+
lastScrollEmitTime = nowTimestamp();
|
|
16996
|
+
wrappedEmit({
|
|
16997
|
+
type: EventType.IncrementalSnapshot,
|
|
16998
|
+
data: __spreadValues({
|
|
16999
|
+
source: IncrementalSource.Scroll
|
|
17000
|
+
}, p)
|
|
17001
|
+
});
|
|
17002
|
+
};
|
|
16960
17003
|
const wrappedCanvasMutationEmit = (p) => wrappedEmit({
|
|
16961
17004
|
type: EventType.IncrementalSnapshot,
|
|
16962
17005
|
data: __spreadValues({
|
|
@@ -17038,9 +17081,19 @@ function record(options = {}) {
|
|
|
17038
17081
|
mutationCb: recordVisibility ? wrappedVisibilityEmit : () => {
|
|
17039
17082
|
},
|
|
17040
17083
|
notifyActivity: checkoutEveryNvm != null ? (count) => {
|
|
17084
|
+
const now = nowTimestamp();
|
|
17085
|
+
const scrollRecent = now - lastScrollEmitTime < scrollSettleTime;
|
|
17086
|
+
const mutationRecent = now - lastSignificantMutationTime < mutationGracePeriod;
|
|
17087
|
+
if (scrollRecent && !mutationRecent) {
|
|
17088
|
+
return;
|
|
17089
|
+
}
|
|
17090
|
+
if (mutationRecent && hadVisibilityCheckoutInGrace) {
|
|
17091
|
+
return;
|
|
17092
|
+
}
|
|
17041
17093
|
visibilityMutationCount += count;
|
|
17042
17094
|
if (visibilityMutationCount >= checkoutEveryNvm) {
|
|
17043
17095
|
visibilityMutationCount = 0;
|
|
17096
|
+
hadVisibilityCheckoutInGrace = true;
|
|
17044
17097
|
if (checkoutDebounce) {
|
|
17045
17098
|
if (!checkoutPending) {
|
|
17046
17099
|
checkoutPending = true;
|
|
@@ -17273,6 +17326,7 @@ function record(options = {}) {
|
|
|
17273
17326
|
recordCanvas,
|
|
17274
17327
|
inlineImages,
|
|
17275
17328
|
userTriggeredOnInput,
|
|
17329
|
+
trustSyntheticInput,
|
|
17276
17330
|
collectFonts,
|
|
17277
17331
|
doc,
|
|
17278
17332
|
maskInputFn,
|
|
@@ -17351,6 +17405,43 @@ function record(options = {}) {
|
|
|
17351
17405
|
);
|
|
17352
17406
|
}
|
|
17353
17407
|
return () => {
|
|
17408
|
+
if (recording) {
|
|
17409
|
+
const activeEl = document.activeElement;
|
|
17410
|
+
if (activeEl && INPUT_TAGS.includes(activeEl.tagName)) {
|
|
17411
|
+
const inputEl = activeEl;
|
|
17412
|
+
const id = mirror.getId(inputEl);
|
|
17413
|
+
if (id !== -1) {
|
|
17414
|
+
const lastValue = lastInputValueMap.get(inputEl);
|
|
17415
|
+
let text = inputEl.value;
|
|
17416
|
+
let isChecked = false;
|
|
17417
|
+
const type = getInputType(inputEl) || "";
|
|
17418
|
+
if (type === "radio" || type === "checkbox") {
|
|
17419
|
+
isChecked = inputEl.checked;
|
|
17420
|
+
} else if (maskInputOptions[inputEl.tagName.toLowerCase()] || maskInputOptions[type]) {
|
|
17421
|
+
text = maskInputValue({
|
|
17422
|
+
element: inputEl,
|
|
17423
|
+
maskInputOptions,
|
|
17424
|
+
tagName: inputEl.tagName,
|
|
17425
|
+
type,
|
|
17426
|
+
value: text,
|
|
17427
|
+
maskInputFn
|
|
17428
|
+
});
|
|
17429
|
+
}
|
|
17430
|
+
if (!lastValue || lastValue.text !== text || lastValue.isChecked !== isChecked) {
|
|
17431
|
+
const inputData = userTriggeredOnInput ? { text, isChecked, userTriggered: false } : { text, isChecked };
|
|
17432
|
+
lastInputValueMap.set(inputEl, inputData);
|
|
17433
|
+
wrappedEmit({
|
|
17434
|
+
type: EventType.IncrementalSnapshot,
|
|
17435
|
+
data: __spreadProps(__spreadValues({
|
|
17436
|
+
source: IncrementalSource.Input
|
|
17437
|
+
}, inputData), {
|
|
17438
|
+
id
|
|
17439
|
+
})
|
|
17440
|
+
});
|
|
17441
|
+
}
|
|
17442
|
+
}
|
|
17443
|
+
}
|
|
17444
|
+
}
|
|
17354
17445
|
if (checkoutDebounceTimer) {
|
|
17355
17446
|
clearTimeout(checkoutDebounceTimer);
|
|
17356
17447
|
checkoutDebounceTimer = null;
|
|
@@ -17470,5 +17561,5 @@ exports.globalSequentialId = globalSequentialId;
|
|
|
17470
17561
|
return module.exports;
|
|
17471
17562
|
}))
|
|
17472
17563
|
//# sourceMappingURL=rrweb-plugin-sequential-id-record.umd.cjs.map
|
|
17473
|
-
`;var Y={slimDOMOptions:"all",inlineStylesheet:!0,recordDOM:!0,recordCanvas:!0,collectFonts:!0,inlineImages:!0,checkoutEveryNvm:60,maskInputOptions:{password:!0},sampling:{mousemove:!1,mouseInteraction:{MouseUp:!1,MouseDown:!1,Click:!0,ContextMenu:!0,DblClick:!0,Focus:!1,Blur:!1,TouchStart:!1,TouchEnd:!1},scroll:100,media:100,input:"last",canvas:"all",visibility:{mode:"none",debounce:50,throttle:100,threshold:.5,sensitivity:.05,rafThrottle:100}},flushCustomEvent:"after",recordAfter:"DOMContentLoaded",userTriggeredOnInput:!0},m=class{recordFn=null;page=null;context;eventCounter=0;events=[];recordOptions;pendingEvents=[];recorderScriptVersion="unknown";recorderLibVersion="unknown";isRecording=!1;constructor(e){this.recordOptions=S(Y,e??{}),this.context={pushEvent:n=>this.events.push(n)}}handleEmit(e){if(e.type===0||e.type===1)return;let n={...e};this.context.pushEvent(n)}async inject(e){this.page=e,await this.page?.addInitScript({content:T}),await this.page?.addInitScript({content:A}),await this.page?.exposeFunction("handleEmit",n=>{this.handleEmit(n)})}async start(){this.recordFn=await this.page?.evaluateHandle(()=>window.rrweb?.record),await this.recordFn?.evaluate((e,n)=>{let r=JSON.parse(n),s=[];window.rrwebPluginSequentialIdRecord&&s.push(window.rrwebPluginSequentialIdRecord.getRecordSequentialIdPlugin({key:"id"})),window.stopFn=e({emit:o=>{window.handleEmit?.(o)},plugins:s,...r})},JSON.stringify(this.recordOptions)),this.isRecording=await this.recordFn?.evaluate(e=>e.isRecording()),this.recorderScriptVersion=await this.recordFn?.evaluate(e=>e.getVersion()),await this.flush()}async stop(){this.isRecording=!1,this.recordFn&&this.page&&!this.page.isClosed()&&(await this.flush(),await this.page.evaluate(()=>{window.stopFn=null}))}async reset(){this.eventCounter=0,this.events=[],await this.stop(),this.context={pushEvent:e=>this.events.push(e)}}async flush(){if(!this.recordFn)return;let e=[];for(let n of this.pendingEvents)try{await this.recordFn.evaluate((r,s)=>{r.addCustomEvent(s.tag,s.payload)},n)}catch{console.debug(`[${Date.now()}] [recorder] flush failed for custom event: ${n.tag}`),e.push(n)}this.pendingEvents=e}async addCustomEvent(e,n){let r={tag:e,payload:n};if(!this.recordFn||!this.isRecording){console.debug(`[${Date.now()}] [recorder] queued custom event (recorder not ready): ${e}`),this.pendingEvents.push(r);return}try{await this.recordFn.evaluate((s,o)=>{s.addCustomEvent(o.tag,o.payload)},r)}catch{this.pendingEvents.push(r)}}isRecordingReady(){return!!this.recordFn&&this.isRecording}getScriptVersion(){return`@appsurify-testmap/rrweb-record:${this.recorderScriptVersion}`}getLibVersion(){return`@appsurify-testmap/rrweb:${this.recorderLibVersion!=="unknown"?this.recorderLibVersion:this.recorderScriptVersion}`}getEvents(){return this.events}getMirror(){return this.recordFn?.mirror}bind(e){this.context=e}setEventCounter(e){this.eventCounter=e}};var g=m;var M=new Map;function N(t,e){M.set(t,e)}function x(t){return M.get(t)}var k=y.test.extend({browser:async({browser:t},e)=>{await e(t)},context:async({browser:t},e,n)=>{let r=await t.newContext(),s=E(t,n);N(n.testId,s),await e(r),await r.close()},page:async({page:t},e,n)=>{let s=n.project.use.testmap??{},o=typeof s=="object"&&"recordingOpts"in s?s.recordingOpts:g,i=new g(o),c=x(n.testId);c&&(c.recorderInstance=i),i.bind({pushEvent:async a=>{c?.recorderEvents.push(a),await Promise.resolve()}}),await i.inject(t),t.on("console",async a=>{a.type()!=="debug"&&console.debug(`[${Date.now()}] [page] console`,a.text())}),t.on("load",async()=>{}),t.on("domcontentloaded",async()=>{await i.start(),c?.runner&&(c.runner.recorder={scriptVersion:i.getScriptVersion(),libVersion:i.getLibVersion()})}),t.on("framenavigated",async()=>{}),t.on("close",async()=>{await i.flush()});let
|
|
17564
|
+
`;var Y={slimDOMOptions:"all",inlineStylesheet:!0,recordDOM:!0,recordCanvas:!0,collectFonts:!0,inlineImages:!0,checkoutEveryNvm:60,maskInputOptions:{password:!0},sampling:{mousemove:!1,mouseInteraction:{MouseUp:!1,MouseDown:!1,Click:!0,ContextMenu:!0,DblClick:!0,Focus:!1,Blur:!1,TouchStart:!1,TouchEnd:!1},scroll:100,media:100,input:"last",canvas:"all",visibility:{mode:"none",debounce:50,throttle:100,threshold:.5,sensitivity:.05,rafThrottle:100}},flushCustomEvent:"after",recordAfter:"DOMContentLoaded",userTriggeredOnInput:!0},m=class{recordFn=null;page=null;context;eventCounter=0;events=[];recordOptions;pendingEvents=[];recorderScriptVersion="unknown";recorderLibVersion="unknown";isRecording=!1;constructor(e){this.recordOptions=S(Y,e??{}),this.context={pushEvent:n=>this.events.push(n)}}handleEmit(e){if(e.type===0||e.type===1)return;let n={...e};this.context.pushEvent(n)}async inject(e){this.page=e,await this.page?.addInitScript({content:T}),await this.page?.addInitScript({content:A}),await this.page?.exposeFunction("handleEmit",n=>{this.handleEmit(n)})}async start(){this.recordFn=await this.page?.evaluateHandle(()=>window.rrweb?.record),await this.recordFn?.evaluate((e,n)=>{let r=JSON.parse(n),s=[];window.rrwebPluginSequentialIdRecord&&s.push(window.rrwebPluginSequentialIdRecord.getRecordSequentialIdPlugin({key:"id"})),window.stopFn=e({emit:o=>{window.handleEmit?.(o)},plugins:s,...r})},JSON.stringify(this.recordOptions)),this.isRecording=await this.recordFn?.evaluate(e=>e.isRecording()),this.recorderScriptVersion=await this.recordFn?.evaluate(e=>e.getVersion()),await this.flush()}async stop(){this.isRecording=!1,this.recordFn&&this.page&&!this.page.isClosed()&&(await this.flush(),await this.page.evaluate(()=>{window.stopFn=null}))}async reset(){this.eventCounter=0,this.events=[],await this.stop(),this.context={pushEvent:e=>this.events.push(e)}}async flush(){if(!this.recordFn)return;let e=[];for(let n of this.pendingEvents)try{await this.recordFn.evaluate((r,s)=>{r.addCustomEvent(s.tag,s.payload)},n)}catch{console.debug(`[${Date.now()}] [recorder] flush failed for custom event: ${n.tag}`),e.push(n)}this.pendingEvents=e}async addCustomEvent(e,n){let r={tag:e,payload:n};if(!this.recordFn||!this.isRecording){console.debug(`[${Date.now()}] [recorder] queued custom event (recorder not ready): ${e}`),this.pendingEvents.push(r);return}try{await this.recordFn.evaluate((s,o)=>{s.addCustomEvent(o.tag,o.payload)},r)}catch{this.pendingEvents.push(r)}}isRecordingReady(){return!!this.recordFn&&this.isRecording}getScriptVersion(){return`@appsurify-testmap/rrweb-record:${this.recorderScriptVersion}`}getLibVersion(){return`@appsurify-testmap/rrweb:${this.recorderLibVersion!=="unknown"?this.recorderLibVersion:this.recorderScriptVersion}`}getEvents(){return this.events}getMirror(){return this.recordFn?.mirror}bind(e){this.context=e}setEventCounter(e){this.eventCounter=e}};var g=m;var M=new Map;function N(t,e){M.set(t,e)}function x(t){return M.get(t)}var k=y.test.extend({browser:async({browser:t},e)=>{await e(t)},context:async({browser:t},e,n)=>{let r=await t.newContext(),s=E(t,n);N(n.testId,s),await e(r),await r.close()},page:async({page:t},e,n)=>{let s=n.project.use.testmap??{},o=typeof s=="object"&&"recordingOpts"in s?s.recordingOpts:g,i=new g(o),c=x(n.testId);c&&(c.recorderInstance=i),i.bind({pushEvent:async a=>{c?.recorderEvents.push(a),await Promise.resolve()}}),await i.inject(t),t.on("console",async a=>{a.type()!=="debug"&&console.debug(`[${Date.now()}] [page] console`,a.text())}),t.on("load",async()=>{}),t.on("domcontentloaded",async()=>{await i.start(),c?.runner&&(c.runner.recorder={scriptVersion:i.getScriptVersion(),libVersion:i.getLibVersion()})}),t.on("framenavigated",async()=>{}),t.on("close",async()=>{await i.flush()});let d=n._onStepEnd.bind(void 0);n._onStepEnd=async a=>{let l=n._stepMap.get(a.stepId);if(l.apiName&&l?.location.file===n.file&&await i.addCustomEvent(l.apiName,{stepId:l.stepId,category:l.category,location:l.location,title:l.title,apiName:l.apiName,endWallTime:l.endWallTime}),!t.isClosed())try{await R(t)}catch{}await d(a)};let h=n._onDidFinishTestFunction.bind(void 0);n._onDidFinishTestFunction=async()=>{i&&i.isRecordingReady()&&(await I(i,500),await i.stop()),await h()},await e(t)}});k.beforeEach(async({},t)=>{console.log(`[${Date.now()}] [\u{1F7E2} TEST START] ${t.title}`)});k.afterEach(async({},t)=>{console.log(`[${Date.now()}] [\u{1F534} TEST END] ${t.title}`);let e=x(t.testId);if(!e)return;e.test.duration=t.duration;let n={runner:e?.runner,spec:e?.spec,browser:e?.browser,test:e?.test,suite:e?.test.suite,recorderEvents:Array.isArray(e?.recorderEvents)?e?.recorderEvents:[]},s=t.project.use.testmap??{};_(n,s.outputReportDir)});0&&(module.exports={expect,test});
|
|
17474
17565
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/recorder/RRWebRecorder.ts","../src/recorder/index.ts","../src/runtime.ts"],"sourcesContent":["import {\n test as base,\n expect,\n} from '@playwright/test';\nimport type {\n ConsoleMessage,\n} from '@playwright/test';\nimport RRWebRecorder from './recorder';\nimport defaultRecordOptions from './recorder';\n\nimport {\n createTestrunContext,\n saveRRWebReport,\n waitForNextRAF,\n waitForRecorderStabilization,\n} from './utils';\nimport {\n getCurrentTestContext,\n setCurrentTestContext,\n} from './runtime';\n\nimport type {\n TestmapConfig\n} from './types';\n\n\nconst test = base.extend<{}>({\n browser: async ({ browser }, use) => {\n await use(browser);\n },\n\n context: async ({ browser }, use, testInfo) => {\n const context = await browser.newContext();\n const testRunContext = createTestrunContext(browser, testInfo);\n setCurrentTestContext(testInfo.testId, testRunContext);\n await use(context);\n await context.close();\n },\n\n page: async ({ page }, use, testInfo) => {\n\n type ExtendedUse = typeof testInfo.project.use & { testmap?: TestmapConfig };\n const pwConfig = testInfo.project.use as ExtendedUse;\n const testmapConfig = pwConfig.testmap ?? {};\n const recordingOpts =\n typeof testmapConfig === 'object' && 'recordingOpts' in testmapConfig\n ? testmapConfig.recordingOpts\n : defaultRecordOptions;\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n // @ts-ignore\n const recorder = new RRWebRecorder(recordingOpts);\n\n const testRunContext = getCurrentTestContext(testInfo.testId);\n if (testRunContext) {\n testRunContext.recorderInstance = recorder;\n }\n\n recorder.bind({\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n pushEvent: async (event) => {\n testRunContext?.recorderEvents.push(event);\n await Promise.resolve();\n },\n });\n await recorder.inject(page);\n\n // eslint-disable-next-line @typescript-eslint/require-await\n page.on('console', async (consoleMessage: ConsoleMessage) => {\n if (consoleMessage.type() === 'debug') return;\n console.debug(`[${Date.now()}] [page] console`, consoleMessage.text());\n });\n\n page.on('load', async () => {\n /* empty */\n });\n\n page.on('domcontentloaded', async () => {\n await recorder.start();\n if (testRunContext?.runner) {\n testRunContext.runner.recorder = {\n scriptVersion: recorder.getScriptVersion(),\n libVersion: recorder.getLibVersion(),\n };\n }\n });\n page.on('framenavigated', async () => {\n /* empty */\n });\n\n page.on('close', async () => {\n await recorder.flush();\n });\n\n // @ts-ignore\n const originalonStepEnd = testInfo._onStepEnd.bind(this);\n // @ts-ignore\n testInfo._onStepEnd = async (stepEndPayload: {\n testId: string;\n stepId: string;\n wallTime: number;\n error?: unknown;\n suggestedRebaseline?: string;\n annotations: { type: string, description?: string }[];\n }) => {\n\n // @ts-ignore\n const currentStepInfo = testInfo._stepMap.get(stepEndPayload.stepId);\n if (currentStepInfo.apiName && currentStepInfo?.location.file === testInfo.file) {\n await recorder.addCustomEvent(currentStepInfo.apiName, {\n stepId: currentStepInfo.stepId,\n category: currentStepInfo.category,\n location: currentStepInfo.location,\n title: currentStepInfo.title,\n apiName: currentStepInfo.apiName,\n endWallTime: currentStepInfo.endWallTime,\n });\n\n }\n if (!page.isClosed()) {\n try {\n await waitForNextRAF(page);\n } catch (error) { /* empty */ }\n }\n await originalonStepEnd(stepEndPayload);\n };\n\n // @ts-ignore\n const originalonDidFinishTestFunction = testInfo._onDidFinishTestFunction.bind(this);\n // @ts-ignore\n testInfo._onDidFinishTestFunction = async () => {\n\n if (recorder && recorder.isRecordingReady()) {\n await waitForRecorderStabilization(recorder, 500);\n await recorder.stop();\n }\n\n await originalonDidFinishTestFunction();\n }\n\n await use(page);\n\n\n },\n});\n\ntest.beforeEach(async ({}, testInfo) => {\n console.log(`[${Date.now()}] [🟢 TEST START] ${testInfo.title}`);\n\n});\n\ntest.afterEach(async ({}, testInfo) => {\n console.log(`[${Date.now()}] [🔴 TEST END] ${testInfo.title}`);\n const testRunContext = getCurrentTestContext(testInfo.testId);\n if (!testRunContext) return;\n\n testRunContext.test.duration = testInfo.duration;\n const testRunResult = {\n runner: testRunContext?.runner,\n spec: testRunContext?.spec,\n browser: testRunContext?.browser,\n test: testRunContext?.test,\n suite: testRunContext?.test.suite,\n recorderEvents: Array.isArray(testRunContext?.recorderEvents) ? testRunContext?.recorderEvents : []\n }\n\n type ExtendedUse = typeof testInfo.project.use & { testmap?: TestmapConfig };\n const pwConfig = testInfo.project.use as ExtendedUse;\n const testmapConfig = pwConfig.testmap ?? {};\n\n saveRRWebReport(testRunResult, testmapConfig.outputReportDir)\n\n});\n\nexport { test, expect };\n\n","import os from 'os';\nimport path from 'path';\nimport fs from 'fs';\nimport { Browser, Page, Frame, TestInfo } from '@playwright/test';\nimport type { RecorderEvent } from './recorder/types';\nimport type { TestRunContext, TestRunResult, SerializedValue } from './types';\nimport RRWebRecorder from \"./recorder\";\n\nconst defaultOutputReportDir = 'test-results/playwright/ui';\n\n// Tracks whether the aggregate report has been cleared in this process.\n// Ensures the file is reset once per test run (process lifetime).\nlet aggregateCleared = false;\n\nfunction writeFileAtomic(filePath: string, data: string) {\n const dir = path.dirname(filePath);\n const tmp = path.join(dir, `.${path.basename(filePath)}.tmp-${process.pid}-${Date.now()}`);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(tmp, data, 'utf-8');\n fs.renameSync(tmp, filePath);\n}\n\nfunction readJsonArraySafe(filePath: string): unknown[] {\n try {\n if (!fs.existsSync(filePath)) return [];\n const text = fs.readFileSync(filePath, 'utf-8').trim();\n if (!text) return [];\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const parsed = JSON.parse(text);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nexport function saveRRWebReport(testRunResult: TestRunResult, outputReportDir?: string) {\n const reportDir = outputReportDir !== undefined ? outputReportDir : defaultOutputReportDir;\n const specName = sanitizeFileNamePart(testRunResult.spec.name);\n const suiteTitle = sanitizeFileNamePart(testRunResult.test.suite?.title);\n const testTitle = sanitizeFileNamePart(testRunResult.test.title);\n const browserName = testRunResult.browser.name;\n\n const jsonFileNameRaw = `${suiteTitle ? suiteTitle + '-' : ''}${testTitle}.json`;\n const jsonFilePathRaw = path.join(reportDir, specName, browserName, jsonFileNameRaw);\n const reportRaw = {\n events: testRunResult.recorderEvents,\n metadata: {\n runner: testRunResult.runner,\n spec: testRunResult.spec,\n suite: testRunResult.test.suite,\n test: testRunResult.test,\n browser: testRunResult.browser,\n }\n };\n fs.mkdirSync(reportDir, { recursive: true });\n fs.mkdirSync(path.dirname(jsonFilePathRaw), { recursive: true });\n fs.writeFileSync(jsonFilePathRaw, JSON.stringify(reportRaw, null, 2), 'utf-8');\n console.log(`[ui-coverage] Saved report to ${jsonFilePathRaw}`);\n\n try {\n const aggregatePath = path.join(reportDir, \"ui-coverage-aggregated.json\");\n // On first call in this process, start a fresh aggregate file so it\n // only contains results from the current run.\n const current = aggregateCleared ? readJsonArraySafe(aggregatePath) : [];\n aggregateCleared = true;\n current.push(reportRaw);\n writeFileAtomic(aggregatePath, JSON.stringify(current, null, 2));\n console.log(`[ui-coverage] Updated aggregate: ${aggregatePath}`);\n } catch (e) {\n console.warn('[ui-coverage] Failed to update aggregate report:', e);\n }\n}\n\nexport function sanitizeFileNamePart(name: string | undefined): string {\n return (name ?? '')\n .trim()\n .replace(/[\\s:/\\\\<>|\"'?*]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\nexport function createTestrunContext(browser: Browser, testInfo: TestInfo): TestRunContext {\n const browserType = browser.browserType();\n const version = browser.version();\n const family = browserType.name();\n\n const absolute = testInfo.file;\n const relative = absolute.replace(process.cwd(), '').replace(/^[/\\\\]/, '');\n const baseName = relative.split(/[\\\\/]/).pop() ?? '';\n const [fileName, fileExtension] = baseName.split(/\\.(?=[^\\\\.]+$)/);\n\n const suiteTitlePath = testInfo.titlePath.slice(1, -1); // всё кроме последнего (сам тест)\n const suiteTitle = suiteTitlePath.join(' > ') || 'Root Suite';\n\n const testRunContext: TestRunContext = {\n runner: {\n source: 'playwright',\n type: 'unknown',\n version: testInfo.config.version,\n platform: os.platform(),\n arch: os.arch(),\n recorder: {\n scriptVersion: 'unknown',\n libVersion: 'unknown'\n }\n\n },\n spec: {\n name: baseName,\n relative,\n absolute,\n baseName,\n fileName,\n fileExtension,\n id: relative,\n },\n test: {\n suite: {\n id: suiteTitlePath.join('::') || 'root',\n invocationDetails: {\n absoluteFile: absolute,\n column: testInfo.column ?? 0,\n line: testInfo.line ?? 0,\n fileUrl: undefined,\n function: undefined,\n originalFile: undefined,\n relativeFile: relative,\n },\n pending: false,\n root: suiteTitlePath.length === 0,\n title: suiteTitle,\n type: \"unknown\"\n },\n id: testInfo.testId,\n title: testInfo.title,\n titlePath: testInfo.titlePath.slice(1),\n fullTitle: testInfo.titlePath.slice(1).join(' '),\n file: testInfo.file,\n invocationDetails: {\n absoluteFile: absolute,\n column: testInfo.column,\n line: testInfo.line,\n fileUrl: '',\n relativeFile: relative,\n },\n state: testInfo.status,\n duration: testInfo.duration,\n pending: false,\n sync: false,\n timedOut: undefined,\n type: ''\n },\n browser: {\n name: family,\n family,\n version,\n majorVersion: parseInt(version.split('.')[0], 10),\n displayName: testInfo.project.use?.channel?.toUpperCase?.() ?? family.charAt(0).toUpperCase() + family.slice(1),\n channel: testInfo.project.use?.channel ?? '',\n path: browserType.executablePath(),\n },\n recorderEvents: [] as RecorderEvent[],\n };\n return testRunContext\n}\n\nexport function deepMerge<T>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue &&\n typeof sourceValue === 'object' &&\n !Array.isArray(sourceValue) &&\n targetValue &&\n typeof targetValue === 'object' &&\n !Array.isArray(targetValue)\n ) {\n result[key] = deepMerge(targetValue, sourceValue);\n } else if (sourceValue !== undefined) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n result[key] = sourceValue as unknown;\n }\n }\n\n return result;\n}\n\nexport async function waitForRecorderStabilization(recorder: RRWebRecorder, timeout = 500) {\n const start = Date.now();\n let lastCount = recorder.getEvents().length;\n\n return new Promise<void>((resolve) => {\n const interval = setInterval(() => {\n const currentCount = recorder.getEvents().length;\n if (currentCount === lastCount || Date.now() - start > timeout) {\n clearInterval(interval);\n resolve();\n }\n lastCount = currentCount;\n }, 50);\n });\n}\n\nexport async function waitForNextRAF(page: Page) {\n await page.evaluate(() => new Promise<void>((r) => requestAnimationFrame(() => r())));\n}\n\nexport async function waitForRAF(\n pageOrFrame: Page | Frame,\n) {\n return await pageOrFrame.evaluate(() => {\n return new Promise((resolve) => {\n requestAnimationFrame(() => {\n requestAnimationFrame(resolve);\n });\n });\n });\n}\n\nexport function parseSerializedValue(value: SerializedValue, handles: any[] | undefined): any {\n return innerParseSerializedValue(value, handles, new Map(), []);\n}\n\nfunction innerParseSerializedValue(value: SerializedValue, handles: any[] | undefined, refs: Map<number, object>, accessChain: Array<string | number>): any {\n if (value.ref !== undefined)\n return refs.get(value.ref);\n if (value.n !== undefined)\n return value.n;\n if (value.s !== undefined)\n return value.s;\n if (value.b !== undefined)\n return value.b;\n if (value.v !== undefined) {\n if (value.v === 'undefined')\n return undefined;\n if (value.v === 'null')\n return null;\n if (value.v === 'NaN')\n return NaN;\n if (value.v === 'Infinity')\n return Infinity;\n if (value.v === '-Infinity')\n return -Infinity;\n if (value.v === '-0')\n return -0;\n }\n if (value.d !== undefined)\n return new Date(value.d);\n if (value.u !== undefined)\n return new URL(value.u);\n if (value.bi !== undefined)\n return BigInt(value.bi);\n if (value.e !== undefined) {\n const error = new Error(value.e.m);\n error.name = value.e.n;\n error.stack = value.e.s;\n return error;\n }\n if (value.r !== undefined)\n return new RegExp(value.r.p, value.r.f);\n if (value.ta !== undefined) {\n const ctor = typedArrayKindToConstructor[value.ta.k] as any;\n return new ctor(value.ta.b.buffer, value.ta.b.byteOffset, value.ta.b.length / ctor.BYTES_PER_ELEMENT);\n }\n\n if (value.a !== undefined) {\n const result: any[] = [];\n refs.set(value.id!, result);\n for (let i = 0; i < value.a.length; i++)\n result.push(innerParseSerializedValue(value.a[i], handles, refs, [...accessChain, i]));\n return result;\n }\n if (value.o !== undefined) {\n const result: any = {};\n refs.set(value.id!, result);\n for (const { k, v } of value.o)\n result[k] = innerParseSerializedValue(v, handles, refs, [...accessChain, k]);\n return result;\n }\n if (value.h !== undefined) {\n if (handles === undefined)\n throw new Error('Unexpected handle');\n return handles[value.h];\n }\n throw new Error(`Attempting to deserialize unexpected value${accessChainToDisplayString(accessChain)}: ${value}`);\n}\n\nexport type HandleOrValue = { h: number } | { fallThrough: any };\ntype VisitorInfo = {\n visited: Map<object, number>;\n lastId: number;\n};\n\nexport function serializeValue(value: any, handleSerializer: (value: any) => HandleOrValue): SerializedValue {\n return innerSerializeValue(value, handleSerializer, { lastId: 0, visited: new Map() }, []);\n}\n\nfunction innerSerializeValue(value: any, handleSerializer: (value: any) => HandleOrValue, visitorInfo: VisitorInfo, accessChain: Array<string | number>): SerializedValue {\n const handle = handleSerializer(value);\n if ('fallThrough' in handle)\n value = handle.fallThrough;\n else\n return handle;\n\n if (typeof value === 'symbol')\n return { v: 'undefined' };\n if (Object.is(value, undefined))\n return { v: 'undefined' };\n if (Object.is(value, null))\n return { v: 'null' };\n if (Object.is(value, NaN))\n return { v: 'NaN' };\n if (Object.is(value, Infinity))\n return { v: 'Infinity' };\n if (Object.is(value, -Infinity))\n return { v: '-Infinity' };\n if (Object.is(value, -0))\n return { v: '-0' };\n if (typeof value === 'boolean')\n return { b: value };\n if (typeof value === 'number')\n return { n: value };\n if (typeof value === 'string')\n return { s: value };\n if (typeof value === 'bigint')\n return { bi: value.toString() };\n if (isError(value))\n return { e: { n: value.name, m: value.message, s: value.stack || '' } };\n if (isDate(value))\n return { d: value.toJSON() };\n if (isURL(value))\n return { u: value.toJSON() };\n if (isRegExp(value))\n return { r: { p: value.source, f: value.flags } };\n\n const typedArrayKind = constructorToTypedArrayKind.get(value.constructor);\n if (typedArrayKind)\n return { ta: { b: Buffer.from(value.buffer, value.byteOffset, value.byteLength), k: typedArrayKind } };\n\n const id = visitorInfo.visited.get(value);\n if (id)\n return { ref: id };\n\n if (Array.isArray(value)) {\n const a = [];\n const id = ++visitorInfo.lastId;\n visitorInfo.visited.set(value, id);\n for (let i = 0; i < value.length; ++i)\n a.push(innerSerializeValue(value[i], handleSerializer, visitorInfo, [...accessChain, i]));\n return { a, id };\n }\n if (typeof value === 'object') {\n const o: { k: string, v: SerializedValue }[] = [];\n const id = ++visitorInfo.lastId;\n visitorInfo.visited.set(value, id);\n for (const name of Object.keys(value))\n o.push({ k: name, v: innerSerializeValue(value[name], handleSerializer, visitorInfo, [...accessChain, name]) });\n return { o, id };\n }\n throw new Error(`Attempting to serialize unexpected value${accessChainToDisplayString(accessChain)}: ${value}`);\n}\n\nfunction accessChainToDisplayString(accessChain: Array<string | number>): string {\n const chainString = accessChain.map((accessor, i) => {\n if (typeof accessor === 'string')\n return i ? `.${accessor}` : accessor;\n return `[${accessor}]`;\n }).join('');\n\n return chainString.length > 0 ? ` at position \"${chainString}\"` : '';\n}\n\nfunction isRegExp(obj: any): obj is RegExp {\n return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]';\n}\n\nfunction isDate(obj: any): obj is Date {\n return obj instanceof Date || Object.prototype.toString.call(obj) === '[object Date]';\n}\n\nfunction isURL(obj: any): obj is URL {\n return obj instanceof URL || Object.prototype.toString.call(obj) === '[object URL]';\n}\n\nfunction isError(obj: any): obj is Error {\n const proto = obj ? Object.getPrototypeOf(obj) : null;\n return obj instanceof Error || proto?.name === 'Error' || (proto && isError(proto));\n}\n\n\ntype TypedArrayKind = NonNullable<SerializedValue['ta']>['k'];\nconst typedArrayKindToConstructor: Record<TypedArrayKind, Function> = {\n i8: Int8Array,\n ui8: Uint8Array,\n ui8c: Uint8ClampedArray,\n i16: Int16Array,\n ui16: Uint16Array,\n i32: Int32Array,\n ui32: Uint32Array,\n f32: Float32Array,\n f64: Float64Array,\n bi64: BigInt64Array,\n bui64: BigUint64Array,\n};\n\nconst constructorToTypedArrayKind: Map<Function, TypedArrayKind> = new Map(Object.entries(typedArrayKindToConstructor).map(([k, v]) => [v, k as TypedArrayKind]));\n","import type { recordOptions } from '@appsurify-testmap/rrweb';\nimport { record } from '@appsurify-testmap/rrweb';\nimport type { Mirror } from '@appsurify-testmap/rrweb-snapshot';\nimport type { Page, JSHandle } from '@playwright/test';\nimport type { RecorderContext, RecorderEvent } from './types';\nimport type { eventWithTime, RecordPlugin } from '@appsurify-testmap/rrweb-types';\nimport { deepMerge } from '../utils';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport rrSrc from './releases/rrweb-record.umd.cjs.src';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport rrPluginSrc from './releases/rrweb-plugin-sequential-id-record.umd.cjs.src';\n\n\nexport const defaultRecordOptions: recordOptions<RecorderEvent> = {\n slimDOMOptions: 'all',\n inlineStylesheet: true,\n recordDOM: true,\n recordCanvas: true,\n collectFonts: true,\n inlineImages: true,\n checkoutEveryNvm: 60,\n maskInputOptions: { password: true },\n sampling: {\n mousemove: false,\n mouseInteraction: {\n MouseUp: false,\n MouseDown: false,\n Click: true,\n ContextMenu: true,\n DblClick: true,\n Focus: false,\n Blur: false,\n TouchStart: false,\n TouchEnd: false,\n },\n scroll: 100,\n media: 100,\n input: 'last',\n canvas: 'all',\n visibility: {\n mode: 'none',\n debounce: 50,\n throttle: 100,\n threshold: 0.5,\n sensitivity: 0.05,\n rafThrottle: 100\n }\n },\n flushCustomEvent: 'after',\n recordAfter: 'DOMContentLoaded',\n userTriggeredOnInput: true,\n}\n\ndeclare global {\n interface Window {\n rrweb?: {\n record?: typeof record;\n },\n stopFn: (() => void) | undefined | null,\n handleEmit: (event: RecorderEvent) => void,\n rrwebPluginSequentialIdRecord?: {\n getRecordSequentialIdPlugin: (options?: Partial<{key: string, getId?: () => number}>) => RecordPlugin;\n }\n }\n}\n\nexport class RRWebRecorder {\n private recordFn: JSHandle | null | undefined = null;\n private page: Page | null = null;\n private context: RecorderContext;\n private eventCounter = 0;\n private events: RecorderEvent[] = [];\n private recordOptions?: recordOptions<RecorderEvent>;\n private pendingEvents: {\n tag: string;\n payload: Record<string, unknown>;\n }[] = [];\n private recorderScriptVersion = 'unknown';\n private recorderLibVersion = 'unknown';\n public isRecording = false;\n\n constructor(options?: recordOptions<RecorderEvent>) {\n this.recordOptions = deepMerge(defaultRecordOptions, options ?? {});\n this.context = {\n pushEvent: (event) => this.events.push(event),\n };\n }\n\n private handleEmit(event: RecorderEvent) {\n if (event.type === 0 || event.type === 1) {\n return;\n }\n const rrEvent: RecorderEvent = {\n ...event,\n };\n this.context.pushEvent(rrEvent);\n }\n\n public async inject(page: Page) {\n this.page = page\n\n await this.page?.addInitScript({content: rrSrc as string});\n await this.page?.addInitScript({content: rrPluginSrc as string});\n\n await this.page?.exposeFunction('handleEmit', (event: RecorderEvent) => {\n this.handleEmit(event);\n });\n\n }\n\n public async start() {\n this.recordFn = await this.page?.evaluateHandle(() => {\n return window.rrweb?.record;\n });\n await this.recordFn?.evaluate((r: typeof record, optsJson) => {\n const opts = JSON.parse(optsJson) as recordOptions<RecorderEvent>;\n const plugins = [];\n if (window.rrwebPluginSequentialIdRecord) {\n plugins.push(\n window.rrwebPluginSequentialIdRecord.getRecordSequentialIdPlugin({\n key: 'id',\n })\n )\n }\n\n window.stopFn = r({\n emit: (event: RecorderEvent) => {\n // console.info(`[${event.timestamp}] [rrweb-recorder] ${event.type} ${event.data?.source} ${event.data?.href}`)\n window.handleEmit?.(event);\n },\n plugins: plugins,\n ...opts,\n })\n }, JSON.stringify(this.recordOptions));\n\n this.isRecording = await this.recordFn?.evaluate((r: typeof record) => r.isRecording()) as boolean;\n this.recorderScriptVersion = await this.recordFn?.evaluate((r: typeof record) => r.getVersion()) as string;\n\n await this.flush();\n }\n\n public async stop() {\n this.isRecording = false;\n if (this.recordFn && this.page && !this.page.isClosed()) {\n await this.flush();\n await this.page.evaluate(() => {\n window.stopFn = null;\n });\n }\n }\n\n public async reset() {\n this.eventCounter = 0;\n this.events = [];\n await this.stop();\n this.context = {\n pushEvent: (event) => this.events.push(event),\n };\n }\n\n public async flush() {\n if (!this.recordFn) return;\n const stillPending: typeof this.pendingEvents = [];\n for (const evt of this.pendingEvents) {\n try {\n await this.recordFn.evaluate((r: typeof record, evt) => {\n r.addCustomEvent(evt.tag, evt.payload)\n }, evt);\n } catch (error) {\n console.debug(`[${Date.now()}] [recorder] flush failed for custom event: ${evt.tag}`);\n stillPending.push(evt);\n }\n }\n this.pendingEvents = stillPending;\n }\n\n public async addCustomEvent(tag: string, payload: Record<string, unknown>) {\n const event = { tag, payload };\n\n if (!this.recordFn || !this.isRecording) {\n console.debug(`[${Date.now()}] [recorder] queued custom event (recorder not ready): ${tag}`);\n this.pendingEvents.push(event);\n return;\n }\n\n try {\n await this.recordFn.evaluate((r: typeof record, evt) => {\n r.addCustomEvent(evt.tag, evt.payload)\n }, event);\n } catch (error) {\n this.pendingEvents.push(event);\n }\n\n }\n\n public isRecordingReady(): boolean {\n return !!this.recordFn && this.isRecording;\n }\n\n public getScriptVersion(): string {\n return `@appsurify-testmap/rrweb-record:${this.recorderScriptVersion}`;\n }\n\n public getLibVersion(): string {\n return `@appsurify-testmap/rrweb:${this.recorderLibVersion !== 'unknown' ? this.recorderLibVersion : this.recorderScriptVersion}`;\n }\n\n public getEvents(): readonly RecorderEvent[] {\n return this.events;\n }\n\n public getMirror(): Mirror | undefined {\n return (this.recordFn as unknown as { mirror?: Mirror })?.mirror;\n }\n\n public bind(ctx: RecorderContext) {\n this.context = ctx;\n }\n\n public setEventCounter(value: number) {\n this.eventCounter = value;\n }\n\n}\n","import { RRWebRecorder } from './RRWebRecorder';\n\n\nexport default RRWebRecorder;\n","import type { TestRunContext } from './types';\n\nexport const testContexts = new Map<string, TestRunContext>();\n\nexport function setCurrentTestContext(key: string, ctx: TestRunContext): void {\n testContexts.set(key, ctx);\n}\n\nexport function getCurrentTestContext(key: string): TestRunContext | undefined {\n return testContexts.get(key);\n}\n\nexport function clearTestContext(key: string): void {\n testContexts.delete(key);\n}\n"],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC1YzJ,IA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","names":["src_exports","__export","test","__toCommonJS","import_test","import_os","import_path","import_fs","defaultOutputReportDir","aggregateCleared","writeFileAtomic","filePath","data","dir","path","tmp","fs","readJsonArraySafe","text","parsed","saveRRWebReport","testRunResult","outputReportDir","reportDir","specName","sanitizeFileNamePart","suiteTitle","testTitle","browserName","jsonFileNameRaw","jsonFilePathRaw","reportRaw","aggregatePath","current","e","name","createTestrunContext","browser","testInfo","browserType","version","family","absolute","relative","baseName","fileName","fileExtension","suiteTitlePath","os","deepMerge","target","source","result","key","sourceValue","targetValue","waitForRecorderStabilization","recorder","timeout","start","lastCount","resolve","interval","currentCount","waitForNextRAF","page","r","typedArrayKindToConstructor","constructorToTypedArrayKind","k","v","defaultRecordOptions","RRWebRecorder","options","deepMerge","event","rrEvent","page","rrweb_record_umd_cjs_default","rrweb_plugin_sequential_id_record_umd_cjs_default","r","optsJson","opts","plugins","stillPending","evt","tag","payload","ctx","value","recorder_default","RRWebRecorder","testContexts","setCurrentTestContext","key","ctx","getCurrentTestContext","test","base","browser","use","testInfo","context","testRunContext","createTestrunContext","setCurrentTestContext","page","testmapConfig","recordingOpts","recorder_default","recorder","getCurrentTestContext","event","consoleMessage","originalonStepEnd","stepEndPayload","currentStepInfo","waitForNextRAF","originalonDidFinishTestFunction","waitForRecorderStabilization","testRunResult","saveRRWebReport"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/recorder/RRWebRecorder.ts","../src/recorder/index.ts","../src/runtime.ts"],"sourcesContent":["import {\n test as base,\n expect,\n} from '@playwright/test';\nimport type {\n ConsoleMessage,\n} from '@playwright/test';\nimport RRWebRecorder from './recorder';\nimport defaultRecordOptions from './recorder';\n\nimport {\n createTestrunContext,\n saveRRWebReport,\n waitForNextRAF,\n waitForRecorderStabilization,\n} from './utils';\nimport {\n getCurrentTestContext,\n setCurrentTestContext,\n} from './runtime';\n\nimport type {\n TestmapConfig\n} from './types';\n\n\nconst test = base.extend<{}>({\n browser: async ({ browser }, use) => {\n await use(browser);\n },\n\n context: async ({ browser }, use, testInfo) => {\n const context = await browser.newContext();\n const testRunContext = createTestrunContext(browser, testInfo);\n setCurrentTestContext(testInfo.testId, testRunContext);\n await use(context);\n await context.close();\n },\n\n page: async ({ page }, use, testInfo) => {\n\n type ExtendedUse = typeof testInfo.project.use & { testmap?: TestmapConfig };\n const pwConfig = testInfo.project.use as ExtendedUse;\n const testmapConfig = pwConfig.testmap ?? {};\n const recordingOpts =\n typeof testmapConfig === 'object' && 'recordingOpts' in testmapConfig\n ? testmapConfig.recordingOpts\n : defaultRecordOptions;\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n // @ts-ignore\n const recorder = new RRWebRecorder(recordingOpts);\n\n const testRunContext = getCurrentTestContext(testInfo.testId);\n if (testRunContext) {\n testRunContext.recorderInstance = recorder;\n }\n\n recorder.bind({\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n pushEvent: async (event) => {\n testRunContext?.recorderEvents.push(event);\n await Promise.resolve();\n },\n });\n await recorder.inject(page);\n\n // eslint-disable-next-line @typescript-eslint/require-await\n page.on('console', async (consoleMessage: ConsoleMessage) => {\n if (consoleMessage.type() === 'debug') return;\n console.debug(`[${Date.now()}] [page] console`, consoleMessage.text());\n });\n\n page.on('load', async () => {\n /* empty */\n });\n\n page.on('domcontentloaded', async () => {\n await recorder.start();\n if (testRunContext?.runner) {\n testRunContext.runner.recorder = {\n scriptVersion: recorder.getScriptVersion(),\n libVersion: recorder.getLibVersion(),\n };\n }\n });\n page.on('framenavigated', async () => {\n /* empty */\n });\n\n page.on('close', async () => {\n await recorder.flush();\n });\n\n // @ts-ignore\n const originalonStepEnd = testInfo._onStepEnd.bind(this);\n // @ts-ignore\n testInfo._onStepEnd = async (stepEndPayload: {\n testId: string;\n stepId: string;\n wallTime: number;\n error?: unknown;\n suggestedRebaseline?: string;\n annotations: { type: string, description?: string }[];\n }) => {\n\n // @ts-ignore\n const currentStepInfo = testInfo._stepMap.get(stepEndPayload.stepId);\n if (currentStepInfo.apiName && currentStepInfo?.location.file === testInfo.file) {\n await recorder.addCustomEvent(currentStepInfo.apiName, {\n stepId: currentStepInfo.stepId,\n category: currentStepInfo.category,\n location: currentStepInfo.location,\n title: currentStepInfo.title,\n apiName: currentStepInfo.apiName,\n endWallTime: currentStepInfo.endWallTime,\n });\n\n }\n if (!page.isClosed()) {\n try {\n await waitForNextRAF(page);\n } catch (error) { /* empty */ }\n }\n await originalonStepEnd(stepEndPayload);\n };\n\n // @ts-ignore\n const originalonDidFinishTestFunction = testInfo._onDidFinishTestFunction.bind(this);\n // @ts-ignore\n testInfo._onDidFinishTestFunction = async () => {\n\n if (recorder && recorder.isRecordingReady()) {\n await waitForRecorderStabilization(recorder, 500);\n await recorder.stop();\n }\n\n await originalonDidFinishTestFunction();\n }\n\n await use(page);\n\n\n },\n});\n\ntest.beforeEach(async ({}, testInfo) => {\n console.log(`[${Date.now()}] [🟢 TEST START] ${testInfo.title}`);\n\n});\n\ntest.afterEach(async ({}, testInfo) => {\n console.log(`[${Date.now()}] [🔴 TEST END] ${testInfo.title}`);\n const testRunContext = getCurrentTestContext(testInfo.testId);\n if (!testRunContext) return;\n\n testRunContext.test.duration = testInfo.duration;\n const testRunResult = {\n runner: testRunContext?.runner,\n spec: testRunContext?.spec,\n browser: testRunContext?.browser,\n test: testRunContext?.test,\n suite: testRunContext?.test.suite,\n recorderEvents: Array.isArray(testRunContext?.recorderEvents) ? testRunContext?.recorderEvents : []\n }\n\n type ExtendedUse = typeof testInfo.project.use & { testmap?: TestmapConfig };\n const pwConfig = testInfo.project.use as ExtendedUse;\n const testmapConfig = pwConfig.testmap ?? {};\n\n saveRRWebReport(testRunResult, testmapConfig.outputReportDir)\n\n});\n\nexport { test, expect };\n\n","import os from 'os';\nimport path from 'path';\nimport fs from 'fs';\nimport { Browser, Page, Frame, TestInfo } from '@playwright/test';\nimport type { RecorderEvent } from './recorder/types';\nimport type { TestRunContext, TestRunResult, SerializedValue } from './types';\nimport RRWebRecorder from \"./recorder\";\n\nconst defaultOutputReportDir = 'test-results/playwright/ui';\n\n// Tracks whether the aggregate report has been cleared in this process.\n// Ensures the file is reset once per test run (process lifetime).\nlet aggregateCleared = false;\n\nfunction writeFileAtomic(filePath: string, data: string) {\n const dir = path.dirname(filePath);\n const tmp = path.join(dir, `.${path.basename(filePath)}.tmp-${process.pid}-${Date.now()}`);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(tmp, data, 'utf-8');\n fs.renameSync(tmp, filePath);\n}\n\nfunction readJsonArraySafe(filePath: string): unknown[] {\n try {\n if (!fs.existsSync(filePath)) return [];\n const text = fs.readFileSync(filePath, 'utf-8').trim();\n if (!text) return [];\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const parsed = JSON.parse(text);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nexport function saveRRWebReport(testRunResult: TestRunResult, outputReportDir?: string) {\n const reportDir = outputReportDir !== undefined ? outputReportDir : defaultOutputReportDir;\n const specName = sanitizeFileNamePart(testRunResult.spec.name);\n const suiteTitle = sanitizeFileNamePart(testRunResult.test.suite?.title);\n const testTitle = sanitizeFileNamePart(testRunResult.test.title);\n const browserName = testRunResult.browser.name;\n\n const jsonFileNameRaw = `${suiteTitle ? suiteTitle + '-' : ''}${testTitle}.json`;\n const jsonFilePathRaw = path.join(reportDir, specName, browserName, jsonFileNameRaw);\n const reportRaw = {\n events: testRunResult.recorderEvents,\n metadata: {\n runner: testRunResult.runner,\n spec: testRunResult.spec,\n suite: testRunResult.test.suite,\n test: testRunResult.test,\n browser: testRunResult.browser,\n }\n };\n fs.mkdirSync(reportDir, { recursive: true });\n fs.mkdirSync(path.dirname(jsonFilePathRaw), { recursive: true });\n fs.writeFileSync(jsonFilePathRaw, JSON.stringify(reportRaw, null, 2), 'utf-8');\n console.log(`[ui-coverage] Saved report to ${jsonFilePathRaw}`);\n\n try {\n const aggregatePath = path.join(reportDir, \"ui-coverage-aggregated.json\");\n // On first call in this process, start a fresh aggregate file so it\n // only contains results from the current run.\n const current = aggregateCleared ? readJsonArraySafe(aggregatePath) : [];\n aggregateCleared = true;\n current.push(reportRaw);\n writeFileAtomic(aggregatePath, JSON.stringify(current, null, 2));\n console.log(`[ui-coverage] Updated aggregate: ${aggregatePath}`);\n } catch (e) {\n console.warn('[ui-coverage] Failed to update aggregate report:', e);\n }\n}\n\nexport function sanitizeFileNamePart(name: string | undefined): string {\n return (name ?? '')\n .trim()\n .replace(/[\\s:/\\\\<>|\"'?*]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\nexport function createTestrunContext(browser: Browser, testInfo: TestInfo): TestRunContext {\n const browserType = browser.browserType();\n const version = browser.version();\n const family = browserType.name();\n\n const absolute = testInfo.file;\n const relative = absolute.replace(process.cwd(), '').replace(/^[/\\\\]/, '');\n const baseName = relative.split(/[\\\\/]/).pop() ?? '';\n const [fileName, fileExtension] = baseName.split(/\\.(?=[^\\\\.]+$)/);\n\n const suiteTitlePath = testInfo.titlePath.slice(1, -1); // всё кроме последнего (сам тест)\n const suiteTitle = suiteTitlePath.join(' > ') || 'Root Suite';\n\n const testRunContext: TestRunContext = {\n runner: {\n source: 'playwright',\n type: 'unknown',\n version: testInfo.config.version,\n platform: os.platform(),\n arch: os.arch(),\n recorder: {\n scriptVersion: 'unknown',\n libVersion: 'unknown'\n }\n\n },\n spec: {\n name: baseName,\n relative,\n absolute,\n baseName,\n fileName,\n fileExtension,\n id: relative,\n },\n test: {\n suite: {\n id: suiteTitlePath.join('::') || 'root',\n invocationDetails: {\n absoluteFile: absolute,\n column: testInfo.column ?? 0,\n line: testInfo.line ?? 0,\n fileUrl: undefined,\n function: undefined,\n originalFile: undefined,\n relativeFile: relative,\n },\n pending: false,\n root: suiteTitlePath.length === 0,\n title: suiteTitle,\n type: \"unknown\"\n },\n id: testInfo.testId,\n title: testInfo.title,\n titlePath: testInfo.titlePath.slice(1),\n fullTitle: testInfo.titlePath.slice(1).join(' '),\n file: testInfo.file,\n invocationDetails: {\n absoluteFile: absolute,\n column: testInfo.column,\n line: testInfo.line,\n fileUrl: '',\n relativeFile: relative,\n },\n state: testInfo.status,\n duration: testInfo.duration,\n pending: false,\n sync: false,\n timedOut: undefined,\n type: ''\n },\n browser: {\n name: family,\n family,\n version,\n majorVersion: parseInt(version.split('.')[0], 10),\n displayName: testInfo.project.use?.channel?.toUpperCase?.() ?? family.charAt(0).toUpperCase() + family.slice(1),\n channel: testInfo.project.use?.channel ?? '',\n path: browserType.executablePath(),\n },\n recorderEvents: [] as RecorderEvent[],\n };\n return testRunContext\n}\n\nexport function deepMerge<T>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue &&\n typeof sourceValue === 'object' &&\n !Array.isArray(sourceValue) &&\n targetValue &&\n typeof targetValue === 'object' &&\n !Array.isArray(targetValue)\n ) {\n result[key] = deepMerge(targetValue, sourceValue);\n } else if (sourceValue !== undefined) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n result[key] = sourceValue as unknown;\n }\n }\n\n return result;\n}\n\nexport async function waitForRecorderStabilization(recorder: RRWebRecorder, timeout = 500) {\n const start = Date.now();\n let lastCount = recorder.getEvents().length;\n\n return new Promise<void>((resolve) => {\n const interval = setInterval(() => {\n const currentCount = recorder.getEvents().length;\n if (currentCount === lastCount || Date.now() - start > timeout) {\n clearInterval(interval);\n resolve();\n }\n lastCount = currentCount;\n }, 50);\n });\n}\n\nexport async function waitForNextRAF(page: Page) {\n await page.evaluate(() => new Promise<void>((r) => requestAnimationFrame(() => r())));\n}\n\nexport async function waitForRAF(\n pageOrFrame: Page | Frame,\n) {\n return await pageOrFrame.evaluate(() => {\n return new Promise((resolve) => {\n requestAnimationFrame(() => {\n requestAnimationFrame(resolve);\n });\n });\n });\n}\n\nexport function parseSerializedValue(value: SerializedValue, handles: any[] | undefined): any {\n return innerParseSerializedValue(value, handles, new Map(), []);\n}\n\nfunction innerParseSerializedValue(value: SerializedValue, handles: any[] | undefined, refs: Map<number, object>, accessChain: Array<string | number>): any {\n if (value.ref !== undefined)\n return refs.get(value.ref);\n if (value.n !== undefined)\n return value.n;\n if (value.s !== undefined)\n return value.s;\n if (value.b !== undefined)\n return value.b;\n if (value.v !== undefined) {\n if (value.v === 'undefined')\n return undefined;\n if (value.v === 'null')\n return null;\n if (value.v === 'NaN')\n return NaN;\n if (value.v === 'Infinity')\n return Infinity;\n if (value.v === '-Infinity')\n return -Infinity;\n if (value.v === '-0')\n return -0;\n }\n if (value.d !== undefined)\n return new Date(value.d);\n if (value.u !== undefined)\n return new URL(value.u);\n if (value.bi !== undefined)\n return BigInt(value.bi);\n if (value.e !== undefined) {\n const error = new Error(value.e.m);\n error.name = value.e.n;\n error.stack = value.e.s;\n return error;\n }\n if (value.r !== undefined)\n return new RegExp(value.r.p, value.r.f);\n if (value.ta !== undefined) {\n const ctor = typedArrayKindToConstructor[value.ta.k] as any;\n return new ctor(value.ta.b.buffer, value.ta.b.byteOffset, value.ta.b.length / ctor.BYTES_PER_ELEMENT);\n }\n\n if (value.a !== undefined) {\n const result: any[] = [];\n refs.set(value.id!, result);\n for (let i = 0; i < value.a.length; i++)\n result.push(innerParseSerializedValue(value.a[i], handles, refs, [...accessChain, i]));\n return result;\n }\n if (value.o !== undefined) {\n const result: any = {};\n refs.set(value.id!, result);\n for (const { k, v } of value.o)\n result[k] = innerParseSerializedValue(v, handles, refs, [...accessChain, k]);\n return result;\n }\n if (value.h !== undefined) {\n if (handles === undefined)\n throw new Error('Unexpected handle');\n return handles[value.h];\n }\n throw new Error(`Attempting to deserialize unexpected value${accessChainToDisplayString(accessChain)}: ${value}`);\n}\n\nexport type HandleOrValue = { h: number } | { fallThrough: any };\ntype VisitorInfo = {\n visited: Map<object, number>;\n lastId: number;\n};\n\nexport function serializeValue(value: any, handleSerializer: (value: any) => HandleOrValue): SerializedValue {\n return innerSerializeValue(value, handleSerializer, { lastId: 0, visited: new Map() }, []);\n}\n\nfunction innerSerializeValue(value: any, handleSerializer: (value: any) => HandleOrValue, visitorInfo: VisitorInfo, accessChain: Array<string | number>): SerializedValue {\n const handle = handleSerializer(value);\n if ('fallThrough' in handle)\n value = handle.fallThrough;\n else\n return handle;\n\n if (typeof value === 'symbol')\n return { v: 'undefined' };\n if (Object.is(value, undefined))\n return { v: 'undefined' };\n if (Object.is(value, null))\n return { v: 'null' };\n if (Object.is(value, NaN))\n return { v: 'NaN' };\n if (Object.is(value, Infinity))\n return { v: 'Infinity' };\n if (Object.is(value, -Infinity))\n return { v: '-Infinity' };\n if (Object.is(value, -0))\n return { v: '-0' };\n if (typeof value === 'boolean')\n return { b: value };\n if (typeof value === 'number')\n return { n: value };\n if (typeof value === 'string')\n return { s: value };\n if (typeof value === 'bigint')\n return { bi: value.toString() };\n if (isError(value))\n return { e: { n: value.name, m: value.message, s: value.stack || '' } };\n if (isDate(value))\n return { d: value.toJSON() };\n if (isURL(value))\n return { u: value.toJSON() };\n if (isRegExp(value))\n return { r: { p: value.source, f: value.flags } };\n\n const typedArrayKind = constructorToTypedArrayKind.get(value.constructor);\n if (typedArrayKind)\n return { ta: { b: Buffer.from(value.buffer, value.byteOffset, value.byteLength), k: typedArrayKind } };\n\n const id = visitorInfo.visited.get(value);\n if (id)\n return { ref: id };\n\n if (Array.isArray(value)) {\n const a = [];\n const id = ++visitorInfo.lastId;\n visitorInfo.visited.set(value, id);\n for (let i = 0; i < value.length; ++i)\n a.push(innerSerializeValue(value[i], handleSerializer, visitorInfo, [...accessChain, i]));\n return { a, id };\n }\n if (typeof value === 'object') {\n const o: { k: string, v: SerializedValue }[] = [];\n const id = ++visitorInfo.lastId;\n visitorInfo.visited.set(value, id);\n for (const name of Object.keys(value))\n o.push({ k: name, v: innerSerializeValue(value[name], handleSerializer, visitorInfo, [...accessChain, name]) });\n return { o, id };\n }\n throw new Error(`Attempting to serialize unexpected value${accessChainToDisplayString(accessChain)}: ${value}`);\n}\n\nfunction accessChainToDisplayString(accessChain: Array<string | number>): string {\n const chainString = accessChain.map((accessor, i) => {\n if (typeof accessor === 'string')\n return i ? `.${accessor}` : accessor;\n return `[${accessor}]`;\n }).join('');\n\n return chainString.length > 0 ? ` at position \"${chainString}\"` : '';\n}\n\nfunction isRegExp(obj: any): obj is RegExp {\n return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]';\n}\n\nfunction isDate(obj: any): obj is Date {\n return obj instanceof Date || Object.prototype.toString.call(obj) === '[object Date]';\n}\n\nfunction isURL(obj: any): obj is URL {\n return obj instanceof URL || Object.prototype.toString.call(obj) === '[object URL]';\n}\n\nfunction isError(obj: any): obj is Error {\n const proto = obj ? Object.getPrototypeOf(obj) : null;\n return obj instanceof Error || proto?.name === 'Error' || (proto && isError(proto));\n}\n\n\ntype TypedArrayKind = NonNullable<SerializedValue['ta']>['k'];\nconst typedArrayKindToConstructor: Record<TypedArrayKind, Function> = {\n i8: Int8Array,\n ui8: Uint8Array,\n ui8c: Uint8ClampedArray,\n i16: Int16Array,\n ui16: Uint16Array,\n i32: Int32Array,\n ui32: Uint32Array,\n f32: Float32Array,\n f64: Float64Array,\n bi64: BigInt64Array,\n bui64: BigUint64Array,\n};\n\nconst constructorToTypedArrayKind: Map<Function, TypedArrayKind> = new Map(Object.entries(typedArrayKindToConstructor).map(([k, v]) => [v, k as TypedArrayKind]));\n","import type { recordOptions } from '@appsurify-testmap/rrweb';\nimport { record } from '@appsurify-testmap/rrweb';\nimport type { Mirror } from '@appsurify-testmap/rrweb-snapshot';\nimport type { Page, JSHandle } from '@playwright/test';\nimport type { RecorderContext, RecorderEvent } from './types';\nimport type { eventWithTime, RecordPlugin } from '@appsurify-testmap/rrweb-types';\nimport { deepMerge } from '../utils';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport rrSrc from './releases/rrweb-record.umd.cjs.src';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport rrPluginSrc from './releases/rrweb-plugin-sequential-id-record.umd.cjs.src';\n\n\nexport const defaultRecordOptions: recordOptions<RecorderEvent> = {\n slimDOMOptions: 'all',\n inlineStylesheet: true,\n recordDOM: true,\n recordCanvas: true,\n collectFonts: true,\n inlineImages: true,\n checkoutEveryNvm: 60,\n maskInputOptions: { password: true },\n sampling: {\n mousemove: false,\n mouseInteraction: {\n MouseUp: false,\n MouseDown: false,\n Click: true,\n ContextMenu: true,\n DblClick: true,\n Focus: false,\n Blur: false,\n TouchStart: false,\n TouchEnd: false,\n },\n scroll: 100,\n media: 100,\n input: 'last',\n canvas: 'all',\n visibility: {\n mode: 'none',\n debounce: 50,\n throttle: 100,\n threshold: 0.5,\n sensitivity: 0.05,\n rafThrottle: 100\n }\n },\n flushCustomEvent: 'after',\n recordAfter: 'DOMContentLoaded',\n userTriggeredOnInput: true,\n}\n\ndeclare global {\n interface Window {\n rrweb?: {\n record?: typeof record;\n },\n stopFn: (() => void) | undefined | null,\n handleEmit: (event: RecorderEvent) => void,\n rrwebPluginSequentialIdRecord?: {\n getRecordSequentialIdPlugin: (options?: Partial<{key: string, getId?: () => number}>) => RecordPlugin;\n }\n }\n}\n\nexport class RRWebRecorder {\n private recordFn: JSHandle | null | undefined = null;\n private page: Page | null = null;\n private context: RecorderContext;\n private eventCounter = 0;\n private events: RecorderEvent[] = [];\n private recordOptions?: recordOptions<RecorderEvent>;\n private pendingEvents: {\n tag: string;\n payload: Record<string, unknown>;\n }[] = [];\n private recorderScriptVersion = 'unknown';\n private recorderLibVersion = 'unknown';\n public isRecording = false;\n\n constructor(options?: recordOptions<RecorderEvent>) {\n this.recordOptions = deepMerge(defaultRecordOptions, options ?? {});\n this.context = {\n pushEvent: (event) => this.events.push(event),\n };\n }\n\n private handleEmit(event: RecorderEvent) {\n if (event.type === 0 || event.type === 1) {\n return;\n }\n const rrEvent: RecorderEvent = {\n ...event,\n };\n this.context.pushEvent(rrEvent);\n }\n\n public async inject(page: Page) {\n this.page = page\n\n await this.page?.addInitScript({content: rrSrc as string});\n await this.page?.addInitScript({content: rrPluginSrc as string});\n\n await this.page?.exposeFunction('handleEmit', (event: RecorderEvent) => {\n this.handleEmit(event);\n });\n\n }\n\n public async start() {\n this.recordFn = await this.page?.evaluateHandle(() => {\n return window.rrweb?.record;\n });\n await this.recordFn?.evaluate((r: typeof record, optsJson) => {\n const opts = JSON.parse(optsJson) as recordOptions<RecorderEvent>;\n const plugins = [];\n if (window.rrwebPluginSequentialIdRecord) {\n plugins.push(\n window.rrwebPluginSequentialIdRecord.getRecordSequentialIdPlugin({\n key: 'id',\n })\n )\n }\n\n window.stopFn = r({\n emit: (event: RecorderEvent) => {\n // console.info(`[${event.timestamp}] [rrweb-recorder] ${event.type} ${event.data?.source} ${event.data?.href}`)\n window.handleEmit?.(event);\n },\n plugins: plugins,\n ...opts,\n })\n }, JSON.stringify(this.recordOptions));\n\n this.isRecording = await this.recordFn?.evaluate((r: typeof record) => r.isRecording()) as boolean;\n this.recorderScriptVersion = await this.recordFn?.evaluate((r: typeof record) => r.getVersion()) as string;\n\n await this.flush();\n }\n\n public async stop() {\n this.isRecording = false;\n if (this.recordFn && this.page && !this.page.isClosed()) {\n await this.flush();\n await this.page.evaluate(() => {\n window.stopFn = null;\n });\n }\n }\n\n public async reset() {\n this.eventCounter = 0;\n this.events = [];\n await this.stop();\n this.context = {\n pushEvent: (event) => this.events.push(event),\n };\n }\n\n public async flush() {\n if (!this.recordFn) return;\n const stillPending: typeof this.pendingEvents = [];\n for (const evt of this.pendingEvents) {\n try {\n await this.recordFn.evaluate((r: typeof record, evt) => {\n r.addCustomEvent(evt.tag, evt.payload)\n }, evt);\n } catch (error) {\n console.debug(`[${Date.now()}] [recorder] flush failed for custom event: ${evt.tag}`);\n stillPending.push(evt);\n }\n }\n this.pendingEvents = stillPending;\n }\n\n public async addCustomEvent(tag: string, payload: Record<string, unknown>) {\n const event = { tag, payload };\n\n if (!this.recordFn || !this.isRecording) {\n console.debug(`[${Date.now()}] [recorder] queued custom event (recorder not ready): ${tag}`);\n this.pendingEvents.push(event);\n return;\n }\n\n try {\n await this.recordFn.evaluate((r: typeof record, evt) => {\n r.addCustomEvent(evt.tag, evt.payload)\n }, event);\n } catch (error) {\n this.pendingEvents.push(event);\n }\n\n }\n\n public isRecordingReady(): boolean {\n return !!this.recordFn && this.isRecording;\n }\n\n public getScriptVersion(): string {\n return `@appsurify-testmap/rrweb-record:${this.recorderScriptVersion}`;\n }\n\n public getLibVersion(): string {\n return `@appsurify-testmap/rrweb:${this.recorderLibVersion !== 'unknown' ? this.recorderLibVersion : this.recorderScriptVersion}`;\n }\n\n public getEvents(): readonly RecorderEvent[] {\n return this.events;\n }\n\n public getMirror(): Mirror | undefined {\n return (this.recordFn as unknown as { mirror?: Mirror })?.mirror;\n }\n\n public bind(ctx: RecorderContext) {\n this.context = ctx;\n }\n\n public setEventCounter(value: number) {\n this.eventCounter = value;\n }\n\n}\n","import { RRWebRecorder } from './RRWebRecorder';\n\n\nexport default RRWebRecorder;\n","import type { TestRunContext } from './types';\n\nexport const testContexts = new Map<string, TestRunContext>();\n\nexport function setCurrentTestContext(key: string, ctx: TestRunContext): void {\n testContexts.set(key, ctx);\n}\n\nexport function getCurrentTestContext(key: string): TestRunContext | undefined {\n return testContexts.get(key);\n}\n\nexport function clearTestContext(key: string): void {\n testContexts.delete(key);\n}\n"],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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","names":["src_exports","__export","test","__toCommonJS","import_test","import_os","import_path","import_fs","defaultOutputReportDir","aggregateCleared","writeFileAtomic","filePath","data","dir","path","tmp","fs","readJsonArraySafe","text","parsed","saveRRWebReport","testRunResult","outputReportDir","reportDir","specName","sanitizeFileNamePart","suiteTitle","testTitle","browserName","jsonFileNameRaw","jsonFilePathRaw","reportRaw","aggregatePath","current","e","name","createTestrunContext","browser","testInfo","browserType","version","family","absolute","relative","baseName","fileName","fileExtension","suiteTitlePath","os","deepMerge","target","source","result","key","sourceValue","targetValue","waitForRecorderStabilization","recorder","timeout","start","lastCount","resolve","interval","currentCount","waitForNextRAF","page","r","typedArrayKindToConstructor","constructorToTypedArrayKind","k","v","defaultRecordOptions","RRWebRecorder","options","deepMerge","event","rrEvent","page","rrweb_record_umd_cjs_default","rrweb_plugin_sequential_id_record_umd_cjs_default","r","optsJson","opts","plugins","stillPending","evt","tag","payload","ctx","value","recorder_default","RRWebRecorder","testContexts","setCurrentTestContext","key","ctx","getCurrentTestContext","test","base","browser","use","testInfo","context","testRunContext","createTestrunContext","setCurrentTestContext","page","testmapConfig","recordingOpts","recorder_default","recorder","getCurrentTestContext","event","consoleMessage","originalonStepEnd","stepEndPayload","currentStepInfo","waitForNextRAF","originalonDidFinishTestFunction","waitForRecorderStabilization","testRunResult","saveRRWebReport"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{test as F,expect as ee}from"@playwright/test";import v from"os";import h from"path";import
|
|
1
|
+
import{test as F,expect as ee}from"@playwright/test";import v from"os";import h from"path";import u from"fs";var A="test-results/playwright/ui",w=!1;function M(t,e){let n=h.dirname(t),r=h.join(n,`.${h.basename(t)}.tmp-${process.pid}-${Date.now()}`);u.mkdirSync(n,{recursive:!0}),u.writeFileSync(r,e,"utf-8"),u.renameSync(r,t)}function N(t){try{if(!u.existsSync(t))return[];let e=u.readFileSync(t,"utf-8").trim();if(!e)return[];let n=JSON.parse(e);return Array.isArray(n)?n:[]}catch{return[]}}function S(t,e){let n=e!==void 0?e:A,r=g(t.spec.name),s=g(t.test.suite?.title),o=g(t.test.title),i=t.browser.name,c=`${s?s+"-":""}${o}.json`,d=h.join(n,r,i,c),p={events:t.recorderEvents,metadata:{runner:t.runner,spec:t.spec,suite:t.test.suite,test:t.test,browser:t.browser}};u.mkdirSync(n,{recursive:!0}),u.mkdirSync(h.dirname(d),{recursive:!0}),u.writeFileSync(d,JSON.stringify(p,null,2),"utf-8"),console.log(`[ui-coverage] Saved report to ${d}`);try{let a=h.join(n,"ui-coverage-aggregated.json"),l=w?N(a):[];w=!0,l.push(p),M(a,JSON.stringify(l,null,2)),console.log(`[ui-coverage] Updated aggregate: ${a}`)}catch(a){console.warn("[ui-coverage] Failed to update aggregate report:",a)}}function g(t){return(t??"").trim().replace(/[\s:/\\<>|"'?*]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function x(t,e){let n=t.browserType(),r=t.version(),s=n.name(),o=e.file,i=o.replace(process.cwd(),"").replace(/^[/\\]/,""),c=i.split(/[\\/]/).pop()??"",[d,p]=c.split(/\.(?=[^\\.]+$)/),a=e.titlePath.slice(1,-1),l=a.join(" > ")||"Root Suite";return{runner:{source:"playwright",type:"unknown",version:e.config.version,platform:v.platform(),arch:v.arch(),recorder:{scriptVersion:"unknown",libVersion:"unknown"}},spec:{name:c,relative:i,absolute:o,baseName:c,fileName:d,fileExtension:p,id:i},test:{suite:{id:a.join("::")||"root",invocationDetails:{absoluteFile:o,column:e.column??0,line:e.line??0,fileUrl:void 0,function:void 0,originalFile:void 0,relativeFile:i},pending:!1,root:a.length===0,title:l,type:"unknown"},id:e.testId,title:e.title,titlePath:e.titlePath.slice(1),fullTitle:e.titlePath.slice(1).join(" "),file:e.file,invocationDetails:{absoluteFile:o,column:e.column,line:e.line,fileUrl:"",relativeFile:i},state:e.status,duration:e.duration,pending:!1,sync:!1,timedOut:void 0,type:""},browser:{name:s,family:s,version:r,majorVersion:parseInt(r.split(".")[0],10),displayName:e.project.use?.channel?.toUpperCase?.()??s.charAt(0).toUpperCase()+s.slice(1),channel:e.project.use?.channel??"",path:n.executablePath()},recorderEvents:[]}}function y(t,e){let n={...t};for(let r in e){let s=e[r],o=t[r];s&&typeof s=="object"&&!Array.isArray(s)&&o&&typeof o=="object"&&!Array.isArray(o)?n[r]=y(o,s):s!==void 0&&(n[r]=s)}return n}async function k(t,e=500){let n=Date.now(),r=t.getEvents().length;return new Promise(s=>{let o=setInterval(()=>{let i=t.getEvents().length;(i===r||Date.now()-n>e)&&(clearInterval(o),s()),r=i},50)})}async function $(t){await t.evaluate(()=>new Promise(e=>requestAnimationFrame(()=>e())))}var O={i8:Int8Array,ui8:Uint8Array,ui8c:Uint8ClampedArray,i16:Int16Array,ui16:Uint16Array,i32:Int32Array,ui32:Uint32Array,f32:Float32Array,f64:Float64Array,bi64:BigInt64Array,bui64:BigUint64Array},W=new Map(Object.entries(O).map(([t,e])=>[e,t]));var C=`(function (g, f) {if ("object" == typeof exports && "object" == typeof module) {module.exports = f();} else if ("function" == typeof define && define.amd) {define("rrweb", [], f);} else if ("object" == typeof exports) {exports["rrweb"] = f();} else {g["rrweb"] = f();}}(typeof self !== 'undefined' ? self : typeof globalThis !== 'undefined' ? globalThis : this, () => {var exports = {};var module = { exports };
|
|
2
2
|
"use strict";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __defProps = Object.defineProperties;
|
|
@@ -14367,7 +14367,8 @@ function initInputObserver({
|
|
|
14367
14367
|
maskInputOptions,
|
|
14368
14368
|
maskInputFn,
|
|
14369
14369
|
sampling,
|
|
14370
|
-
userTriggeredOnInput
|
|
14370
|
+
userTriggeredOnInput,
|
|
14371
|
+
trustSyntheticInput
|
|
14371
14372
|
}) {
|
|
14372
14373
|
function eventHandler(event) {
|
|
14373
14374
|
let target = getEventTarget(event);
|
|
@@ -14417,34 +14418,53 @@ function initInputObserver({
|
|
|
14417
14418
|
function cbWithDedup(target, v2) {
|
|
14418
14419
|
const lastInputValue = lastInputValueMap.get(target);
|
|
14419
14420
|
const el = target;
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
|
|
14428
|
-
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
|
|
14433
|
-
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
|
|
14437
|
-
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
|
|
14443
|
-
|
|
14444
|
-
|
|
14445
|
-
|
|
14446
|
-
|
|
14447
|
-
|
|
14421
|
+
if (trustSyntheticInput) {
|
|
14422
|
+
const isInitialEmpty = !v2.userTriggered && el.value === "" && !v2.isChecked && !lastInputValue;
|
|
14423
|
+
const isSelectDefaultSelection = el.tagName === "SELECT" && !v2.userTriggered && !lastInputValue && el.selectedIndex === 0;
|
|
14424
|
+
if (isInitialEmpty || isSelectDefaultSelection) {
|
|
14425
|
+
console.debug(
|
|
14426
|
+
\`[\${nowTimestamp()}] [rrweb:record/observer] phantom input ignored (trust mode)\`,
|
|
14427
|
+
{
|
|
14428
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
|
|
14429
|
+
node: index.describeNode(el),
|
|
14430
|
+
tag: el.tagName,
|
|
14431
|
+
value: el.value,
|
|
14432
|
+
isInitialEmpty,
|
|
14433
|
+
isSelectDefaultSelection
|
|
14434
|
+
}
|
|
14435
|
+
);
|
|
14436
|
+
return;
|
|
14437
|
+
}
|
|
14438
|
+
} else {
|
|
14439
|
+
const hasPlaceholder = el.hasAttribute("placeholder");
|
|
14440
|
+
const isEmpty = el.value === "";
|
|
14441
|
+
const isDefaultEmpty = typeof el.defaultValue === "string" ? el.defaultValue === "" : true;
|
|
14442
|
+
const isNonUser = !v2.userTriggered;
|
|
14443
|
+
const isRepeatEmpty = !lastInputValue || lastInputValue.text === "";
|
|
14444
|
+
const isLikelyPhantom = hasPlaceholder && isEmpty && isDefaultEmpty && isRepeatEmpty && isNonUser && !v2.isChecked && el.type !== "hidden" && INPUT_TAGS.includes(el.tagName);
|
|
14445
|
+
const isRenderDrivenTextInput = el.tagName === "INPUT" && el.type === "text" && !v2.userTriggered && v2.text === el.defaultValue && !lastInputValue && el.hasAttribute("placeholder");
|
|
14446
|
+
const isValueFromDefault = !v2.userTriggered && el.value === el.defaultValue && !lastInputValue && el.hasAttribute("placeholder") && !v2.isChecked && el.type !== "hidden" && INPUT_TAGS.includes(el.tagName);
|
|
14447
|
+
const isPhantomCheckbox = el.type === "checkbox" && !v2.userTriggered && !v2.isChecked && !lastInputValue;
|
|
14448
|
+
const isPhantomRadio = el.type === "radio" && !v2.userTriggered && !v2.isChecked && !lastInputValue;
|
|
14449
|
+
if (isLikelyPhantom || isRenderDrivenTextInput || isValueFromDefault || isPhantomCheckbox || isPhantomRadio) {
|
|
14450
|
+
console.debug(
|
|
14451
|
+
\`[\${nowTimestamp()}] [rrweb:record/observer] \\u26D4 phantom input ignored\`,
|
|
14452
|
+
{
|
|
14453
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
|
|
14454
|
+
node: index.describeNode(el),
|
|
14455
|
+
tag: el.tagName,
|
|
14456
|
+
nodeType: el.nodeType,
|
|
14457
|
+
attribute: el.attributes,
|
|
14458
|
+
value: el.value,
|
|
14459
|
+
isLikelyPhantom,
|
|
14460
|
+
isRenderDrivenTextInput,
|
|
14461
|
+
isValueFromDefault,
|
|
14462
|
+
isPhantomCheckbox,
|
|
14463
|
+
isPhantomRadio
|
|
14464
|
+
}
|
|
14465
|
+
);
|
|
14466
|
+
return;
|
|
14467
|
+
}
|
|
14448
14468
|
}
|
|
14449
14469
|
if (!lastInputValue || lastInputValue.text !== v2.text || lastInputValue.isChecked !== v2.isChecked) {
|
|
14450
14470
|
lastInputValueMap.set(target, v2);
|
|
@@ -16508,8 +16528,15 @@ class NavigationManager {
|
|
|
16508
16528
|
return;
|
|
16509
16529
|
if (this.locked)
|
|
16510
16530
|
return;
|
|
16511
|
-
this.
|
|
16512
|
-
|
|
16531
|
+
if (this.pendingNavigation) {
|
|
16532
|
+
this.cancelTimers();
|
|
16533
|
+
this.disconnectSettlingObserver();
|
|
16534
|
+
this.pendingNavigation = null;
|
|
16535
|
+
this.onSnapshot(true);
|
|
16536
|
+
} else {
|
|
16537
|
+
this.cancelTimers();
|
|
16538
|
+
this.disconnectSettlingObserver();
|
|
16539
|
+
}
|
|
16513
16540
|
this.pendingNavigation = data;
|
|
16514
16541
|
if (this.frozen) {
|
|
16515
16542
|
return;
|
|
@@ -16723,7 +16750,7 @@ class ProcessedNodeManager {
|
|
|
16723
16750
|
destroy() {
|
|
16724
16751
|
}
|
|
16725
16752
|
}
|
|
16726
|
-
const version$1 = "3.
|
|
16753
|
+
const version$1 = "3.10.0-alpha.1";
|
|
16727
16754
|
let wrappedEmit;
|
|
16728
16755
|
let takeFullSnapshot$1;
|
|
16729
16756
|
let canvasManager;
|
|
@@ -16772,6 +16799,7 @@ function record(options = {}) {
|
|
|
16772
16799
|
recordAfter = options.recordAfter === "DOMContentLoaded" ? options.recordAfter : "load",
|
|
16773
16800
|
flushCustomEvent = options.flushCustomEvent !== void 0 ? options.flushCustomEvent : "after",
|
|
16774
16801
|
userTriggeredOnInput = false,
|
|
16802
|
+
trustSyntheticInput = false,
|
|
16775
16803
|
collectFonts = false,
|
|
16776
16804
|
inlineImages = false,
|
|
16777
16805
|
plugins,
|
|
@@ -16846,6 +16874,11 @@ function record(options = {}) {
|
|
|
16846
16874
|
let checkoutPending = false;
|
|
16847
16875
|
let checkoutDebounceTimer = null;
|
|
16848
16876
|
let checkoutFreezeTimestamp = null;
|
|
16877
|
+
let lastScrollEmitTime = 0;
|
|
16878
|
+
const scrollSettleTime = (sampling.scroll || 100) * 2;
|
|
16879
|
+
let lastSignificantMutationTime = 0;
|
|
16880
|
+
const mutationGracePeriod = 500;
|
|
16881
|
+
let hadVisibilityCheckoutInGrace = false;
|
|
16849
16882
|
const eventProcessor = (e2) => {
|
|
16850
16883
|
for (const plugin3 of plugins || []) {
|
|
16851
16884
|
if (plugin3.eventProcessor) {
|
|
@@ -16936,6 +16969,13 @@ function record(options = {}) {
|
|
|
16936
16969
|
}
|
|
16937
16970
|
};
|
|
16938
16971
|
const wrappedMutationEmit = (m) => {
|
|
16972
|
+
var _a3, _b2;
|
|
16973
|
+
var _a2, _b;
|
|
16974
|
+
const totalChanges = ((_a3 = (_a2 = m.adds) == null ? void 0 : _a2.length) != null ? _a3 : 0) + ((_b2 = (_b = m.removes) == null ? void 0 : _b.length) != null ? _b2 : 0);
|
|
16975
|
+
if (totalChanges > 10) {
|
|
16976
|
+
lastSignificantMutationTime = nowTimestamp();
|
|
16977
|
+
hadVisibilityCheckoutInGrace = false;
|
|
16978
|
+
}
|
|
16939
16979
|
wrappedEmit({
|
|
16940
16980
|
type: EventType.IncrementalSnapshot,
|
|
16941
16981
|
data: __spreadValues({
|
|
@@ -16951,12 +16991,15 @@ function record(options = {}) {
|
|
|
16951
16991
|
}, v2)
|
|
16952
16992
|
});
|
|
16953
16993
|
};
|
|
16954
|
-
const wrappedScrollEmit = (p) =>
|
|
16955
|
-
|
|
16956
|
-
|
|
16957
|
-
|
|
16958
|
-
|
|
16959
|
-
|
|
16994
|
+
const wrappedScrollEmit = (p) => {
|
|
16995
|
+
lastScrollEmitTime = nowTimestamp();
|
|
16996
|
+
wrappedEmit({
|
|
16997
|
+
type: EventType.IncrementalSnapshot,
|
|
16998
|
+
data: __spreadValues({
|
|
16999
|
+
source: IncrementalSource.Scroll
|
|
17000
|
+
}, p)
|
|
17001
|
+
});
|
|
17002
|
+
};
|
|
16960
17003
|
const wrappedCanvasMutationEmit = (p) => wrappedEmit({
|
|
16961
17004
|
type: EventType.IncrementalSnapshot,
|
|
16962
17005
|
data: __spreadValues({
|
|
@@ -17038,9 +17081,19 @@ function record(options = {}) {
|
|
|
17038
17081
|
mutationCb: recordVisibility ? wrappedVisibilityEmit : () => {
|
|
17039
17082
|
},
|
|
17040
17083
|
notifyActivity: checkoutEveryNvm != null ? (count) => {
|
|
17084
|
+
const now = nowTimestamp();
|
|
17085
|
+
const scrollRecent = now - lastScrollEmitTime < scrollSettleTime;
|
|
17086
|
+
const mutationRecent = now - lastSignificantMutationTime < mutationGracePeriod;
|
|
17087
|
+
if (scrollRecent && !mutationRecent) {
|
|
17088
|
+
return;
|
|
17089
|
+
}
|
|
17090
|
+
if (mutationRecent && hadVisibilityCheckoutInGrace) {
|
|
17091
|
+
return;
|
|
17092
|
+
}
|
|
17041
17093
|
visibilityMutationCount += count;
|
|
17042
17094
|
if (visibilityMutationCount >= checkoutEveryNvm) {
|
|
17043
17095
|
visibilityMutationCount = 0;
|
|
17096
|
+
hadVisibilityCheckoutInGrace = true;
|
|
17044
17097
|
if (checkoutDebounce) {
|
|
17045
17098
|
if (!checkoutPending) {
|
|
17046
17099
|
checkoutPending = true;
|
|
@@ -17273,6 +17326,7 @@ function record(options = {}) {
|
|
|
17273
17326
|
recordCanvas,
|
|
17274
17327
|
inlineImages,
|
|
17275
17328
|
userTriggeredOnInput,
|
|
17329
|
+
trustSyntheticInput,
|
|
17276
17330
|
collectFonts,
|
|
17277
17331
|
doc,
|
|
17278
17332
|
maskInputFn,
|
|
@@ -17351,6 +17405,43 @@ function record(options = {}) {
|
|
|
17351
17405
|
);
|
|
17352
17406
|
}
|
|
17353
17407
|
return () => {
|
|
17408
|
+
if (recording) {
|
|
17409
|
+
const activeEl = document.activeElement;
|
|
17410
|
+
if (activeEl && INPUT_TAGS.includes(activeEl.tagName)) {
|
|
17411
|
+
const inputEl = activeEl;
|
|
17412
|
+
const id = mirror.getId(inputEl);
|
|
17413
|
+
if (id !== -1) {
|
|
17414
|
+
const lastValue = lastInputValueMap.get(inputEl);
|
|
17415
|
+
let text = inputEl.value;
|
|
17416
|
+
let isChecked = false;
|
|
17417
|
+
const type = getInputType(inputEl) || "";
|
|
17418
|
+
if (type === "radio" || type === "checkbox") {
|
|
17419
|
+
isChecked = inputEl.checked;
|
|
17420
|
+
} else if (maskInputOptions[inputEl.tagName.toLowerCase()] || maskInputOptions[type]) {
|
|
17421
|
+
text = maskInputValue({
|
|
17422
|
+
element: inputEl,
|
|
17423
|
+
maskInputOptions,
|
|
17424
|
+
tagName: inputEl.tagName,
|
|
17425
|
+
type,
|
|
17426
|
+
value: text,
|
|
17427
|
+
maskInputFn
|
|
17428
|
+
});
|
|
17429
|
+
}
|
|
17430
|
+
if (!lastValue || lastValue.text !== text || lastValue.isChecked !== isChecked) {
|
|
17431
|
+
const inputData = userTriggeredOnInput ? { text, isChecked, userTriggered: false } : { text, isChecked };
|
|
17432
|
+
lastInputValueMap.set(inputEl, inputData);
|
|
17433
|
+
wrappedEmit({
|
|
17434
|
+
type: EventType.IncrementalSnapshot,
|
|
17435
|
+
data: __spreadProps(__spreadValues({
|
|
17436
|
+
source: IncrementalSource.Input
|
|
17437
|
+
}, inputData), {
|
|
17438
|
+
id
|
|
17439
|
+
})
|
|
17440
|
+
});
|
|
17441
|
+
}
|
|
17442
|
+
}
|
|
17443
|
+
}
|
|
17444
|
+
}
|
|
17354
17445
|
if (checkoutDebounceTimer) {
|
|
17355
17446
|
clearTimeout(checkoutDebounceTimer);
|
|
17356
17447
|
checkoutDebounceTimer = null;
|
|
@@ -17470,5 +17561,5 @@ exports.globalSequentialId = globalSequentialId;
|
|
|
17470
17561
|
return module.exports;
|
|
17471
17562
|
}))
|
|
17472
17563
|
//# sourceMappingURL=rrweb-plugin-sequential-id-record.umd.cjs.map
|
|
17473
|
-
`;var L={slimDOMOptions:"all",inlineStylesheet:!0,recordDOM:!0,recordCanvas:!0,collectFonts:!0,inlineImages:!0,checkoutEveryNvm:60,maskInputOptions:{password:!0},sampling:{mousemove:!1,mouseInteraction:{MouseUp:!1,MouseDown:!1,Click:!0,ContextMenu:!0,DblClick:!0,Focus:!1,Blur:!1,TouchStart:!1,TouchEnd:!1},scroll:100,media:100,input:"last",canvas:"all",visibility:{mode:"none",debounce:50,throttle:100,threshold:.5,sensitivity:.05,rafThrottle:100}},flushCustomEvent:"after",recordAfter:"DOMContentLoaded",userTriggeredOnInput:!0},f=class{recordFn=null;page=null;context;eventCounter=0;events=[];recordOptions;pendingEvents=[];recorderScriptVersion="unknown";recorderLibVersion="unknown";isRecording=!1;constructor(e){this.recordOptions=y(L,e??{}),this.context={pushEvent:n=>this.events.push(n)}}handleEmit(e){if(e.type===0||e.type===1)return;let n={...e};this.context.pushEvent(n)}async inject(e){this.page=e,await this.page?.addInitScript({content:C}),await this.page?.addInitScript({content:_}),await this.page?.exposeFunction("handleEmit",n=>{this.handleEmit(n)})}async start(){this.recordFn=await this.page?.evaluateHandle(()=>window.rrweb?.record),await this.recordFn?.evaluate((e,n)=>{let r=JSON.parse(n),s=[];window.rrwebPluginSequentialIdRecord&&s.push(window.rrwebPluginSequentialIdRecord.getRecordSequentialIdPlugin({key:"id"})),window.stopFn=e({emit:o=>{window.handleEmit?.(o)},plugins:s,...r})},JSON.stringify(this.recordOptions)),this.isRecording=await this.recordFn?.evaluate(e=>e.isRecording()),this.recorderScriptVersion=await this.recordFn?.evaluate(e=>e.getVersion()),await this.flush()}async stop(){this.isRecording=!1,this.recordFn&&this.page&&!this.page.isClosed()&&(await this.flush(),await this.page.evaluate(()=>{window.stopFn=null}))}async reset(){this.eventCounter=0,this.events=[],await this.stop(),this.context={pushEvent:e=>this.events.push(e)}}async flush(){if(!this.recordFn)return;let e=[];for(let n of this.pendingEvents)try{await this.recordFn.evaluate((r,s)=>{r.addCustomEvent(s.tag,s.payload)},n)}catch{console.debug(`[${Date.now()}] [recorder] flush failed for custom event: ${n.tag}`),e.push(n)}this.pendingEvents=e}async addCustomEvent(e,n){let r={tag:e,payload:n};if(!this.recordFn||!this.isRecording){console.debug(`[${Date.now()}] [recorder] queued custom event (recorder not ready): ${e}`),this.pendingEvents.push(r);return}try{await this.recordFn.evaluate((s,o)=>{s.addCustomEvent(o.tag,o.payload)},r)}catch{this.pendingEvents.push(r)}}isRecordingReady(){return!!this.recordFn&&this.isRecording}getScriptVersion(){return`@appsurify-testmap/rrweb-record:${this.recorderScriptVersion}`}getLibVersion(){return`@appsurify-testmap/rrweb:${this.recorderLibVersion!=="unknown"?this.recorderLibVersion:this.recorderScriptVersion}`}getEvents(){return this.events}getMirror(){return this.recordFn?.mirror}bind(e){this.context=e}setEventCounter(e){this.eventCounter=e}};var m=f;var E=new Map;function I(t,e){E.set(t,e)}function b(t){return E.get(t)}var R=F.extend({browser:async({browser:t},e)=>{await e(t)},context:async({browser:t},e,n)=>{let r=await t.newContext(),s=x(t,n);I(n.testId,s),await e(r),await r.close()},page:async({page:t},e,n)=>{let s=n.project.use.testmap??{},o=typeof s=="object"&&"recordingOpts"in s?s.recordingOpts:m,i=new m(o),c=b(n.testId);c&&(c.recorderInstance=i),i.bind({pushEvent:async a=>{c?.recorderEvents.push(a),await Promise.resolve()}}),await i.inject(t),t.on("console",async a=>{a.type()!=="debug"&&console.debug(`[${Date.now()}] [page] console`,a.text())}),t.on("load",async()=>{}),t.on("domcontentloaded",async()=>{await i.start(),c?.runner&&(c.runner.recorder={scriptVersion:i.getScriptVersion(),libVersion:i.getLibVersion()})}),t.on("framenavigated",async()=>{}),t.on("close",async()=>{await i.flush()});let
|
|
17564
|
+
`;var L={slimDOMOptions:"all",inlineStylesheet:!0,recordDOM:!0,recordCanvas:!0,collectFonts:!0,inlineImages:!0,checkoutEveryNvm:60,maskInputOptions:{password:!0},sampling:{mousemove:!1,mouseInteraction:{MouseUp:!1,MouseDown:!1,Click:!0,ContextMenu:!0,DblClick:!0,Focus:!1,Blur:!1,TouchStart:!1,TouchEnd:!1},scroll:100,media:100,input:"last",canvas:"all",visibility:{mode:"none",debounce:50,throttle:100,threshold:.5,sensitivity:.05,rafThrottle:100}},flushCustomEvent:"after",recordAfter:"DOMContentLoaded",userTriggeredOnInput:!0},f=class{recordFn=null;page=null;context;eventCounter=0;events=[];recordOptions;pendingEvents=[];recorderScriptVersion="unknown";recorderLibVersion="unknown";isRecording=!1;constructor(e){this.recordOptions=y(L,e??{}),this.context={pushEvent:n=>this.events.push(n)}}handleEmit(e){if(e.type===0||e.type===1)return;let n={...e};this.context.pushEvent(n)}async inject(e){this.page=e,await this.page?.addInitScript({content:C}),await this.page?.addInitScript({content:_}),await this.page?.exposeFunction("handleEmit",n=>{this.handleEmit(n)})}async start(){this.recordFn=await this.page?.evaluateHandle(()=>window.rrweb?.record),await this.recordFn?.evaluate((e,n)=>{let r=JSON.parse(n),s=[];window.rrwebPluginSequentialIdRecord&&s.push(window.rrwebPluginSequentialIdRecord.getRecordSequentialIdPlugin({key:"id"})),window.stopFn=e({emit:o=>{window.handleEmit?.(o)},plugins:s,...r})},JSON.stringify(this.recordOptions)),this.isRecording=await this.recordFn?.evaluate(e=>e.isRecording()),this.recorderScriptVersion=await this.recordFn?.evaluate(e=>e.getVersion()),await this.flush()}async stop(){this.isRecording=!1,this.recordFn&&this.page&&!this.page.isClosed()&&(await this.flush(),await this.page.evaluate(()=>{window.stopFn=null}))}async reset(){this.eventCounter=0,this.events=[],await this.stop(),this.context={pushEvent:e=>this.events.push(e)}}async flush(){if(!this.recordFn)return;let e=[];for(let n of this.pendingEvents)try{await this.recordFn.evaluate((r,s)=>{r.addCustomEvent(s.tag,s.payload)},n)}catch{console.debug(`[${Date.now()}] [recorder] flush failed for custom event: ${n.tag}`),e.push(n)}this.pendingEvents=e}async addCustomEvent(e,n){let r={tag:e,payload:n};if(!this.recordFn||!this.isRecording){console.debug(`[${Date.now()}] [recorder] queued custom event (recorder not ready): ${e}`),this.pendingEvents.push(r);return}try{await this.recordFn.evaluate((s,o)=>{s.addCustomEvent(o.tag,o.payload)},r)}catch{this.pendingEvents.push(r)}}isRecordingReady(){return!!this.recordFn&&this.isRecording}getScriptVersion(){return`@appsurify-testmap/rrweb-record:${this.recorderScriptVersion}`}getLibVersion(){return`@appsurify-testmap/rrweb:${this.recorderLibVersion!=="unknown"?this.recorderLibVersion:this.recorderScriptVersion}`}getEvents(){return this.events}getMirror(){return this.recordFn?.mirror}bind(e){this.context=e}setEventCounter(e){this.eventCounter=e}};var m=f;var E=new Map;function I(t,e){E.set(t,e)}function b(t){return E.get(t)}var R=F.extend({browser:async({browser:t},e)=>{await e(t)},context:async({browser:t},e,n)=>{let r=await t.newContext(),s=x(t,n);I(n.testId,s),await e(r),await r.close()},page:async({page:t},e,n)=>{let s=n.project.use.testmap??{},o=typeof s=="object"&&"recordingOpts"in s?s.recordingOpts:m,i=new m(o),c=b(n.testId);c&&(c.recorderInstance=i),i.bind({pushEvent:async a=>{c?.recorderEvents.push(a),await Promise.resolve()}}),await i.inject(t),t.on("console",async a=>{a.type()!=="debug"&&console.debug(`[${Date.now()}] [page] console`,a.text())}),t.on("load",async()=>{}),t.on("domcontentloaded",async()=>{await i.start(),c?.runner&&(c.runner.recorder={scriptVersion:i.getScriptVersion(),libVersion:i.getLibVersion()})}),t.on("framenavigated",async()=>{}),t.on("close",async()=>{await i.flush()});let d=n._onStepEnd.bind(void 0);n._onStepEnd=async a=>{let l=n._stepMap.get(a.stepId);if(l.apiName&&l?.location.file===n.file&&await i.addCustomEvent(l.apiName,{stepId:l.stepId,category:l.category,location:l.location,title:l.title,apiName:l.apiName,endWallTime:l.endWallTime}),!t.isClosed())try{await $(t)}catch{}await d(a)};let p=n._onDidFinishTestFunction.bind(void 0);n._onDidFinishTestFunction=async()=>{i&&i.isRecordingReady()&&(await k(i,500),await i.stop()),await p()},await e(t)}});R.beforeEach(async({},t)=>{console.log(`[${Date.now()}] [\u{1F7E2} TEST START] ${t.title}`)});R.afterEach(async({},t)=>{console.log(`[${Date.now()}] [\u{1F534} TEST END] ${t.title}`);let e=b(t.testId);if(!e)return;e.test.duration=t.duration;let n={runner:e?.runner,spec:e?.spec,browser:e?.browser,test:e?.test,suite:e?.test.suite,recorderEvents:Array.isArray(e?.recorderEvents)?e?.recorderEvents:[]},s=t.project.use.testmap??{};S(n,s.outputReportDir)});export{ee as expect,R as test};
|
|
17474
17565
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/recorder/RRWebRecorder.ts","../src/recorder/index.ts","../src/runtime.ts"],"sourcesContent":["import {\n test as base,\n expect,\n} from '@playwright/test';\nimport type {\n ConsoleMessage,\n} from '@playwright/test';\nimport RRWebRecorder from './recorder';\nimport defaultRecordOptions from './recorder';\n\nimport {\n createTestrunContext,\n saveRRWebReport,\n waitForNextRAF,\n waitForRecorderStabilization,\n} from './utils';\nimport {\n getCurrentTestContext,\n setCurrentTestContext,\n} from './runtime';\n\nimport type {\n TestmapConfig\n} from './types';\n\n\nconst test = base.extend<{}>({\n browser: async ({ browser }, use) => {\n await use(browser);\n },\n\n context: async ({ browser }, use, testInfo) => {\n const context = await browser.newContext();\n const testRunContext = createTestrunContext(browser, testInfo);\n setCurrentTestContext(testInfo.testId, testRunContext);\n await use(context);\n await context.close();\n },\n\n page: async ({ page }, use, testInfo) => {\n\n type ExtendedUse = typeof testInfo.project.use & { testmap?: TestmapConfig };\n const pwConfig = testInfo.project.use as ExtendedUse;\n const testmapConfig = pwConfig.testmap ?? {};\n const recordingOpts =\n typeof testmapConfig === 'object' && 'recordingOpts' in testmapConfig\n ? testmapConfig.recordingOpts\n : defaultRecordOptions;\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n // @ts-ignore\n const recorder = new RRWebRecorder(recordingOpts);\n\n const testRunContext = getCurrentTestContext(testInfo.testId);\n if (testRunContext) {\n testRunContext.recorderInstance = recorder;\n }\n\n recorder.bind({\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n pushEvent: async (event) => {\n testRunContext?.recorderEvents.push(event);\n await Promise.resolve();\n },\n });\n await recorder.inject(page);\n\n // eslint-disable-next-line @typescript-eslint/require-await\n page.on('console', async (consoleMessage: ConsoleMessage) => {\n if (consoleMessage.type() === 'debug') return;\n console.debug(`[${Date.now()}] [page] console`, consoleMessage.text());\n });\n\n page.on('load', async () => {\n /* empty */\n });\n\n page.on('domcontentloaded', async () => {\n await recorder.start();\n if (testRunContext?.runner) {\n testRunContext.runner.recorder = {\n scriptVersion: recorder.getScriptVersion(),\n libVersion: recorder.getLibVersion(),\n };\n }\n });\n page.on('framenavigated', async () => {\n /* empty */\n });\n\n page.on('close', async () => {\n await recorder.flush();\n });\n\n // @ts-ignore\n const originalonStepEnd = testInfo._onStepEnd.bind(this);\n // @ts-ignore\n testInfo._onStepEnd = async (stepEndPayload: {\n testId: string;\n stepId: string;\n wallTime: number;\n error?: unknown;\n suggestedRebaseline?: string;\n annotations: { type: string, description?: string }[];\n }) => {\n\n // @ts-ignore\n const currentStepInfo = testInfo._stepMap.get(stepEndPayload.stepId);\n if (currentStepInfo.apiName && currentStepInfo?.location.file === testInfo.file) {\n await recorder.addCustomEvent(currentStepInfo.apiName, {\n stepId: currentStepInfo.stepId,\n category: currentStepInfo.category,\n location: currentStepInfo.location,\n title: currentStepInfo.title,\n apiName: currentStepInfo.apiName,\n endWallTime: currentStepInfo.endWallTime,\n });\n\n }\n if (!page.isClosed()) {\n try {\n await waitForNextRAF(page);\n } catch (error) { /* empty */ }\n }\n await originalonStepEnd(stepEndPayload);\n };\n\n // @ts-ignore\n const originalonDidFinishTestFunction = testInfo._onDidFinishTestFunction.bind(this);\n // @ts-ignore\n testInfo._onDidFinishTestFunction = async () => {\n\n if (recorder && recorder.isRecordingReady()) {\n await waitForRecorderStabilization(recorder, 500);\n await recorder.stop();\n }\n\n await originalonDidFinishTestFunction();\n }\n\n await use(page);\n\n\n },\n});\n\ntest.beforeEach(async ({}, testInfo) => {\n console.log(`[${Date.now()}] [🟢 TEST START] ${testInfo.title}`);\n\n});\n\ntest.afterEach(async ({}, testInfo) => {\n console.log(`[${Date.now()}] [🔴 TEST END] ${testInfo.title}`);\n const testRunContext = getCurrentTestContext(testInfo.testId);\n if (!testRunContext) return;\n\n testRunContext.test.duration = testInfo.duration;\n const testRunResult = {\n runner: testRunContext?.runner,\n spec: testRunContext?.spec,\n browser: testRunContext?.browser,\n test: testRunContext?.test,\n suite: testRunContext?.test.suite,\n recorderEvents: Array.isArray(testRunContext?.recorderEvents) ? testRunContext?.recorderEvents : []\n }\n\n type ExtendedUse = typeof testInfo.project.use & { testmap?: TestmapConfig };\n const pwConfig = testInfo.project.use as ExtendedUse;\n const testmapConfig = pwConfig.testmap ?? {};\n\n saveRRWebReport(testRunResult, testmapConfig.outputReportDir)\n\n});\n\nexport { test, expect };\n\n","import os from 'os';\nimport path from 'path';\nimport fs from 'fs';\nimport { Browser, Page, Frame, TestInfo } from '@playwright/test';\nimport type { RecorderEvent } from './recorder/types';\nimport type { TestRunContext, TestRunResult, SerializedValue } from './types';\nimport RRWebRecorder from \"./recorder\";\n\nconst defaultOutputReportDir = 'test-results/playwright/ui';\n\n// Tracks whether the aggregate report has been cleared in this process.\n// Ensures the file is reset once per test run (process lifetime).\nlet aggregateCleared = false;\n\nfunction writeFileAtomic(filePath: string, data: string) {\n const dir = path.dirname(filePath);\n const tmp = path.join(dir, `.${path.basename(filePath)}.tmp-${process.pid}-${Date.now()}`);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(tmp, data, 'utf-8');\n fs.renameSync(tmp, filePath);\n}\n\nfunction readJsonArraySafe(filePath: string): unknown[] {\n try {\n if (!fs.existsSync(filePath)) return [];\n const text = fs.readFileSync(filePath, 'utf-8').trim();\n if (!text) return [];\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const parsed = JSON.parse(text);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nexport function saveRRWebReport(testRunResult: TestRunResult, outputReportDir?: string) {\n const reportDir = outputReportDir !== undefined ? outputReportDir : defaultOutputReportDir;\n const specName = sanitizeFileNamePart(testRunResult.spec.name);\n const suiteTitle = sanitizeFileNamePart(testRunResult.test.suite?.title);\n const testTitle = sanitizeFileNamePart(testRunResult.test.title);\n const browserName = testRunResult.browser.name;\n\n const jsonFileNameRaw = `${suiteTitle ? suiteTitle + '-' : ''}${testTitle}.json`;\n const jsonFilePathRaw = path.join(reportDir, specName, browserName, jsonFileNameRaw);\n const reportRaw = {\n events: testRunResult.recorderEvents,\n metadata: {\n runner: testRunResult.runner,\n spec: testRunResult.spec,\n suite: testRunResult.test.suite,\n test: testRunResult.test,\n browser: testRunResult.browser,\n }\n };\n fs.mkdirSync(reportDir, { recursive: true });\n fs.mkdirSync(path.dirname(jsonFilePathRaw), { recursive: true });\n fs.writeFileSync(jsonFilePathRaw, JSON.stringify(reportRaw, null, 2), 'utf-8');\n console.log(`[ui-coverage] Saved report to ${jsonFilePathRaw}`);\n\n try {\n const aggregatePath = path.join(reportDir, \"ui-coverage-aggregated.json\");\n // On first call in this process, start a fresh aggregate file so it\n // only contains results from the current run.\n const current = aggregateCleared ? readJsonArraySafe(aggregatePath) : [];\n aggregateCleared = true;\n current.push(reportRaw);\n writeFileAtomic(aggregatePath, JSON.stringify(current, null, 2));\n console.log(`[ui-coverage] Updated aggregate: ${aggregatePath}`);\n } catch (e) {\n console.warn('[ui-coverage] Failed to update aggregate report:', e);\n }\n}\n\nexport function sanitizeFileNamePart(name: string | undefined): string {\n return (name ?? '')\n .trim()\n .replace(/[\\s:/\\\\<>|\"'?*]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\nexport function createTestrunContext(browser: Browser, testInfo: TestInfo): TestRunContext {\n const browserType = browser.browserType();\n const version = browser.version();\n const family = browserType.name();\n\n const absolute = testInfo.file;\n const relative = absolute.replace(process.cwd(), '').replace(/^[/\\\\]/, '');\n const baseName = relative.split(/[\\\\/]/).pop() ?? '';\n const [fileName, fileExtension] = baseName.split(/\\.(?=[^\\\\.]+$)/);\n\n const suiteTitlePath = testInfo.titlePath.slice(1, -1); // всё кроме последнего (сам тест)\n const suiteTitle = suiteTitlePath.join(' > ') || 'Root Suite';\n\n const testRunContext: TestRunContext = {\n runner: {\n source: 'playwright',\n type: 'unknown',\n version: testInfo.config.version,\n platform: os.platform(),\n arch: os.arch(),\n recorder: {\n scriptVersion: 'unknown',\n libVersion: 'unknown'\n }\n\n },\n spec: {\n name: baseName,\n relative,\n absolute,\n baseName,\n fileName,\n fileExtension,\n id: relative,\n },\n test: {\n suite: {\n id: suiteTitlePath.join('::') || 'root',\n invocationDetails: {\n absoluteFile: absolute,\n column: testInfo.column ?? 0,\n line: testInfo.line ?? 0,\n fileUrl: undefined,\n function: undefined,\n originalFile: undefined,\n relativeFile: relative,\n },\n pending: false,\n root: suiteTitlePath.length === 0,\n title: suiteTitle,\n type: \"unknown\"\n },\n id: testInfo.testId,\n title: testInfo.title,\n titlePath: testInfo.titlePath.slice(1),\n fullTitle: testInfo.titlePath.slice(1).join(' '),\n file: testInfo.file,\n invocationDetails: {\n absoluteFile: absolute,\n column: testInfo.column,\n line: testInfo.line,\n fileUrl: '',\n relativeFile: relative,\n },\n state: testInfo.status,\n duration: testInfo.duration,\n pending: false,\n sync: false,\n timedOut: undefined,\n type: ''\n },\n browser: {\n name: family,\n family,\n version,\n majorVersion: parseInt(version.split('.')[0], 10),\n displayName: testInfo.project.use?.channel?.toUpperCase?.() ?? family.charAt(0).toUpperCase() + family.slice(1),\n channel: testInfo.project.use?.channel ?? '',\n path: browserType.executablePath(),\n },\n recorderEvents: [] as RecorderEvent[],\n };\n return testRunContext\n}\n\nexport function deepMerge<T>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue &&\n typeof sourceValue === 'object' &&\n !Array.isArray(sourceValue) &&\n targetValue &&\n typeof targetValue === 'object' &&\n !Array.isArray(targetValue)\n ) {\n result[key] = deepMerge(targetValue, sourceValue);\n } else if (sourceValue !== undefined) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n result[key] = sourceValue as unknown;\n }\n }\n\n return result;\n}\n\nexport async function waitForRecorderStabilization(recorder: RRWebRecorder, timeout = 500) {\n const start = Date.now();\n let lastCount = recorder.getEvents().length;\n\n return new Promise<void>((resolve) => {\n const interval = setInterval(() => {\n const currentCount = recorder.getEvents().length;\n if (currentCount === lastCount || Date.now() - start > timeout) {\n clearInterval(interval);\n resolve();\n }\n lastCount = currentCount;\n }, 50);\n });\n}\n\nexport async function waitForNextRAF(page: Page) {\n await page.evaluate(() => new Promise<void>((r) => requestAnimationFrame(() => r())));\n}\n\nexport async function waitForRAF(\n pageOrFrame: Page | Frame,\n) {\n return await pageOrFrame.evaluate(() => {\n return new Promise((resolve) => {\n requestAnimationFrame(() => {\n requestAnimationFrame(resolve);\n });\n });\n });\n}\n\nexport function parseSerializedValue(value: SerializedValue, handles: any[] | undefined): any {\n return innerParseSerializedValue(value, handles, new Map(), []);\n}\n\nfunction innerParseSerializedValue(value: SerializedValue, handles: any[] | undefined, refs: Map<number, object>, accessChain: Array<string | number>): any {\n if (value.ref !== undefined)\n return refs.get(value.ref);\n if (value.n !== undefined)\n return value.n;\n if (value.s !== undefined)\n return value.s;\n if (value.b !== undefined)\n return value.b;\n if (value.v !== undefined) {\n if (value.v === 'undefined')\n return undefined;\n if (value.v === 'null')\n return null;\n if (value.v === 'NaN')\n return NaN;\n if (value.v === 'Infinity')\n return Infinity;\n if (value.v === '-Infinity')\n return -Infinity;\n if (value.v === '-0')\n return -0;\n }\n if (value.d !== undefined)\n return new Date(value.d);\n if (value.u !== undefined)\n return new URL(value.u);\n if (value.bi !== undefined)\n return BigInt(value.bi);\n if (value.e !== undefined) {\n const error = new Error(value.e.m);\n error.name = value.e.n;\n error.stack = value.e.s;\n return error;\n }\n if (value.r !== undefined)\n return new RegExp(value.r.p, value.r.f);\n if (value.ta !== undefined) {\n const ctor = typedArrayKindToConstructor[value.ta.k] as any;\n return new ctor(value.ta.b.buffer, value.ta.b.byteOffset, value.ta.b.length / ctor.BYTES_PER_ELEMENT);\n }\n\n if (value.a !== undefined) {\n const result: any[] = [];\n refs.set(value.id!, result);\n for (let i = 0; i < value.a.length; i++)\n result.push(innerParseSerializedValue(value.a[i], handles, refs, [...accessChain, i]));\n return result;\n }\n if (value.o !== undefined) {\n const result: any = {};\n refs.set(value.id!, result);\n for (const { k, v } of value.o)\n result[k] = innerParseSerializedValue(v, handles, refs, [...accessChain, k]);\n return result;\n }\n if (value.h !== undefined) {\n if (handles === undefined)\n throw new Error('Unexpected handle');\n return handles[value.h];\n }\n throw new Error(`Attempting to deserialize unexpected value${accessChainToDisplayString(accessChain)}: ${value}`);\n}\n\nexport type HandleOrValue = { h: number } | { fallThrough: any };\ntype VisitorInfo = {\n visited: Map<object, number>;\n lastId: number;\n};\n\nexport function serializeValue(value: any, handleSerializer: (value: any) => HandleOrValue): SerializedValue {\n return innerSerializeValue(value, handleSerializer, { lastId: 0, visited: new Map() }, []);\n}\n\nfunction innerSerializeValue(value: any, handleSerializer: (value: any) => HandleOrValue, visitorInfo: VisitorInfo, accessChain: Array<string | number>): SerializedValue {\n const handle = handleSerializer(value);\n if ('fallThrough' in handle)\n value = handle.fallThrough;\n else\n return handle;\n\n if (typeof value === 'symbol')\n return { v: 'undefined' };\n if (Object.is(value, undefined))\n return { v: 'undefined' };\n if (Object.is(value, null))\n return { v: 'null' };\n if (Object.is(value, NaN))\n return { v: 'NaN' };\n if (Object.is(value, Infinity))\n return { v: 'Infinity' };\n if (Object.is(value, -Infinity))\n return { v: '-Infinity' };\n if (Object.is(value, -0))\n return { v: '-0' };\n if (typeof value === 'boolean')\n return { b: value };\n if (typeof value === 'number')\n return { n: value };\n if (typeof value === 'string')\n return { s: value };\n if (typeof value === 'bigint')\n return { bi: value.toString() };\n if (isError(value))\n return { e: { n: value.name, m: value.message, s: value.stack || '' } };\n if (isDate(value))\n return { d: value.toJSON() };\n if (isURL(value))\n return { u: value.toJSON() };\n if (isRegExp(value))\n return { r: { p: value.source, f: value.flags } };\n\n const typedArrayKind = constructorToTypedArrayKind.get(value.constructor);\n if (typedArrayKind)\n return { ta: { b: Buffer.from(value.buffer, value.byteOffset, value.byteLength), k: typedArrayKind } };\n\n const id = visitorInfo.visited.get(value);\n if (id)\n return { ref: id };\n\n if (Array.isArray(value)) {\n const a = [];\n const id = ++visitorInfo.lastId;\n visitorInfo.visited.set(value, id);\n for (let i = 0; i < value.length; ++i)\n a.push(innerSerializeValue(value[i], handleSerializer, visitorInfo, [...accessChain, i]));\n return { a, id };\n }\n if (typeof value === 'object') {\n const o: { k: string, v: SerializedValue }[] = [];\n const id = ++visitorInfo.lastId;\n visitorInfo.visited.set(value, id);\n for (const name of Object.keys(value))\n o.push({ k: name, v: innerSerializeValue(value[name], handleSerializer, visitorInfo, [...accessChain, name]) });\n return { o, id };\n }\n throw new Error(`Attempting to serialize unexpected value${accessChainToDisplayString(accessChain)}: ${value}`);\n}\n\nfunction accessChainToDisplayString(accessChain: Array<string | number>): string {\n const chainString = accessChain.map((accessor, i) => {\n if (typeof accessor === 'string')\n return i ? `.${accessor}` : accessor;\n return `[${accessor}]`;\n }).join('');\n\n return chainString.length > 0 ? ` at position \"${chainString}\"` : '';\n}\n\nfunction isRegExp(obj: any): obj is RegExp {\n return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]';\n}\n\nfunction isDate(obj: any): obj is Date {\n return obj instanceof Date || Object.prototype.toString.call(obj) === '[object Date]';\n}\n\nfunction isURL(obj: any): obj is URL {\n return obj instanceof URL || Object.prototype.toString.call(obj) === '[object URL]';\n}\n\nfunction isError(obj: any): obj is Error {\n const proto = obj ? Object.getPrototypeOf(obj) : null;\n return obj instanceof Error || proto?.name === 'Error' || (proto && isError(proto));\n}\n\n\ntype TypedArrayKind = NonNullable<SerializedValue['ta']>['k'];\nconst typedArrayKindToConstructor: Record<TypedArrayKind, Function> = {\n i8: Int8Array,\n ui8: Uint8Array,\n ui8c: Uint8ClampedArray,\n i16: Int16Array,\n ui16: Uint16Array,\n i32: Int32Array,\n ui32: Uint32Array,\n f32: Float32Array,\n f64: Float64Array,\n bi64: BigInt64Array,\n bui64: BigUint64Array,\n};\n\nconst constructorToTypedArrayKind: Map<Function, TypedArrayKind> = new Map(Object.entries(typedArrayKindToConstructor).map(([k, v]) => [v, k as TypedArrayKind]));\n","import type { recordOptions } from '@appsurify-testmap/rrweb';\nimport { record } from '@appsurify-testmap/rrweb';\nimport type { Mirror } from '@appsurify-testmap/rrweb-snapshot';\nimport type { Page, JSHandle } from '@playwright/test';\nimport type { RecorderContext, RecorderEvent } from './types';\nimport type { eventWithTime, RecordPlugin } from '@appsurify-testmap/rrweb-types';\nimport { deepMerge } from '../utils';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport rrSrc from './releases/rrweb-record.umd.cjs.src';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport rrPluginSrc from './releases/rrweb-plugin-sequential-id-record.umd.cjs.src';\n\n\nexport const defaultRecordOptions: recordOptions<RecorderEvent> = {\n slimDOMOptions: 'all',\n inlineStylesheet: true,\n recordDOM: true,\n recordCanvas: true,\n collectFonts: true,\n inlineImages: true,\n checkoutEveryNvm: 60,\n maskInputOptions: { password: true },\n sampling: {\n mousemove: false,\n mouseInteraction: {\n MouseUp: false,\n MouseDown: false,\n Click: true,\n ContextMenu: true,\n DblClick: true,\n Focus: false,\n Blur: false,\n TouchStart: false,\n TouchEnd: false,\n },\n scroll: 100,\n media: 100,\n input: 'last',\n canvas: 'all',\n visibility: {\n mode: 'none',\n debounce: 50,\n throttle: 100,\n threshold: 0.5,\n sensitivity: 0.05,\n rafThrottle: 100\n }\n },\n flushCustomEvent: 'after',\n recordAfter: 'DOMContentLoaded',\n userTriggeredOnInput: true,\n}\n\ndeclare global {\n interface Window {\n rrweb?: {\n record?: typeof record;\n },\n stopFn: (() => void) | undefined | null,\n handleEmit: (event: RecorderEvent) => void,\n rrwebPluginSequentialIdRecord?: {\n getRecordSequentialIdPlugin: (options?: Partial<{key: string, getId?: () => number}>) => RecordPlugin;\n }\n }\n}\n\nexport class RRWebRecorder {\n private recordFn: JSHandle | null | undefined = null;\n private page: Page | null = null;\n private context: RecorderContext;\n private eventCounter = 0;\n private events: RecorderEvent[] = [];\n private recordOptions?: recordOptions<RecorderEvent>;\n private pendingEvents: {\n tag: string;\n payload: Record<string, unknown>;\n }[] = [];\n private recorderScriptVersion = 'unknown';\n private recorderLibVersion = 'unknown';\n public isRecording = false;\n\n constructor(options?: recordOptions<RecorderEvent>) {\n this.recordOptions = deepMerge(defaultRecordOptions, options ?? {});\n this.context = {\n pushEvent: (event) => this.events.push(event),\n };\n }\n\n private handleEmit(event: RecorderEvent) {\n if (event.type === 0 || event.type === 1) {\n return;\n }\n const rrEvent: RecorderEvent = {\n ...event,\n };\n this.context.pushEvent(rrEvent);\n }\n\n public async inject(page: Page) {\n this.page = page\n\n await this.page?.addInitScript({content: rrSrc as string});\n await this.page?.addInitScript({content: rrPluginSrc as string});\n\n await this.page?.exposeFunction('handleEmit', (event: RecorderEvent) => {\n this.handleEmit(event);\n });\n\n }\n\n public async start() {\n this.recordFn = await this.page?.evaluateHandle(() => {\n return window.rrweb?.record;\n });\n await this.recordFn?.evaluate((r: typeof record, optsJson) => {\n const opts = JSON.parse(optsJson) as recordOptions<RecorderEvent>;\n const plugins = [];\n if (window.rrwebPluginSequentialIdRecord) {\n plugins.push(\n window.rrwebPluginSequentialIdRecord.getRecordSequentialIdPlugin({\n key: 'id',\n })\n )\n }\n\n window.stopFn = r({\n emit: (event: RecorderEvent) => {\n // console.info(`[${event.timestamp}] [rrweb-recorder] ${event.type} ${event.data?.source} ${event.data?.href}`)\n window.handleEmit?.(event);\n },\n plugins: plugins,\n ...opts,\n })\n }, JSON.stringify(this.recordOptions));\n\n this.isRecording = await this.recordFn?.evaluate((r: typeof record) => r.isRecording()) as boolean;\n this.recorderScriptVersion = await this.recordFn?.evaluate((r: typeof record) => r.getVersion()) as string;\n\n await this.flush();\n }\n\n public async stop() {\n this.isRecording = false;\n if (this.recordFn && this.page && !this.page.isClosed()) {\n await this.flush();\n await this.page.evaluate(() => {\n window.stopFn = null;\n });\n }\n }\n\n public async reset() {\n this.eventCounter = 0;\n this.events = [];\n await this.stop();\n this.context = {\n pushEvent: (event) => this.events.push(event),\n };\n }\n\n public async flush() {\n if (!this.recordFn) return;\n const stillPending: typeof this.pendingEvents = [];\n for (const evt of this.pendingEvents) {\n try {\n await this.recordFn.evaluate((r: typeof record, evt) => {\n r.addCustomEvent(evt.tag, evt.payload)\n }, evt);\n } catch (error) {\n console.debug(`[${Date.now()}] [recorder] flush failed for custom event: ${evt.tag}`);\n stillPending.push(evt);\n }\n }\n this.pendingEvents = stillPending;\n }\n\n public async addCustomEvent(tag: string, payload: Record<string, unknown>) {\n const event = { tag, payload };\n\n if (!this.recordFn || !this.isRecording) {\n console.debug(`[${Date.now()}] [recorder] queued custom event (recorder not ready): ${tag}`);\n this.pendingEvents.push(event);\n return;\n }\n\n try {\n await this.recordFn.evaluate((r: typeof record, evt) => {\n r.addCustomEvent(evt.tag, evt.payload)\n }, event);\n } catch (error) {\n this.pendingEvents.push(event);\n }\n\n }\n\n public isRecordingReady(): boolean {\n return !!this.recordFn && this.isRecording;\n }\n\n public getScriptVersion(): string {\n return `@appsurify-testmap/rrweb-record:${this.recorderScriptVersion}`;\n }\n\n public getLibVersion(): string {\n return `@appsurify-testmap/rrweb:${this.recorderLibVersion !== 'unknown' ? this.recorderLibVersion : this.recorderScriptVersion}`;\n }\n\n public getEvents(): readonly RecorderEvent[] {\n return this.events;\n }\n\n public getMirror(): Mirror | undefined {\n return (this.recordFn as unknown as { mirror?: Mirror })?.mirror;\n }\n\n public bind(ctx: RecorderContext) {\n this.context = ctx;\n }\n\n public setEventCounter(value: number) {\n this.eventCounter = value;\n }\n\n}\n","import { RRWebRecorder } from './RRWebRecorder';\n\n\nexport default RRWebRecorder;\n","import type { TestRunContext } from './types';\n\nexport const testContexts = new Map<string, TestRunContext>();\n\nexport function setCurrentTestContext(key: string, ctx: TestRunContext): void {\n testContexts.set(key, ctx);\n}\n\nexport function getCurrentTestContext(key: string): TestRunContext | undefined {\n return testContexts.get(key);\n}\n\nexport function clearTestContext(key: string): void {\n testContexts.delete(key);\n}\n"],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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","names":["base","expect","os","path","fs","defaultOutputReportDir","aggregateCleared","writeFileAtomic","filePath","data","dir","tmp","readJsonArraySafe","text","parsed","saveRRWebReport","testRunResult","outputReportDir","reportDir","specName","sanitizeFileNamePart","suiteTitle","testTitle","browserName","jsonFileNameRaw","jsonFilePathRaw","reportRaw","aggregatePath","current","e","name","createTestrunContext","browser","testInfo","browserType","version","family","absolute","relative","baseName","fileName","fileExtension","suiteTitlePath","deepMerge","target","source","result","key","sourceValue","targetValue","waitForRecorderStabilization","recorder","timeout","start","lastCount","resolve","interval","currentCount","waitForNextRAF","page","r","typedArrayKindToConstructor","constructorToTypedArrayKind","k","v","defaultRecordOptions","RRWebRecorder","options","deepMerge","event","rrEvent","page","rrweb_record_umd_cjs_default","rrweb_plugin_sequential_id_record_umd_cjs_default","r","optsJson","opts","plugins","stillPending","evt","tag","payload","ctx","value","recorder_default","RRWebRecorder","testContexts","setCurrentTestContext","key","ctx","getCurrentTestContext","test","base","browser","use","testInfo","context","testRunContext","createTestrunContext","setCurrentTestContext","page","testmapConfig","recordingOpts","recorder_default","recorder","getCurrentTestContext","event","consoleMessage","originalonStepEnd","stepEndPayload","currentStepInfo","waitForNextRAF","originalonDidFinishTestFunction","waitForRecorderStabilization","testRunResult","saveRRWebReport"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/recorder/RRWebRecorder.ts","../src/recorder/index.ts","../src/runtime.ts"],"sourcesContent":["import {\n test as base,\n expect,\n} from '@playwright/test';\nimport type {\n ConsoleMessage,\n} from '@playwright/test';\nimport RRWebRecorder from './recorder';\nimport defaultRecordOptions from './recorder';\n\nimport {\n createTestrunContext,\n saveRRWebReport,\n waitForNextRAF,\n waitForRecorderStabilization,\n} from './utils';\nimport {\n getCurrentTestContext,\n setCurrentTestContext,\n} from './runtime';\n\nimport type {\n TestmapConfig\n} from './types';\n\n\nconst test = base.extend<{}>({\n browser: async ({ browser }, use) => {\n await use(browser);\n },\n\n context: async ({ browser }, use, testInfo) => {\n const context = await browser.newContext();\n const testRunContext = createTestrunContext(browser, testInfo);\n setCurrentTestContext(testInfo.testId, testRunContext);\n await use(context);\n await context.close();\n },\n\n page: async ({ page }, use, testInfo) => {\n\n type ExtendedUse = typeof testInfo.project.use & { testmap?: TestmapConfig };\n const pwConfig = testInfo.project.use as ExtendedUse;\n const testmapConfig = pwConfig.testmap ?? {};\n const recordingOpts =\n typeof testmapConfig === 'object' && 'recordingOpts' in testmapConfig\n ? testmapConfig.recordingOpts\n : defaultRecordOptions;\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n // @ts-ignore\n const recorder = new RRWebRecorder(recordingOpts);\n\n const testRunContext = getCurrentTestContext(testInfo.testId);\n if (testRunContext) {\n testRunContext.recorderInstance = recorder;\n }\n\n recorder.bind({\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n pushEvent: async (event) => {\n testRunContext?.recorderEvents.push(event);\n await Promise.resolve();\n },\n });\n await recorder.inject(page);\n\n // eslint-disable-next-line @typescript-eslint/require-await\n page.on('console', async (consoleMessage: ConsoleMessage) => {\n if (consoleMessage.type() === 'debug') return;\n console.debug(`[${Date.now()}] [page] console`, consoleMessage.text());\n });\n\n page.on('load', async () => {\n /* empty */\n });\n\n page.on('domcontentloaded', async () => {\n await recorder.start();\n if (testRunContext?.runner) {\n testRunContext.runner.recorder = {\n scriptVersion: recorder.getScriptVersion(),\n libVersion: recorder.getLibVersion(),\n };\n }\n });\n page.on('framenavigated', async () => {\n /* empty */\n });\n\n page.on('close', async () => {\n await recorder.flush();\n });\n\n // @ts-ignore\n const originalonStepEnd = testInfo._onStepEnd.bind(this);\n // @ts-ignore\n testInfo._onStepEnd = async (stepEndPayload: {\n testId: string;\n stepId: string;\n wallTime: number;\n error?: unknown;\n suggestedRebaseline?: string;\n annotations: { type: string, description?: string }[];\n }) => {\n\n // @ts-ignore\n const currentStepInfo = testInfo._stepMap.get(stepEndPayload.stepId);\n if (currentStepInfo.apiName && currentStepInfo?.location.file === testInfo.file) {\n await recorder.addCustomEvent(currentStepInfo.apiName, {\n stepId: currentStepInfo.stepId,\n category: currentStepInfo.category,\n location: currentStepInfo.location,\n title: currentStepInfo.title,\n apiName: currentStepInfo.apiName,\n endWallTime: currentStepInfo.endWallTime,\n });\n\n }\n if (!page.isClosed()) {\n try {\n await waitForNextRAF(page);\n } catch (error) { /* empty */ }\n }\n await originalonStepEnd(stepEndPayload);\n };\n\n // @ts-ignore\n const originalonDidFinishTestFunction = testInfo._onDidFinishTestFunction.bind(this);\n // @ts-ignore\n testInfo._onDidFinishTestFunction = async () => {\n\n if (recorder && recorder.isRecordingReady()) {\n await waitForRecorderStabilization(recorder, 500);\n await recorder.stop();\n }\n\n await originalonDidFinishTestFunction();\n }\n\n await use(page);\n\n\n },\n});\n\ntest.beforeEach(async ({}, testInfo) => {\n console.log(`[${Date.now()}] [🟢 TEST START] ${testInfo.title}`);\n\n});\n\ntest.afterEach(async ({}, testInfo) => {\n console.log(`[${Date.now()}] [🔴 TEST END] ${testInfo.title}`);\n const testRunContext = getCurrentTestContext(testInfo.testId);\n if (!testRunContext) return;\n\n testRunContext.test.duration = testInfo.duration;\n const testRunResult = {\n runner: testRunContext?.runner,\n spec: testRunContext?.spec,\n browser: testRunContext?.browser,\n test: testRunContext?.test,\n suite: testRunContext?.test.suite,\n recorderEvents: Array.isArray(testRunContext?.recorderEvents) ? testRunContext?.recorderEvents : []\n }\n\n type ExtendedUse = typeof testInfo.project.use & { testmap?: TestmapConfig };\n const pwConfig = testInfo.project.use as ExtendedUse;\n const testmapConfig = pwConfig.testmap ?? {};\n\n saveRRWebReport(testRunResult, testmapConfig.outputReportDir)\n\n});\n\nexport { test, expect };\n\n","import os from 'os';\nimport path from 'path';\nimport fs from 'fs';\nimport { Browser, Page, Frame, TestInfo } from '@playwright/test';\nimport type { RecorderEvent } from './recorder/types';\nimport type { TestRunContext, TestRunResult, SerializedValue } from './types';\nimport RRWebRecorder from \"./recorder\";\n\nconst defaultOutputReportDir = 'test-results/playwright/ui';\n\n// Tracks whether the aggregate report has been cleared in this process.\n// Ensures the file is reset once per test run (process lifetime).\nlet aggregateCleared = false;\n\nfunction writeFileAtomic(filePath: string, data: string) {\n const dir = path.dirname(filePath);\n const tmp = path.join(dir, `.${path.basename(filePath)}.tmp-${process.pid}-${Date.now()}`);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(tmp, data, 'utf-8');\n fs.renameSync(tmp, filePath);\n}\n\nfunction readJsonArraySafe(filePath: string): unknown[] {\n try {\n if (!fs.existsSync(filePath)) return [];\n const text = fs.readFileSync(filePath, 'utf-8').trim();\n if (!text) return [];\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const parsed = JSON.parse(text);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nexport function saveRRWebReport(testRunResult: TestRunResult, outputReportDir?: string) {\n const reportDir = outputReportDir !== undefined ? outputReportDir : defaultOutputReportDir;\n const specName = sanitizeFileNamePart(testRunResult.spec.name);\n const suiteTitle = sanitizeFileNamePart(testRunResult.test.suite?.title);\n const testTitle = sanitizeFileNamePart(testRunResult.test.title);\n const browserName = testRunResult.browser.name;\n\n const jsonFileNameRaw = `${suiteTitle ? suiteTitle + '-' : ''}${testTitle}.json`;\n const jsonFilePathRaw = path.join(reportDir, specName, browserName, jsonFileNameRaw);\n const reportRaw = {\n events: testRunResult.recorderEvents,\n metadata: {\n runner: testRunResult.runner,\n spec: testRunResult.spec,\n suite: testRunResult.test.suite,\n test: testRunResult.test,\n browser: testRunResult.browser,\n }\n };\n fs.mkdirSync(reportDir, { recursive: true });\n fs.mkdirSync(path.dirname(jsonFilePathRaw), { recursive: true });\n fs.writeFileSync(jsonFilePathRaw, JSON.stringify(reportRaw, null, 2), 'utf-8');\n console.log(`[ui-coverage] Saved report to ${jsonFilePathRaw}`);\n\n try {\n const aggregatePath = path.join(reportDir, \"ui-coverage-aggregated.json\");\n // On first call in this process, start a fresh aggregate file so it\n // only contains results from the current run.\n const current = aggregateCleared ? readJsonArraySafe(aggregatePath) : [];\n aggregateCleared = true;\n current.push(reportRaw);\n writeFileAtomic(aggregatePath, JSON.stringify(current, null, 2));\n console.log(`[ui-coverage] Updated aggregate: ${aggregatePath}`);\n } catch (e) {\n console.warn('[ui-coverage] Failed to update aggregate report:', e);\n }\n}\n\nexport function sanitizeFileNamePart(name: string | undefined): string {\n return (name ?? '')\n .trim()\n .replace(/[\\s:/\\\\<>|\"'?*]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\nexport function createTestrunContext(browser: Browser, testInfo: TestInfo): TestRunContext {\n const browserType = browser.browserType();\n const version = browser.version();\n const family = browserType.name();\n\n const absolute = testInfo.file;\n const relative = absolute.replace(process.cwd(), '').replace(/^[/\\\\]/, '');\n const baseName = relative.split(/[\\\\/]/).pop() ?? '';\n const [fileName, fileExtension] = baseName.split(/\\.(?=[^\\\\.]+$)/);\n\n const suiteTitlePath = testInfo.titlePath.slice(1, -1); // всё кроме последнего (сам тест)\n const suiteTitle = suiteTitlePath.join(' > ') || 'Root Suite';\n\n const testRunContext: TestRunContext = {\n runner: {\n source: 'playwright',\n type: 'unknown',\n version: testInfo.config.version,\n platform: os.platform(),\n arch: os.arch(),\n recorder: {\n scriptVersion: 'unknown',\n libVersion: 'unknown'\n }\n\n },\n spec: {\n name: baseName,\n relative,\n absolute,\n baseName,\n fileName,\n fileExtension,\n id: relative,\n },\n test: {\n suite: {\n id: suiteTitlePath.join('::') || 'root',\n invocationDetails: {\n absoluteFile: absolute,\n column: testInfo.column ?? 0,\n line: testInfo.line ?? 0,\n fileUrl: undefined,\n function: undefined,\n originalFile: undefined,\n relativeFile: relative,\n },\n pending: false,\n root: suiteTitlePath.length === 0,\n title: suiteTitle,\n type: \"unknown\"\n },\n id: testInfo.testId,\n title: testInfo.title,\n titlePath: testInfo.titlePath.slice(1),\n fullTitle: testInfo.titlePath.slice(1).join(' '),\n file: testInfo.file,\n invocationDetails: {\n absoluteFile: absolute,\n column: testInfo.column,\n line: testInfo.line,\n fileUrl: '',\n relativeFile: relative,\n },\n state: testInfo.status,\n duration: testInfo.duration,\n pending: false,\n sync: false,\n timedOut: undefined,\n type: ''\n },\n browser: {\n name: family,\n family,\n version,\n majorVersion: parseInt(version.split('.')[0], 10),\n displayName: testInfo.project.use?.channel?.toUpperCase?.() ?? family.charAt(0).toUpperCase() + family.slice(1),\n channel: testInfo.project.use?.channel ?? '',\n path: browserType.executablePath(),\n },\n recorderEvents: [] as RecorderEvent[],\n };\n return testRunContext\n}\n\nexport function deepMerge<T>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue &&\n typeof sourceValue === 'object' &&\n !Array.isArray(sourceValue) &&\n targetValue &&\n typeof targetValue === 'object' &&\n !Array.isArray(targetValue)\n ) {\n result[key] = deepMerge(targetValue, sourceValue);\n } else if (sourceValue !== undefined) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n result[key] = sourceValue as unknown;\n }\n }\n\n return result;\n}\n\nexport async function waitForRecorderStabilization(recorder: RRWebRecorder, timeout = 500) {\n const start = Date.now();\n let lastCount = recorder.getEvents().length;\n\n return new Promise<void>((resolve) => {\n const interval = setInterval(() => {\n const currentCount = recorder.getEvents().length;\n if (currentCount === lastCount || Date.now() - start > timeout) {\n clearInterval(interval);\n resolve();\n }\n lastCount = currentCount;\n }, 50);\n });\n}\n\nexport async function waitForNextRAF(page: Page) {\n await page.evaluate(() => new Promise<void>((r) => requestAnimationFrame(() => r())));\n}\n\nexport async function waitForRAF(\n pageOrFrame: Page | Frame,\n) {\n return await pageOrFrame.evaluate(() => {\n return new Promise((resolve) => {\n requestAnimationFrame(() => {\n requestAnimationFrame(resolve);\n });\n });\n });\n}\n\nexport function parseSerializedValue(value: SerializedValue, handles: any[] | undefined): any {\n return innerParseSerializedValue(value, handles, new Map(), []);\n}\n\nfunction innerParseSerializedValue(value: SerializedValue, handles: any[] | undefined, refs: Map<number, object>, accessChain: Array<string | number>): any {\n if (value.ref !== undefined)\n return refs.get(value.ref);\n if (value.n !== undefined)\n return value.n;\n if (value.s !== undefined)\n return value.s;\n if (value.b !== undefined)\n return value.b;\n if (value.v !== undefined) {\n if (value.v === 'undefined')\n return undefined;\n if (value.v === 'null')\n return null;\n if (value.v === 'NaN')\n return NaN;\n if (value.v === 'Infinity')\n return Infinity;\n if (value.v === '-Infinity')\n return -Infinity;\n if (value.v === '-0')\n return -0;\n }\n if (value.d !== undefined)\n return new Date(value.d);\n if (value.u !== undefined)\n return new URL(value.u);\n if (value.bi !== undefined)\n return BigInt(value.bi);\n if (value.e !== undefined) {\n const error = new Error(value.e.m);\n error.name = value.e.n;\n error.stack = value.e.s;\n return error;\n }\n if (value.r !== undefined)\n return new RegExp(value.r.p, value.r.f);\n if (value.ta !== undefined) {\n const ctor = typedArrayKindToConstructor[value.ta.k] as any;\n return new ctor(value.ta.b.buffer, value.ta.b.byteOffset, value.ta.b.length / ctor.BYTES_PER_ELEMENT);\n }\n\n if (value.a !== undefined) {\n const result: any[] = [];\n refs.set(value.id!, result);\n for (let i = 0; i < value.a.length; i++)\n result.push(innerParseSerializedValue(value.a[i], handles, refs, [...accessChain, i]));\n return result;\n }\n if (value.o !== undefined) {\n const result: any = {};\n refs.set(value.id!, result);\n for (const { k, v } of value.o)\n result[k] = innerParseSerializedValue(v, handles, refs, [...accessChain, k]);\n return result;\n }\n if (value.h !== undefined) {\n if (handles === undefined)\n throw new Error('Unexpected handle');\n return handles[value.h];\n }\n throw new Error(`Attempting to deserialize unexpected value${accessChainToDisplayString(accessChain)}: ${value}`);\n}\n\nexport type HandleOrValue = { h: number } | { fallThrough: any };\ntype VisitorInfo = {\n visited: Map<object, number>;\n lastId: number;\n};\n\nexport function serializeValue(value: any, handleSerializer: (value: any) => HandleOrValue): SerializedValue {\n return innerSerializeValue(value, handleSerializer, { lastId: 0, visited: new Map() }, []);\n}\n\nfunction innerSerializeValue(value: any, handleSerializer: (value: any) => HandleOrValue, visitorInfo: VisitorInfo, accessChain: Array<string | number>): SerializedValue {\n const handle = handleSerializer(value);\n if ('fallThrough' in handle)\n value = handle.fallThrough;\n else\n return handle;\n\n if (typeof value === 'symbol')\n return { v: 'undefined' };\n if (Object.is(value, undefined))\n return { v: 'undefined' };\n if (Object.is(value, null))\n return { v: 'null' };\n if (Object.is(value, NaN))\n return { v: 'NaN' };\n if (Object.is(value, Infinity))\n return { v: 'Infinity' };\n if (Object.is(value, -Infinity))\n return { v: '-Infinity' };\n if (Object.is(value, -0))\n return { v: '-0' };\n if (typeof value === 'boolean')\n return { b: value };\n if (typeof value === 'number')\n return { n: value };\n if (typeof value === 'string')\n return { s: value };\n if (typeof value === 'bigint')\n return { bi: value.toString() };\n if (isError(value))\n return { e: { n: value.name, m: value.message, s: value.stack || '' } };\n if (isDate(value))\n return { d: value.toJSON() };\n if (isURL(value))\n return { u: value.toJSON() };\n if (isRegExp(value))\n return { r: { p: value.source, f: value.flags } };\n\n const typedArrayKind = constructorToTypedArrayKind.get(value.constructor);\n if (typedArrayKind)\n return { ta: { b: Buffer.from(value.buffer, value.byteOffset, value.byteLength), k: typedArrayKind } };\n\n const id = visitorInfo.visited.get(value);\n if (id)\n return { ref: id };\n\n if (Array.isArray(value)) {\n const a = [];\n const id = ++visitorInfo.lastId;\n visitorInfo.visited.set(value, id);\n for (let i = 0; i < value.length; ++i)\n a.push(innerSerializeValue(value[i], handleSerializer, visitorInfo, [...accessChain, i]));\n return { a, id };\n }\n if (typeof value === 'object') {\n const o: { k: string, v: SerializedValue }[] = [];\n const id = ++visitorInfo.lastId;\n visitorInfo.visited.set(value, id);\n for (const name of Object.keys(value))\n o.push({ k: name, v: innerSerializeValue(value[name], handleSerializer, visitorInfo, [...accessChain, name]) });\n return { o, id };\n }\n throw new Error(`Attempting to serialize unexpected value${accessChainToDisplayString(accessChain)}: ${value}`);\n}\n\nfunction accessChainToDisplayString(accessChain: Array<string | number>): string {\n const chainString = accessChain.map((accessor, i) => {\n if (typeof accessor === 'string')\n return i ? `.${accessor}` : accessor;\n return `[${accessor}]`;\n }).join('');\n\n return chainString.length > 0 ? ` at position \"${chainString}\"` : '';\n}\n\nfunction isRegExp(obj: any): obj is RegExp {\n return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]';\n}\n\nfunction isDate(obj: any): obj is Date {\n return obj instanceof Date || Object.prototype.toString.call(obj) === '[object Date]';\n}\n\nfunction isURL(obj: any): obj is URL {\n return obj instanceof URL || Object.prototype.toString.call(obj) === '[object URL]';\n}\n\nfunction isError(obj: any): obj is Error {\n const proto = obj ? Object.getPrototypeOf(obj) : null;\n return obj instanceof Error || proto?.name === 'Error' || (proto && isError(proto));\n}\n\n\ntype TypedArrayKind = NonNullable<SerializedValue['ta']>['k'];\nconst typedArrayKindToConstructor: Record<TypedArrayKind, Function> = {\n i8: Int8Array,\n ui8: Uint8Array,\n ui8c: Uint8ClampedArray,\n i16: Int16Array,\n ui16: Uint16Array,\n i32: Int32Array,\n ui32: Uint32Array,\n f32: Float32Array,\n f64: Float64Array,\n bi64: BigInt64Array,\n bui64: BigUint64Array,\n};\n\nconst constructorToTypedArrayKind: Map<Function, TypedArrayKind> = new Map(Object.entries(typedArrayKindToConstructor).map(([k, v]) => [v, k as TypedArrayKind]));\n","import type { recordOptions } from '@appsurify-testmap/rrweb';\nimport { record } from '@appsurify-testmap/rrweb';\nimport type { Mirror } from '@appsurify-testmap/rrweb-snapshot';\nimport type { Page, JSHandle } from '@playwright/test';\nimport type { RecorderContext, RecorderEvent } from './types';\nimport type { eventWithTime, RecordPlugin } from '@appsurify-testmap/rrweb-types';\nimport { deepMerge } from '../utils';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport rrSrc from './releases/rrweb-record.umd.cjs.src';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport rrPluginSrc from './releases/rrweb-plugin-sequential-id-record.umd.cjs.src';\n\n\nexport const defaultRecordOptions: recordOptions<RecorderEvent> = {\n slimDOMOptions: 'all',\n inlineStylesheet: true,\n recordDOM: true,\n recordCanvas: true,\n collectFonts: true,\n inlineImages: true,\n checkoutEveryNvm: 60,\n maskInputOptions: { password: true },\n sampling: {\n mousemove: false,\n mouseInteraction: {\n MouseUp: false,\n MouseDown: false,\n Click: true,\n ContextMenu: true,\n DblClick: true,\n Focus: false,\n Blur: false,\n TouchStart: false,\n TouchEnd: false,\n },\n scroll: 100,\n media: 100,\n input: 'last',\n canvas: 'all',\n visibility: {\n mode: 'none',\n debounce: 50,\n throttle: 100,\n threshold: 0.5,\n sensitivity: 0.05,\n rafThrottle: 100\n }\n },\n flushCustomEvent: 'after',\n recordAfter: 'DOMContentLoaded',\n userTriggeredOnInput: true,\n}\n\ndeclare global {\n interface Window {\n rrweb?: {\n record?: typeof record;\n },\n stopFn: (() => void) | undefined | null,\n handleEmit: (event: RecorderEvent) => void,\n rrwebPluginSequentialIdRecord?: {\n getRecordSequentialIdPlugin: (options?: Partial<{key: string, getId?: () => number}>) => RecordPlugin;\n }\n }\n}\n\nexport class RRWebRecorder {\n private recordFn: JSHandle | null | undefined = null;\n private page: Page | null = null;\n private context: RecorderContext;\n private eventCounter = 0;\n private events: RecorderEvent[] = [];\n private recordOptions?: recordOptions<RecorderEvent>;\n private pendingEvents: {\n tag: string;\n payload: Record<string, unknown>;\n }[] = [];\n private recorderScriptVersion = 'unknown';\n private recorderLibVersion = 'unknown';\n public isRecording = false;\n\n constructor(options?: recordOptions<RecorderEvent>) {\n this.recordOptions = deepMerge(defaultRecordOptions, options ?? {});\n this.context = {\n pushEvent: (event) => this.events.push(event),\n };\n }\n\n private handleEmit(event: RecorderEvent) {\n if (event.type === 0 || event.type === 1) {\n return;\n }\n const rrEvent: RecorderEvent = {\n ...event,\n };\n this.context.pushEvent(rrEvent);\n }\n\n public async inject(page: Page) {\n this.page = page\n\n await this.page?.addInitScript({content: rrSrc as string});\n await this.page?.addInitScript({content: rrPluginSrc as string});\n\n await this.page?.exposeFunction('handleEmit', (event: RecorderEvent) => {\n this.handleEmit(event);\n });\n\n }\n\n public async start() {\n this.recordFn = await this.page?.evaluateHandle(() => {\n return window.rrweb?.record;\n });\n await this.recordFn?.evaluate((r: typeof record, optsJson) => {\n const opts = JSON.parse(optsJson) as recordOptions<RecorderEvent>;\n const plugins = [];\n if (window.rrwebPluginSequentialIdRecord) {\n plugins.push(\n window.rrwebPluginSequentialIdRecord.getRecordSequentialIdPlugin({\n key: 'id',\n })\n )\n }\n\n window.stopFn = r({\n emit: (event: RecorderEvent) => {\n // console.info(`[${event.timestamp}] [rrweb-recorder] ${event.type} ${event.data?.source} ${event.data?.href}`)\n window.handleEmit?.(event);\n },\n plugins: plugins,\n ...opts,\n })\n }, JSON.stringify(this.recordOptions));\n\n this.isRecording = await this.recordFn?.evaluate((r: typeof record) => r.isRecording()) as boolean;\n this.recorderScriptVersion = await this.recordFn?.evaluate((r: typeof record) => r.getVersion()) as string;\n\n await this.flush();\n }\n\n public async stop() {\n this.isRecording = false;\n if (this.recordFn && this.page && !this.page.isClosed()) {\n await this.flush();\n await this.page.evaluate(() => {\n window.stopFn = null;\n });\n }\n }\n\n public async reset() {\n this.eventCounter = 0;\n this.events = [];\n await this.stop();\n this.context = {\n pushEvent: (event) => this.events.push(event),\n };\n }\n\n public async flush() {\n if (!this.recordFn) return;\n const stillPending: typeof this.pendingEvents = [];\n for (const evt of this.pendingEvents) {\n try {\n await this.recordFn.evaluate((r: typeof record, evt) => {\n r.addCustomEvent(evt.tag, evt.payload)\n }, evt);\n } catch (error) {\n console.debug(`[${Date.now()}] [recorder] flush failed for custom event: ${evt.tag}`);\n stillPending.push(evt);\n }\n }\n this.pendingEvents = stillPending;\n }\n\n public async addCustomEvent(tag: string, payload: Record<string, unknown>) {\n const event = { tag, payload };\n\n if (!this.recordFn || !this.isRecording) {\n console.debug(`[${Date.now()}] [recorder] queued custom event (recorder not ready): ${tag}`);\n this.pendingEvents.push(event);\n return;\n }\n\n try {\n await this.recordFn.evaluate((r: typeof record, evt) => {\n r.addCustomEvent(evt.tag, evt.payload)\n }, event);\n } catch (error) {\n this.pendingEvents.push(event);\n }\n\n }\n\n public isRecordingReady(): boolean {\n return !!this.recordFn && this.isRecording;\n }\n\n public getScriptVersion(): string {\n return `@appsurify-testmap/rrweb-record:${this.recorderScriptVersion}`;\n }\n\n public getLibVersion(): string {\n return `@appsurify-testmap/rrweb:${this.recorderLibVersion !== 'unknown' ? this.recorderLibVersion : this.recorderScriptVersion}`;\n }\n\n public getEvents(): readonly RecorderEvent[] {\n return this.events;\n }\n\n public getMirror(): Mirror | undefined {\n return (this.recordFn as unknown as { mirror?: Mirror })?.mirror;\n }\n\n public bind(ctx: RecorderContext) {\n this.context = ctx;\n }\n\n public setEventCounter(value: number) {\n this.eventCounter = value;\n }\n\n}\n","import { RRWebRecorder } from './RRWebRecorder';\n\n\nexport default RRWebRecorder;\n","import type { TestRunContext } from './types';\n\nexport const testContexts = new Map<string, TestRunContext>();\n\nexport function setCurrentTestContext(key: string, ctx: TestRunContext): void {\n testContexts.set(key, ctx);\n}\n\nexport function getCurrentTestContext(key: string): TestRunContext | undefined {\n return testContexts.get(key);\n}\n\nexport function clearTestContext(key: string): void {\n testContexts.delete(key);\n}\n"],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC1YzJ,IAAME,EAAqD,CAC9D,eAAgB,MAChB,iBAAkB,GAClB,UAAW,GACX,aAAc,GACd,aAAc,GACd,aAAc,GACd,iBAAkB,GAClB,iBAAkB,CAAE,SAAU,EAAK,EACnC,SAAU,CACR,UAAW,GACX,iBAAkB,CAChB,QAAS,GACT,UAAW,GACX,MAAO,GACP,YAAa,GACb,SAAU,GACV,MAAO,GACP,KAAM,GACN,WAAY,GACZ,SAAU,EACZ,EACA,OAAQ,IACR,MAAO,IACP,MAAO,OACP,OAAQ,MACR,WAAY,CACV,KAAM,OACN,SAAU,GACV,SAAU,IACV,UAAW,GACX,YAAa,IACb,YAAa,GACf,CACF,EACA,iBAAkB,QAClB,YAAa,mBACb,qBAAsB,EAC1B,EAeaC,EAAN,KAAoB,CACjB,SAAwC,KACxC,KAAoB,KACpB,QACA,aAAe,EACf,OAA0B,CAAC,EAC3B,cACA,cAGF,CAAC,EACC,sBAAwB,UACxB,mBAAqB,UACtB,YAAc,GAErB,YAAYC,EAAwC,CAClD,KAAK,cAAgBC,EAAUH,EAAsBE,GAAW,CAAC,CAAC,EAClE,KAAK,QAAU,CACb,UAAYE,GAAU,KAAK,OAAO,KAAKA,CAAK,CAC9C,CACF,CAEQ,WAAWA,EAAsB,CACvC,GAAIA,EAAM,OAAS,GAAKA,EAAM,OAAS,EACrC,OAEF,IAAMC,EAAyB,CAC7B,GAAGD,CACL,EACA,KAAK,QAAQ,UAAUC,CAAO,CAChC,CAEA,MAAa,OAAOC,EAAY,CAC9B,KAAK,KAAOA,EAEZ,MAAM,KAAK,MAAM,cAAc,CAAC,QAASC,CAAe,CAAC,EACzD,MAAM,KAAK,MAAM,cAAc,CAAC,QAASC,CAAqB,CAAC,EAE/D,MAAM,KAAK,MAAM,eAAe,aAAeJ,GAAyB,CACtE,KAAK,WAAWA,CAAK,CACvB,CAAC,CAEH,CAEA,MAAa,OAAQ,CACnB,KAAK,SAAW,MAAM,KAAK,MAAM,eAAe,IACvC,OAAO,OAAO,MACtB,EACD,MAAM,KAAK,UAAU,SAAS,CAACK,EAAkBC,IAAa,CAC5D,IAAMC,EAAO,KAAK,MAAMD,CAAQ,EAC1BE,EAAU,CAAC,EACb,OAAO,+BACTA,EAAQ,KACN,OAAO,8BAA8B,4BAA4B,CAC/D,IAAK,IACP,CAAC,CACH,EAGF,OAAO,OAASH,EAAE,CAChB,KAAOL,GAAyB,CAE9B,OAAO,aAAaA,CAAK,CAC3B,EACA,QAASQ,EACT,GAAGD,CACL,CAAC,CACH,EAAG,KAAK,UAAU,KAAK,aAAa,CAAC,EAErC,KAAK,YAAc,MAAM,KAAK,UAAU,SAAUF,GAAqBA,EAAE,YAAY,CAAC,EACtF,KAAK,sBAAwB,MAAM,KAAK,UAAU,SAAUA,GAAqBA,EAAE,WAAW,CAAC,EAE/F,MAAM,KAAK,MAAM,CACnB,CAEA,MAAa,MAAO,CAClB,KAAK,YAAc,GACf,KAAK,UAAY,KAAK,MAAQ,CAAC,KAAK,KAAK,SAAS,IACpD,MAAM,KAAK,MAAM,EACjB,MAAM,KAAK,KAAK,SAAS,IAAM,CAC7B,OAAO,OAAS,IAClB,CAAC,EAEL,CAEA,MAAa,OAAQ,CACnB,KAAK,aAAe,EACpB,KAAK,OAAS,CAAC,EACf,MAAM,KAAK,KAAK,EAChB,KAAK,QAAU,CACb,UAAYL,GAAU,KAAK,OAAO,KAAKA,CAAK,CAC9C,CACF,CAEA,MAAa,OAAQ,CACnB,GAAI,CAAC,KAAK,SAAU,OACpB,IAAMS,EAA0C,CAAC,EACjD,QAAWC,KAAO,KAAK,cACrB,GAAI,CACF,MAAM,KAAK,SAAS,SAAS,CAAC,EAAkBA,IAAQ,CACtD,EAAE,eAAeA,EAAI,IAAKA,EAAI,OAAO,CACvC,EAAGA,CAAG,CACR,MAAE,CACA,QAAQ,MAAM,IAAI,KAAK,IAAI,gDAAgDA,EAAI,KAAK,EACpFD,EAAa,KAAKC,CAAG,CACvB,CAEF,KAAK,cAAgBD,CACvB,CAEA,MAAa,eAAeE,EAAaC,EAAkC,CACzE,IAAMZ,EAAQ,CAAE,IAAAW,EAAK,QAAAC,CAAQ,EAE7B,GAAI,CAAC,KAAK,UAAY,CAAC,KAAK,YAAa,CACvC,QAAQ,MAAM,IAAI,KAAK,IAAI,2DAA2DD,GAAK,EAC3F,KAAK,cAAc,KAAKX,CAAK,EAC7B,OAGF,GAAI,CACF,MAAM,KAAK,SAAS,SAAS,CAACK,EAAkBK,IAAQ,CACtDL,EAAE,eAAeK,EAAI,IAAKA,EAAI,OAAO,CACvC,EAAGV,CAAK,CACV,MAAE,CACA,KAAK,cAAc,KAAKA,CAAK,CAC/B,CAEF,CAEO,kBAA4B,CACjC,MAAO,CAAC,CAAC,KAAK,UAAY,KAAK,WACjC,CAEO,kBAA2B,CAChC,MAAO,mCAAmC,KAAK,uBACjD,CAEO,eAAwB,CAC7B,MAAO,4BAA4B,KAAK,qBAAuB,UAAY,KAAK,mBAAqB,KAAK,uBAC5G,CAEO,WAAsC,CAC3C,OAAO,KAAK,MACd,CAEO,WAAgC,CACrC,OAAQ,KAAK,UAA6C,MAC5D,CAEO,KAAKa,EAAsB,CAChC,KAAK,QAAUA,CACjB,CAEO,gBAAgBC,EAAe,CACpC,KAAK,aAAeA,CACtB,CAEF,EC/NA,IAAOC,EAAQC,ECDR,IAAMC,EAAe,IAAI,IAEzB,SAASC,EAAsBC,EAAaC,EAA2B,CAC5EH,EAAa,IAAIE,EAAKC,CAAG,CAC3B,CAEO,SAASC,EAAsBF,EAAyC,CAC7E,OAAOF,EAAa,IAAIE,CAAG,CAC7B,CJgBA,IAAMG,EAAOC,EAAK,OAAW,CAC3B,QAAS,MAAO,CAAE,QAAAC,CAAQ,EAAGC,IAAQ,CACnC,MAAMA,EAAID,CAAO,CACnB,EAEA,QAAS,MAAO,CAAE,QAAAA,CAAQ,EAAGC,EAAKC,IAAa,CAC7C,IAAMC,EAAU,MAAMH,EAAQ,WAAW,EACnCI,EAAiBC,EAAqBL,EAASE,CAAQ,EAC7DI,EAAsBJ,EAAS,OAAQE,CAAc,EACrD,MAAMH,EAAIE,CAAO,EACjB,MAAMA,EAAQ,MAAM,CACtB,EAEA,KAAM,MAAO,CAAE,KAAAI,CAAK,EAAGN,EAAKC,IAAa,CAIvC,IAAMM,EADWN,EAAS,QAAQ,IACH,SAAW,CAAC,EACrCO,EACJ,OAAOD,GAAkB,UAAY,kBAAmBA,EACpDA,EAAc,cACdE,EAIAC,EAAW,IAAID,EAAcD,CAAa,EAE1CL,EAAiBQ,EAAsBV,EAAS,MAAM,EACxDE,IACFA,EAAe,iBAAmBO,GAGpCA,EAAS,KAAK,CAEZ,UAAW,MAAOE,GAAU,CAC1BT,GAAgB,eAAe,KAAKS,CAAK,EACzC,MAAM,QAAQ,QAAQ,CACxB,CACF,CAAC,EACD,MAAMF,EAAS,OAAOJ,CAAI,EAG1BA,EAAK,GAAG,UAAW,MAAOO,GAAmC,CACvDA,EAAe,KAAK,IAAM,SAC9B,QAAQ,MAAM,IAAI,KAAK,IAAI,oBAAqBA,EAAe,KAAK,CAAC,CACvE,CAAC,EAEDP,EAAK,GAAG,OAAQ,SAAY,CAE5B,CAAC,EAEDA,EAAK,GAAG,mBAAoB,SAAY,CACtC,MAAMI,EAAS,MAAM,EACjBP,GAAgB,SAClBA,EAAe,OAAO,SAAW,CAC/B,cAAeO,EAAS,iBAAiB,EACzC,WAAYA,EAAS,cAAc,CACrC,EAEJ,CAAC,EACDJ,EAAK,GAAG,iBAAkB,SAAY,CAEtC,CAAC,EAEDA,EAAK,GAAG,QAAS,SAAY,CAC3B,MAAMI,EAAS,MAAM,CACvB,CAAC,EAGD,IAAMI,EAAoBb,EAAS,WAAW,KAAK,MAAI,EAEvDA,EAAS,WAAa,MAAOc,GAOvB,CAGJ,IAAMC,EAAkBf,EAAS,SAAS,IAAIc,EAAe,MAAM,EAYnE,GAXIC,EAAgB,SAAWA,GAAiB,SAAS,OAASf,EAAS,MACzE,MAAMS,EAAS,eAAeM,EAAgB,QAAS,CACrD,OAAQA,EAAgB,OACxB,SAAUA,EAAgB,SAC1B,SAAUA,EAAgB,SAC1B,MAAOA,EAAgB,MACvB,QAASA,EAAgB,QACzB,YAAaA,EAAgB,WAC/B,CAAC,EAGC,CAACV,EAAK,SAAS,EACjB,GAAI,CACF,MAAMW,EAAeX,CAAI,CAC3B,MAAE,CAA4B,CAEhC,MAAMQ,EAAkBC,CAAc,CACxC,EAGA,IAAMG,EAAkCjB,EAAS,yBAAyB,KAAK,MAAI,EAEnFA,EAAS,yBAA2B,SAAY,CAE1CS,GAAYA,EAAS,iBAAiB,IACxC,MAAMS,EAA6BT,EAAU,GAAG,EAChD,MAAMA,EAAS,KAAK,GAGtB,MAAMQ,EAAgC,CACxC,EAEA,MAAMlB,EAAIM,CAAI,CAGhB,CACF,CAAC,EAEDT,EAAK,WAAW,MAAO,CAAC,EAAGI,IAAa,CACtC,QAAQ,IAAI,IAAI,KAAK,IAAI,6BAAsBA,EAAS,OAAO,CAEjE,CAAC,EAEDJ,EAAK,UAAU,MAAO,CAAC,EAAGI,IAAa,CACrC,QAAQ,IAAI,IAAI,KAAK,IAAI,2BAAoBA,EAAS,OAAO,EAC7D,IAAME,EAAiBQ,EAAsBV,EAAS,MAAM,EAC5D,GAAI,CAACE,EAAgB,OAErBA,EAAe,KAAK,SAAWF,EAAS,SACxC,IAAMmB,EAAgB,CAClB,OAAQjB,GAAgB,OACxB,KAAMA,GAAgB,KACtB,QAASA,GAAgB,QACzB,KAAMA,GAAgB,KACtB,MAAOA,GAAgB,KAAK,MAC5B,eAAgB,MAAM,QAAQA,GAAgB,cAAc,EAAIA,GAAgB,eAAiB,CAAC,CACtG,EAIMI,EADWN,EAAS,QAAQ,IACH,SAAW,CAAC,EAE3CoB,EAAgBD,EAAeb,EAAc,eAAe,CAE9D,CAAC","names":["base","expect","os","path","fs","defaultOutputReportDir","aggregateCleared","writeFileAtomic","filePath","data","dir","tmp","readJsonArraySafe","text","parsed","saveRRWebReport","testRunResult","outputReportDir","reportDir","specName","sanitizeFileNamePart","suiteTitle","testTitle","browserName","jsonFileNameRaw","jsonFilePathRaw","reportRaw","aggregatePath","current","e","name","createTestrunContext","browser","testInfo","browserType","version","family","absolute","relative","baseName","fileName","fileExtension","suiteTitlePath","deepMerge","target","source","result","key","sourceValue","targetValue","waitForRecorderStabilization","recorder","timeout","start","lastCount","resolve","interval","currentCount","waitForNextRAF","page","r","typedArrayKindToConstructor","constructorToTypedArrayKind","k","v","defaultRecordOptions","RRWebRecorder","options","deepMerge","event","rrEvent","page","rrweb_record_umd_cjs_default","rrweb_plugin_sequential_id_record_umd_cjs_default","r","optsJson","opts","plugins","stillPending","evt","tag","payload","ctx","value","recorder_default","RRWebRecorder","testContexts","setCurrentTestContext","key","ctx","getCurrentTestContext","test","base","browser","use","testInfo","context","testRunContext","createTestrunContext","setCurrentTestContext","page","testmapConfig","recordingOpts","recorder_default","recorder","getCurrentTestContext","event","consoleMessage","originalonStepEnd","stepEndPayload","currentStepInfo","waitForNextRAF","originalonDidFinishTestFunction","waitForRecorderStabilization","testRunResult","saveRRWebReport"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsurify-testmap/rrweb-playwright-plugin",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0-alpha.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"@playwright/test": ">=1.50.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@appsurify-testmap/rrweb": "^3.
|
|
44
|
-
"@appsurify-testmap/rrweb-snapshot": "^3.
|
|
45
|
-
"@appsurify-testmap/rrweb-types": "^3.
|
|
43
|
+
"@appsurify-testmap/rrweb": "^3.10.0-alpha.1",
|
|
44
|
+
"@appsurify-testmap/rrweb-snapshot": "^3.10.0-alpha.1",
|
|
45
|
+
"@appsurify-testmap/rrweb-types": "^3.10.0-alpha.1",
|
|
46
46
|
"@playwright/test": "^1.52.0",
|
|
47
47
|
"@types/node": "^24.10.0",
|
|
48
48
|
"puppeteer": "^24.9.0",
|