@appetize/playwright
Advanced tools
Comparing version 1.1.0 to 1.1.2
@@ -1,5 +0,5 @@ | ||
var re=(p,f,v)=>{if(!f.has(p))throw TypeError("Cannot "+v)};var S=(p,f,v)=>(re(p,f,"read from private field"),v?v.call(p):f.get(p)),W=(p,f,v)=>{if(f.has(p))throw TypeError("Cannot add the same private member more than once");f instanceof WeakSet?f.add(p):f.set(p,v)},B=(p,f,v,N)=>(re(p,f,"write to private field"),N?N.call(p,v):f.set(p,v),v);(function(p,f){typeof exports=="object"&&typeof module!="undefined"?f(exports,require("events"),require("@playwright/test"),require("fs")):typeof define=="function"&&define.amd?define(["exports","events","@playwright/test","fs"],f):(p=typeof globalThis!="undefined"?globalThis:p||self,f(p.playwright={},p.events,p.test$1,p.fs))})(this,function(p,f,v,N){var A,$;"use strict";function oe(i){return i&&typeof i=="object"&&"default"in i?i:{default:i}}var C=oe(N);async function ae(i,{retries:e=3,timeout:t=1e3,predicate:s=()=>!0}){for(let n=1;n<=e;n++)try{return await i()}catch(r){if(n===e||!s(r,n))throw r;await new Promise(o=>setTimeout(o,t))}throw null}function ce(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,i=>{const e=Math.random()*16|0;return(i==="x"?e:e&3|8).toString(16)})}function he(i){return Object.entries(i).map(([e,t])=>`${e}=${encodeURIComponent(t)}`).join("&")}function ue(){let i,e;return[new Promise((s,n)=>{i=s,e=n}),i,e]}function E(i){return Array.isArray(i)?i.map(E).filter(e=>e!=null):typeof i=="object"&&i!==null?Object.entries(i).reduce((e,[t,s])=>{const n=E(s);return n!=null&&(e[t]=n),e},{}):i}function J(i,e){if("captureStackTrace"in Error)Error.captureStackTrace(i,e);else{const t=new Error;Object.defineProperty(i,"stack",{configurable:!0,get(){const{stack:s}=t;return Object.defineProperty(this,"stack",{value:s}),s}})}}async function d(i,e){i instanceof m&&J(i,e)}class m extends Error{constructor(e){super(e),this.name="Error",this.isOperational=!0,J(this,this.constructor)}}class le extends m{constructor(e){super(`No element found for selector | ||
${JSON.stringify(e,null,2)}`)}}class de extends m{constructor(e){super(`Action requires 1 unique element but the selector returned ${e.length}. Provide a \`matchIndex\` to pick an element below or add additional attributes to your selector. | ||
var re=(p,f,v)=>{if(!f.has(p))throw TypeError("Cannot "+v)};var S=(p,f,v)=>(re(p,f,"read from private field"),v?v.call(p):f.get(p)),W=(p,f,v)=>{if(f.has(p))throw TypeError("Cannot add the same private member more than once");f instanceof WeakSet?f.add(p):f.set(p,v)},B=(p,f,v,N)=>(re(p,f,"write to private field"),N?N.call(p,v):f.set(p,v),v);(function(p,f){typeof exports=="object"&&typeof module!="undefined"?f(exports,require("events"),require("@playwright/test"),require("fs")):typeof define=="function"&&define.amd?define(["exports","events","@playwright/test","fs"],f):(p=typeof globalThis!="undefined"?globalThis:p||self,f(p.playwright={},p.events,p.test$1,p.fs))})(this,function(p,f,v,N){var A,P;"use strict";function oe(i){return i&&typeof i=="object"&&"default"in i?i:{default:i}}var F=oe(N);async function ae(i,{retries:e=3,timeout:t=1e3,predicate:s=()=>!0}){for(let n=1;n<=e;n++)try{return await i()}catch(r){if(n===e||!s(r,n))throw r;await new Promise(o=>setTimeout(o,t))}throw null}function ce(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,i=>{const e=Math.random()*16|0;return(i==="x"?e:e&3|8).toString(16)})}function he(i){return Object.entries(i).map(([e,t])=>`${e}=${encodeURIComponent(t)}`).join("&")}function ue(){let i,e;return[new Promise((s,n)=>{i=s,e=n}),i,e]}function E(i){return Array.isArray(i)?i.map(E).filter(e=>e!=null):typeof i=="object"&&i!==null?Object.entries(i).reduce((e,[t,s])=>{const n=E(s);return n!=null&&(e[t]=n),e},{}):i}function J(i,e){if("captureStackTrace"in Error)Error.captureStackTrace(i,e);else{const t=new Error;Object.defineProperty(i,"stack",{configurable:!0,get(){const{stack:s}=t;return Object.defineProperty(this,"stack",{value:s}),s}})}}async function d(i,e){i instanceof y&&J(i,e)}class y extends Error{constructor(e){super(e),this.name="Error",this.isOperational=!0,J(this,this.constructor)}}class le extends y{constructor(e){super(`No element found for selector | ||
${JSON.stringify(e,null,2)}`)}}class de extends y{constructor(e){super(`Action requires 1 unique element but the selector returned ${e.length}. Provide a \`matchIndex\` to pick an element below or add additional attributes to your selector. | ||
${we(e)}`)}}class pe extends m{constructor(e){e.localPosition?super(`localPosition (${e.localPosition.x}, ${e.localPosition.y}) for the element evaluates to a coordinate outside of screen bounds.`):super("Element is outside of screen bounds.")}}class I extends m{}class M extends m{constructor(e){super(`App Recorder must be enabled to use ${e}. Please set "record" to true in the config.`)}}function we(i){const t=i.slice(0,5),s=i.length>5;return`${t.map((r,o)=>`// ${o} | ||
${we(e)}`)}}class pe extends y{constructor(e){e.localPosition?super(`localPosition (${e.localPosition.x}, ${e.localPosition.y}) for the element evaluates to a coordinate outside of screen bounds.`):super("Element is outside of screen bounds.")}}class C extends y{}class M extends y{constructor(e){super(`App Recorder must be enabled to use ${e}. Please set "record" to true in the config.`)}}function we(i){const t=i.slice(0,5),s=i.length>5;return`${t.map((r,o)=>`// ${o} | ||
${JSON.stringify(r,null,2)}`).join(` | ||
@@ -9,14 +9,14 @@ | ||
...and ${i.length-5} more`:""}`}async function H(i,e=5e3){const t=Date.now();let s=!1;for(;;)try{return await i(r=>{if(r)throw s=!0,r})}catch(n){if(await new Promise(r=>setTimeout(r,100)),s||e!==null&&Date.now()-t>e)throw n}}async function D(i){return new Promise(e=>setTimeout(e,i))}async function _(i,e,t){const s=typeof t=="function"?{}:t,n=typeof t=="function"?t:t==null?void 0:t.predicate,r=typeof(s==null?void 0:s.timeout)!="undefined"?s.timeout:1e4;return new Promise((o,a)=>{const c=h=>{(!n||n(h))&&(i.off(e,c),o(h))};i.on(e,c),r!==null&&setTimeout(()=>{i.off(e,c),a(new I(`Timeout ${r}ms exceeded while waiting for event "${e}"`))},r)})}function k(i){if(typeof i=="string"){if(i.endsWith("%"))return parseInt(i,10)/100;throw new Error(`Invalid position value: ${i}. Must be a number between 0 and 1, or a string ending with %`)}return i}class fe{constructor({platform:e,screen:t,app:s}){this.platform=e,this.screen=t,this.app=s}pixelToDip(e){return e/(this.screen.devicePixelRatio||1)}dipToPixel(e){return e*(this.screen.devicePixelRatio||1)}getCoordinates(e,t){const s=k(e.x),n=k(e.y);return{x:s*t.width,y:n*t.height}}mapHardwareKey(e){switch(e){case"HOME":return"home";case"VOLUME_UP":return"volumeUp";case"VOLUME_DOWN":return"volumeDown"}return e}mapAction(e){return E((()=>{e=E(e);let s,n,r;if("element"in e&&e.element&&(s=this.mapElement(e.element)),"position"in e&&e.position){const o=k(e.position.x),a=k(e.position.y);if(!x.isValidNumber(o)||!x.isValidNumber(a))throw new m(`Invalid position: (${e.position.x}, ${e.position.y}). Values must be a number or a percentage`);if(!x.isPositionWithinBounds(e.position))throw typeof e.position.x=="string"?new Error(`Invalid position: (${e.position.x}, ${e.position.y}) must be within (0%, 0%) and (100%, 100%)`):new Error(`Invalid position: (${e.position.x}, ${e.position.y}) must be within (0, 0) and (1, 1)`);this.platform==="android"?n=this.getCoordinates(e.position,{width:this.dipToPixel(this.screen.width)-1,height:this.dipToPixel(this.screen.height)-1}):n=this.getCoordinates(e.position,{width:this.screen.width-1,height:this.screen.height-1})}else if("coordinates"in e&&e.coordinates){if(!x.isValidNumber(e.coordinates.x)||!x.isValidNumber(e.coordinates.y))throw new m(`Invalid coordinates: (${e.coordinates.x}, ${e.coordinates.y}). Values must be a number`);if(!x.isCoordinatesWithinBounds(e.coordinates,{width:this.screen.width-1,height:this.screen.height-1}))throw new m(`Invalid coordinates: (${e.coordinates.x}, ${e.coordinates.y}) exceed screen bounds (${this.screen.width-1}, ${this.screen.height-1})`);this.platform==="android"?n={x:this.dipToPixel(e.coordinates.x),y:this.dipToPixel(e.coordinates.y)}:n=e.coordinates}if("localPosition"in e&&e.localPosition){const o=k(e.localPosition.x),a=k(e.localPosition.y);if(!x.isValidNumber(o)||!x.isValidNumber(a))throw new m(`Invalid localPosition: (${e.localPosition.x}, ${e.localPosition.y}). Values must be a number or a percentage`);r={x:o,y:a}}else s&&(r={x:.5,y:.5});if("duration"in e&&e.duration&&!x.isValidNumber(e.duration))throw new m(`Invalid duration: ${e.duration}. Value must be a number`);switch(e.type){case"tap":{const{position:o,...a}=e;return{...a,element:s,localPosition:r,coordinates:n}}case"swipe":{const{position:o,...a}=e;return{...a,element:s,localPosition:r,coordinates:n,moves:e.moves.map(c=>{if(this.platform==="android"){const{x:h,y:u}=this.getCoordinates(c,{width:this.dipToPixel(this.screen.width)-1,height:this.dipToPixel(this.screen.height)-1});return{...c,x:h,y:u}}else{const{x:h,y:u}=this.getCoordinates(c,{width:this.screen.width-1,height:this.screen.height-1});return{...c,x:h,y:u}}})}}case"keypress":{const o=this.mapHardwareKey(e.key),a=this.mapHardwareKey(e.character);return{...e,key:o,character:a,shiftKey:this.platform==="ios"?ye(e.shiftKey):e.shiftKey}}case"findElements":return{...e,element:s}}return e})())}mapElement(e){const{attributes:t,bounds:s,...n}=e,r=()=>{if(s){const{x:a,y:c,width:h,height:u}=s;return this.platform==="android"?{x:this.dipToPixel(a),y:this.dipToPixel(c),width:this.dipToPixel(h),height:this.dipToPixel(u)}:{x:L(a),y:L(c),width:L(h),height:L(u)}}},o=()=>{if(t)return Object.keys(t).reduce((a,c)=>{if(this.platform==="ios")switch(c){case"userInteractionEnabled":case"isHidden":return{...a,[c]:t[c]?"1":"0"}}else this.platform;return{...a,[c]:t[c]}},{})};return E({...n,bounds:r(),attributes:o(),accessibilityElements:void 0})}}class me{constructor({platform:e,screen:t,app:s}){this.platform=e,this.screen=t,this.app=s}pixelToDip(e){return e/(this.screen.devicePixelRatio||1)}dipToPixel(e){return e*(this.screen.devicePixelRatio||1)}getPosition(e,t){return{x:e.x/t.width,y:e.y/t.height}}mapHardwareKey(e){switch(e){case"home":return"HOME";case"volumeUp":return"VOLUME_UP";case"volumeDown":return"VOLUME_DOWN"}return e}mapAction(e){return E((()=>{let s,n,r,o="localPosition"in e?e.localPosition:void 0;switch("coordinates"in e&&e.coordinates&&(n={x:this.pixelToDip(e.coordinates.x),y:this.pixelToDip(e.coordinates.y)},r=this.getPosition(n,{width:this.screen.width-1,height:this.screen.height-1})),"element"in e&&e.element&&(s=this.mapElement(e.element),n&&s.bounds&&(o=this.getPosition({x:n.x-s.bounds.x,y:n.y-s.bounds.y},{width:s.bounds.width,height:s.bounds.height}))),e.type){case"tap":return{...e,element:s,position:r,localPosition:o};case"swipe":return{...e,element:s,position:r,localPosition:o,moves:e.moves.map(a=>{const{x:c,y:h}=this.getPosition({x:this.pixelToDip(a.x),y:this.pixelToDip(a.y)},{width:this.screen.width-1,height:this.screen.height-1});return{x:c,y:h,t:a.t}})};case"keypress":{const a=this.mapHardwareKey(e.key),c=this.mapHardwareKey(e.character);return{...e,key:a,character:c,shiftKey:typeof e.shiftKey=="number"?ge(e.shiftKey):Boolean(e.shiftKey)}}case"findElements":return{...e,element:s}}return e})())}mapUI(e){var o,a;const t=(o=e.ui)!=null?o:e.result,s=e.springboard,n=c=>{var h;return{...this.mapElement(c),children:(h=c.children)==null?void 0:h.map(n)}},r=[];return t&&(this.platform==="ios"?r.push({type:"app",appId:(a=this.app)==null?void 0:a.bundle,children:t.map(n)}):r.push({type:"app",children:t.map(n)})),s&&r.push({type:"app",appId:"com.apple.springboard",children:s.map(n)}),r}mapElement(e){const{attributes:t,bounds:s,accessibilityElements:n,...r}=e,o=h=>this.platform==="android"?{x:this.pixelToDip(h.x),y:this.pixelToDip(h.y),width:this.pixelToDip(h.width),height:this.pixelToDip(h.height)}:{x:U(h.x),y:U(h.y),width:U(h.width),height:U(h.height)},a=h=>Object.keys(h).reduce((u,l)=>{switch(l){case"userInteractionEnabled":case"isHidden":return{...u,[l]:h[l]==="1"};default:return{...u,[l]:h[l]}}},{}),c=h=>h.map(u=>{const{accessibilityFrame:l}=u;return{...a(u),accessibilityFrame:l?o(l):void 0}});return E({...r,bounds:s?o(s):void 0,attributes:t?a(t):void 0,accessibilityElements:n?c(n):void 0})}mapAppetizerEvent(e,t){var s,n;switch(e){case"debug":return{type:"log",value:t};case"interceptResponse":return{type:"network",value:{type:"response",...t}};case"interceptRequest":return{type:"network",value:{type:"request",...t}};case"interceptError":return{type:"network",value:{type:"error",...t}};case"userError":return{type:"error",value:t};case"recordedAction":return{type:"action",value:this.mapAction(t)};case"playbackFoundAndSent":{const r=t;return{type:"playbackFoundAndSent",value:{...r,playback:{...r.playback,action:r.playback.action?this.mapAction(r.playback.action):void 0},matchedElements:(s=r.matchedElements)==null?void 0:s.map(o=>{if(o)return this.mapElement(o)})}}}case"playbackError":{const r=t;return{type:"playbackError",value:{...r,playback:{...r.playback,action:r.playback.action?this.mapAction(r.playback.action):void 0},matchedElements:(n=r.matchedElements)==null?void 0:n.map(o=>{if(o)return this.mapElement(o)})}}}case"uiDump":return{type:"uiDump",value:this.mapUI(t)};case"userInteractionReceived":return{type:"interaction",value:t};case"countdownWarning":return{type:"inactivityWarning",value:t};case"h264Data":return{type:"video",value:{...t,codec:"h264"}};case"frameData":return{type:"video",value:{...t,codec:"jpeg"}};case"audioData":return{type:"audio",value:{...t,codec:"aac"}};case"deleteEvent":return null}}}class x{static isCoordinatesWithinBounds(e,t){return!(e.x<0||e.x>t.width||e.y<0||e.y>t.height)}static isPositionWithinBounds(e){const t=k(e.x),s=k(e.y);return!(t<0||t>1||s<0||s>1)}static isValidNumber(e){return!(typeof e!="number"||isNaN(e))}}function ye(i){return i?1:0}function ge(i){return i===1}function U(i){return typeof i=="number"?i:i==="inf"?1/0:i==="-inf"?-1/0:parseFloat(i)}function L(i){return i===1/0?"inf":i===-1/0?"-inf":i}function be(i){if(typeof i!="object"||Array.isArray(i))throw new Error("Element must be an object");const e=Object.keys(i),s=ve(e,["text","accessibilityIdentifier","accessibilityLabel","resource-id","content-desc","class","baseClass"]);if(s.length>0){const n=s.map(r=>`'${r}'`).join(", ");throw new Error(`Element has invalid properties: ${n}. Did you mean to put these under 'attributes'?`)}return i}function ve(i,e){return i.filter(t=>e.includes(t))}function xe(i){const e=i.length;let t="";for(let s=0;s<e;s+=65535){let n=65535;s+65535>e&&(n=e-s),t+=String.fromCharCode.apply(null,i.subarray(s,s+n))}return t}function Ee(i,e){const t=xe(i),s=btoa(t);return`data:${e};base64,`+s}class ke{constructor({duration:e}){this.moves=[],this.duration=e,this.moves=[{x:0,y:0}]}to(e,t){if(typeof e!="string"||typeof t!="string")throw new m('x and y must be strings and in percentages (e.g. "50%")');if(!e.endsWith("%")||!t.endsWith("%"))throw new m('x and y must be in percentages (e.g. "50%")');return this.moves.push({x:parseFloat(e)/100,y:parseFloat(t)/100}),this}wait(e){var s;const t=this.moves[this.moves.length-1];return t&&(t.wait=e+((s=t.wait)!=null?s:0)),this}build(){var a;const t=(a=this.duration)!=null?a:Math.max(500,16*(this.moves.length-1)),s=Math.floor(t/16),n=[],r=Math.floor(s/(this.moves.length-1));let o=0;if(r===0){const c=(this.moves.length-1)*16;throw new Error(`Duration is too short for ${this.moves.length-1} moves, please set duration to at least ${c}ms`)}for(let c=0;c<this.moves.length-1;c++){const h=this.moves[c],u=this.moves[c+1],l=c===this.moves.length-2;for(let w=0;w<=r;w++){if(!l&&w===r)continue;const g=w/r,b=h.x+g*(u.x-h.x),F=h.y+g*(u.y-h.y),y=((c*r+w)*16+o)/1e3;n.push({x:b,y:F,t:y}),w===0&&h.wait&&(n.push({x:b,y:F,t:y+h.wait/1e3}),o+=h.wait)}}return n}up(e="50%"){const t=parseFloat(e);return this.to("0%",`-${t}%`)}down(e="50%"){const t=parseFloat(e);return this.to("0%",`${t}%`)}left(e="50%"){const t=parseFloat(e);return this.to(`-${t}%`,"0%")}right(e="50%"){const t=parseFloat(e);return this.to(`${t}%`,"0%")}}class V{constructor(){this.log=function(){const e="[Appetize]";return Function.prototype.bind.call(console.log,console,e)}(),this.warn=function(){const e="[Appetize]";return Function.prototype.bind.call(console.warn,console,e)}(),this.error=function(){const e="[Appetize]";return Function.prototype.bind.call(console.error,console,e)}(),this.debug=function(){const e="[Appetize]";return Function.prototype.bind.call(console.debug,console,e)}()}}class Ae extends f.EventEmitter{constructor({socket:t,config:s,path:n,token:r,app:o,device:a,logger:c=new V}){super();W(this,A,void 0);W(this,$,void 0);this.isEndingManually=!1,this.countdownWarning=!1,this.ready=!1,this._waitForAnimationsPromises=new Set,this.actionLogs=[],this.config=s,this.socket=t,this.device=a,this.app=o,this.path=n,this.token=r,this.logger=c;const h=({type:u,value:l})=>{const g=new me({platform:this.config.platform,screen:this.device.screen,app:this.app}).mapAppetizerEvent(u,l);switch(u){case"ready":this.ready=!0;break;case"adbOverTcp":{B(this,A,{...l,command:Se(l)});break}case"networkInspectorUrl":B(this,$,l);break;case"countdownWarning":this.countdownWarning=!0;break;case"timeoutReset":this.countdownWarning=!1;break;case"deviceInfo":this.device=l;break}g?(this.emit(g.type,g.value),this.emit("*",g)):g!==null&&(this.emit(u,l),this.emit("*",{type:u,value:l}))};this.socket.on("*",h),this.on("disconnect",()=>{this.socket.off("*",h),this.isEndingManually||(this.countdownWarning?this.logger.warn("Appetize session has ended due to inactivity"):this.logger.warn("Session disconnected"))})}on(t,s){return t==="network"&&this.config.proxy!=="intercept"&&this.logger.warn('Session must be configured with `proxy: "intercept"` to listen to network events.'),t==="log"&&this.config.debug!==!0&&this.logger.warn("Session must be configured with `debug: true` to listen to log events."),t==="action"&&this.config.record!==!0&&this.logger.warn("Session must configured with `record: true` to listen to action events."),super.on(t,s)}async waitUntilReady(){let t=!0;const s=async r=>new Promise(o=>{const a=setInterval(()=>{r()&&o(void 0)},10);setTimeout(()=>{clearInterval(a),o(void 0)},3e3)}),n=()=>{t=!1};this.socket.once("disconnect",n);try{await H(r=>{if(!this.ready){if(t)throw new I("Timed out after 180s waiting for session to be ready");r(new Error("Session disconnected"))}},18e4)}finally{this.socket.off("disconnect",n)}await Promise.all([this.config.proxy==="intercept"?s(()=>Boolean(S(this,$))):Promise.resolve(),this.config.enableAdb?s(()=>Boolean(S(this,A))):Promise.resolve()])}async waitForEvent(t,s){try{return await _(this,t,s)}catch(n){throw d(n,this.waitForEvent),n}}async end(){this.isEndingManually=!0,await this.socket.disconnect()}get networkInspectorUrl(){return this.config.proxy!=="intercept"&&this.logger.warn('Session must be configured with `proxy: "intercept"` to use the network inspector'),S(this,$)}get adbConnection(){if(this.config.platform&&this.config.platform!=="android"&&this.logger.warn("Session must be connected to an Android device to use adb"),this.config.enableAdb||this.logger.warn("Session must be configured with `enableAdb: true` to use adb"),S(this,A))return S(this,A)}async rotate(t){try{const[s]=await Promise.all([this.waitForEvent("orientationChanged"),this.socket.send("userInteraction",{type:"keypress",key:t==="left"?"rotateLeft":"rotateRight",timeStamp:Date.now()})]);return s}catch(s){throw d(s,this.rotate),s}}async screenshot(t="buffer"){try{this.socket.send("getScreenshot",{});const s=await _(this.socket,"screenshot",{timeout:6e4});if(!s.success)throw new m("Screenshot failed");return{data:t==="buffer"?(o=>typeof window=="undefined"?Buffer.from(o):o)(s.data):Ee(new Uint8Array(s.data),s.mimeType),mimeType:s.mimeType}}catch(s){throw d(s,this.screenshot),s}}async heartbeat(){try{return await this.socket.send("heartbeat")}catch(t){throw d(t,this.heartbeat),t}}async type(t){try{await D(1e3);const s=await this.playAction({type:"typeText",text:t});return await D(500),s}catch(s){throw d(s,this.type),s}}async keypress(t,s){try{if(t==="ANDROID_KEYCODE_MENU")return await this.socket.send("androidKeycodeMenu");if((s==null?void 0:s.shift)||t==="HOME"){switch(t){case"ArrowUp":t="arrowUp";break;case"ArrowDown":t="arrowDown";break;case"ArrowLeft":t="arrowLeft";break;case"ArrowRight":t="arrowRight";break;case"Enter":t="\r";break;case"Tab":t=" ";break;case"Backspace":t="\b";break}return this.playAction({type:"keypress",key:t,shiftKey:!!(s!=null&&s.shift)})}else return this.playAction({type:"keypress",character:t})}catch(n){throw d(n,this.keypress),n}}async setLanguage(t){try{return this.config.language=t,await this.socket.send("setLanguage",{language:t,timeStamp:Date.now()})}catch(s){throw d(s,this.setLanguage),s}}async setLocation(t,s){try{if(typeof t!="number"||typeof s!="number")throw new m("setLocation requires latitude and longitude to be numbers");const n=[t,s];return this.config.location=n,await this.socket.send("setLocation",{location:n,timeStamp:Date.now()})}catch(n){throw d(n,this.setLocation),n}}async openUrl(t){try{return await this.socket.send("openUrl",{url:t,timeStamp:Date.now()})}catch(s){throw d(s,this.openUrl),s}}async shake(){try{return await this.socket.send("shakeDevice")}catch(t){throw d(t,this.swipe),t}}async toggleSoftKeyboard(){try{if(this.config.platform!=="ios")throw new Error("toggleSoftKeyboard is only available on iOS devices");return await this.socket.send("toggleSoftKeyboard")}catch(t){throw d(t,this.toggleSoftKeyboard),t}}async biometry({match:t}){try{return await this.socket.send(t?"biometryMatch":"biometryNoMatch")}catch(s){throw d(s,this.biometry),s}}async allowInteractions(t){try{return await this.socket.send(t?"enableInteractions":"disableInteractions")}catch(s){throw d(s,this.allowInteractions),s}}async restartApp(){try{this.socket.send("restartApp");const{platform:t}=this.config;t==="ios"?await this.waitForEvent("appLaunch",{timeout:6e4}):await D(1e3)}catch(t){throw d(t,this.restartApp),t}}async reinstallApp(){try{this.socket.send("reinstallApp"),await this.waitForEvent("appLaunch",{timeout:6e4})}catch(t){throw d(t,this.reinstallApp),t}}async adbShellCommand(t){if(this.config.platform!=="android")throw new Error("adbShellCommand is only available on Android devices");try{return await this.socket.send("adbShellCommand",{command:t,timeStamp:Date.now()})}catch(s){throw d(s,this.adbShellCommand),s}}async playAction(t,s={}){const{timeout:n=1e4}=s;try{if(!this.config.record)throw new M("playAction()");if(isNaN(n))throw new m(`Invalid timeout value: ${s.timeout}`);if(n<0)throw new m(`Timeout value cannot be negative: ${s.timeout}`);"element"in t&&t.element&&be(t.element);const r=new fe({platform:this.config.platform,screen:this.device.screen,app:this.app}),o=ce(),c=s.noMap?t:r.mapAction(t),h={id:o,action:c,options:{...s,timeout:Math.round(n/1e3)}},[u]=await Promise.all([new Promise((l,w)=>{const g=()=>{this.off("playbackFoundAndSent",b),this.off("playbackError",F)},b=async y=>{var R;((R=y.playback)==null?void 0:R.id)===o&&(await this.addActionLog({action:t,payload:h,result:y}),g(),l(y))},F=async y=>{var R;if(((R=y.playback)==null?void 0:R.id)===o)switch(await this.addActionLog({action:t,payload:h,error:y}),g(),y.errorId){case"internalError":w(new m(`An internal error has occurred for the action: | ||
${JSON.stringify(t,null,2)}`));break;case"notFound":if(y.playback!==void 0&&"element"in y.playback.action&&y.playback.action.element!==void 0){w(new le(y.playback.action.element));break}case"ambiguousMatch":if("matchedElements"in y&&y.matchedElements!==void 0){w(new de(y.matchedElements));break}case"invalidArgument":if("element"in t&&t.element&&y.message.match("outside the screen bounds")){w(new pe(t));break}default:w(new m(y.message));break}};this.once("playbackFoundAndSent",b),this.once("playbackError",F)}),this.socket.send("playAction",h)]);return u}catch(r){throw d(r,this.playAction),r}}async playActions(t,s={}){try{if(!this.config.record)throw new M("playActions()");const n=[];for(const r of t){const o=await this.playAction(r,s);n.push(o);const a=t[t.indexOf(r)+1];a&&a.type==="keypress"&&r.type==="keypress"||await D(1e3)}return n}catch(n){throw d(n,this.playActions),n}}async getUI({timeout:t=3e4}={}){try{return this.socket.send("dumpUi"),await _(this,"uiDump",{timeout:t})}catch(s){throw d(s,this.getUI),s}}async findElement(t,s){var n;try{return(n=(await this.playAction({type:"findElements",element:t,appId:s==null?void 0:s.appId},s)).matchedElements)==null?void 0:n[0]}catch(r){throw d(r,this.findElement),r}}async findElements(t,s){try{return(await this.playAction({type:"findElements",element:t,appId:s==null?void 0:s.appId},s)).matchedElements}catch(n){throw d(n,this.findElements),n}}async tap(t,s){var n;try{if(!this.config.record)throw new M("tap()");return await this.playAction({type:"tap",...t,duration:((n=t.duration)!=null?n:0)/1e3},s)}catch(r){throw d(r,this.tap),r}}async swipe({duration:t,gesture:s,...n},r){try{if(!this.config.record)throw new M("swipe()");let o;const a=new ke({duration:t});if(typeof s=="function")s(a);else switch(s){case"up":a.up();break;case"down":a.down();break;case"left":a.left();break;case"right":a.right();break}if("element"in n)o={type:"swipe",element:n.element,localPosition:n.localPosition,moves:a.build()};else if("position"in n)o={type:"swipe",position:n.position,moves:a.build()};else throw new Error("Either element or position must be specified");return this.playAction(o,r)}catch(o){throw d(o,this.swipe),o}}async waitForAnimations(t={}){try{const{imageThreshold:s=.01,timeout:n=1e4}=t;let r=1e3,o=1;t.imageThresholdDuration&&(r=t.imageThresholdDuration);const[a,c,h]=ue(),u=setTimeout(()=>{h(new I(`Timed out after ${n}ms waiting for animation to end. Waited for imageThreshold of ${s} but lowest was ${o.toFixed(2)}`))},n);let l;const w=({percentage:g,timestamp:b})=>{g<o&&(o=g),g<=s?(l||(l=b),l&&b-l>=r&&c()):l=void 0};return this.socket.send("enablePixelChangeDetection"),this.socket.on("pixelsChanged",w),this._waitForAnimationsPromises.add(a),await a.finally(()=>{clearTimeout(u),this.socket.off("pixelsChanged",w),this._waitForAnimationsPromises.delete(a),this._waitForAnimationsPromises.size===0&&this.socket.send("disablePixelChangeDetection")})}catch(s){throw d(s,this.waitForAnimations),s}}async addActionLog(t){this.actionLogs.push(t)}async getAdbInfo(){return this.logger.warn("getAdbInfo() is deprecated. Please use the `adbConnection` property instead."),Promise.resolve(S(this,A))}async getNetworkInspectorUrl(){return this.logger.warn("getNetworkInspectorUrl() is deprecated. Please use the `networkInspectorUrl` property instead."),Promise.resolve(S(this,$))}async getDeviceInfo(){return this.logger.warn("getDeviceInfo() is deprecated. Please use the `device` property instead."),Promise.resolve(this.device)}}A=new WeakMap,$=new WeakMap;function Se(i){const e="ssh -fN -o StrictHostKeyChecking=no -oHostKeyAlgorithms=+ssh-rsa -p SERVER_PORT USERNAME@HOSTNAME -L6000:FORWARD_DESTINATION:FORWARD_PORT && adb connect localhost:6000";if(!i||!i.forwards[0])return;let t=e;return t=t.replace(/SERVER_PORT/,i.port.toString()),t=t.replace(/USERNAME/,i.user),t=t.replace(/HOSTNAME/,i.hostname),t=t.replace(/FORWARD_DESTINATION/,i.forwards[0].destination),t=t.replace(/FORWARD_PORT/,i.forwards[0].port.toString()),t}v.expect.extend({toHaveElement:async(i,e,t={})=>{try{const s=await i.findElements(e,t);return{pass:typeof t.matches=="number"?s.length===t.matches:s.length>0,message:()=>`Element not found: | ||
${JSON.stringify(e,null,2)}`}}catch(s){return{pass:!1,message:()=>s.message}}}});class _e extends f.EventEmitter{constructor({socket:e,logger:t=new V}){super(),this.logger=t,this.socket=e,this.socket.on("*",({type:s,value:n})=>{const r=Te(s,n);r!==null&&(r?(this.emit(r.type,r.value),this.emit("*",r)):(this.emit(s,n),this.emit("*",{type:s,value:n})))})}on(e,t){return super.on(e,t)}async startSession(e){throw new Error("Not implemented")}async setConfig(e){throw new Error("Not implemented")}getConfig(){return this._config}async waitForSessionStart(e){return new Promise(async(t,s)=>{const n=()=>{s(new Error("Session disconnected before it was ready"))},r=a=>{s(new Error(`Session failed to start - ${typeof a.message=="object"?JSON.stringify(a.message):a.message}`))},o=a=>{a.message.match(/Too many requests/)&&s(new Error("Session failed to start due to too many requests"))};try{this.on("error",o),e.on("disconnect",n),e.on("error",r),await e.waitUntilReady()}finally{this.off("error",o),e.off("disconnect",n),e.off("error",r)}t(e)})}}function Te(i,e){switch(i){case"concurrentQueue":return{type:"queue",value:{type:"concurrent",name:e.name,position:e.position}};case"queue":return{type:"queue",value:{type:"session",position:e.position}};case"userError":return{type:"error",value:e};case"newSession":return null}}class Pe extends _e{constructor({socket:e,window:t,logger:s=new V,config:n}){super({socket:e,logger:s}),this.ready=!1,this.window=t,n&&(this._config=this.mapConfig(n)),this.window.on("*",async({type:r,value:o})=>{if(this.ready)switch(r){case"app":this.app=o,this.emit(r,o);break;case"deviceInfo":this.device=o,this.emit(r,o);break;case"config":this._config=this.mapConfig(o);break}}),this.window.on("reinit",()=>{this.ready=!1,this.session=void 0,this.init({isReinit:!0})}),this.socket.on("*",async({type:r,value:o})=>{if(this.ready)switch(r){case"newSession":try{this.session=this.createSession(this._config,{path:o.path,token:o.sessionToken}),await this.waitForSessionStart(this.session),this.emit("session",this.session)}catch(a){this.session=void 0,this.emit("sessionError",a)}}}),this.init()}async init(e={isReinit:!1}){await this.window.waitUntilReady();const t=async()=>{if(e.isReinit){const r=this._config,o=await this.setConfig({});return this.setConfig({record:!0,...r,...o})}else return this.setConfig({record:!0,...this._config})},[s,n]=await Promise.all([this.window.postMessage({type:"getApp"},!0),this.window.postMessage({type:"getDeviceInfo"},!0),t()]);this.app=s,this.device=n,this.ready=!0}async waitUntilReady(){if(!this.ready)return H(async()=>{if(!this.ready)throw new Error("Timed out waiting for client to be ready")},3e4)}async startSession(e){try{await this.waitUntilReady()}catch(s){const n=s instanceof Error?s.message:s;throw new Error(`Failed to start session. ${n}`)}this.session&&await this.session.end(),await this.setConfig(e!=null?e:{});const[t]=await Promise.all([new Promise((s,n)=>{const r=a=>{this.off("session",r),this.off("sessionError",o),s(a)},o=a=>{this.off("session",r),this.off("sessionError",o),n(a)};this.on("session",r),this.on("sessionError",o)}),this.window.postMessage({type:"requestSession"},!0)]);return t}async config(e){return this.logger.warn("client.config() is deprecated and will be removed in a future major release. Use client.setConfig() instead."),this.setConfig(e)}async setConfig({publicKey:e,...t}){if(e){const n=await this.window.postMessage({type:"loadApp",value:e},!0);if(n&&"error"in n)throw new Error(n.error)}const s=await this.window.postMessage({type:"setConfig",value:this.validateConfig(t!=null?t:{})},!0).then(this.mapConfig);return this._config=s,s}mapConfig(e){return{...E(e),device:e.deviceType||e.device}}validateConfig(e){return e}createSession(e,t){throw new Error("Not implemented")}}class $e extends V{constructor(){super(...arguments),this.logHistory=[],this.logLevel=process.env.CI==="true"?"warnings-errors":"verbose",this.log=(...e)=>{if(this.logHistory.push({method:"log",data:e}),this.logLevel==="verbose")return console.log(...e)},this.warn=(...e)=>{if(this.logHistory.push({method:"warn",data:e}),this.logLevel==="verbose"||this.logLevel==="warnings-errors")return console.warn(...e)},this.error=(...e)=>{if(this.logHistory.push({method:"error",data:e}),this.logLevel==="verbose"||this.logLevel==="warnings-errors")return console.error(...e)},this.debug=(...e)=>{if(this.logHistory.push({method:"debug",data:e}),this.logLevel==="verbose")return console.debug(...e)},this.clearLogHistory=()=>{this.logHistory=[]}}}const T=new $e;async function Fe(i){await i.pause()}function K(i){if(i.character)return i.character;const e=i.key;return z(e)?e:i.shiftKey?e.toUpperCase():e.toLowerCase()}function z(i){return/^[\b\t\r]/.test(i)}class Ce{constructor({testInfo:e,session:t}){this.currentRecord=0,this.session=t,this.testInfo=e}async record(){const e=this.testInfo.file,t=await C.default.promises.readFile(e,"utf8"),n=t.split(` | ||
`).map((r,o)=>({line:r,num:o+1})).slice(this.testInfo.line).filter(({line:r})=>r.includes("session.record()"))[this.currentRecord].num;if(n!==void 0){console.log(`\u{1F534} Recording at line ${n}`);const r=[],o=c=>{Ie(r,c),console.log(Y(c))};this.session.on("action",o),await Fe(this.session.page),await D(2e3),this.session.off("action",o);const a=t.split(` | ||
`).map((c,h)=>{var u,l;if(h===n-1){const w=(l=(u=c.match(/^\s*/))==null?void 0:u[0])!=null?l:0;return`${r.map(b=>Y(b)).reduce((b,F,y)=>`${b} | ||
// ${y+1}. ${F}`,"// Recorded using session.record()")} | ||
...and ${i.length-5} more`:""}`}async function H(i,e=5e3){const t=Date.now();let s=!1;for(;;)try{return await i(r=>{if(r)throw s=!0,r})}catch(n){if(await new Promise(r=>setTimeout(r,100)),s||e!==null&&Date.now()-t>e)throw n}}async function I(i){return new Promise(e=>setTimeout(e,i))}async function D(i,e,t){const s=typeof t=="function"?{}:t,n=typeof t=="function"?t:t==null?void 0:t.predicate,r=typeof(s==null?void 0:s.timeout)!="undefined"?s.timeout:1e4;return new Promise((o,a)=>{const c=h=>{(!n||n(h))&&(i.off(e,c),o(h))};i.on(e,c),r!==null&&setTimeout(()=>{i.off(e,c),a(new C(`Timeout ${r}ms exceeded while waiting for event "${e}"`))},r)})}function k(i){if(typeof i=="string"){if(i.endsWith("%"))return parseInt(i,10)/100;throw new Error(`Invalid position value: ${i}. Must be a number between 0 and 1, or a string ending with %`)}return i}class fe{constructor({platform:e,screen:t,app:s}){this.platform=e,this.screen=t,this.app=s}pixelToDip(e){return e/(this.screen.devicePixelRatio||1)}dipToPixel(e){return e*(this.screen.devicePixelRatio||1)}getCoordinates(e,t){const s=k(e.x),n=k(e.y);return{x:s*t.width,y:n*t.height}}mapHardwareKey(e){switch(e){case"HOME":return"home";case"VOLUME_UP":return"volumeUp";case"VOLUME_DOWN":return"volumeDown"}return e}mapAction(e){return E((()=>{e=E(e);let s,n,r;if("element"in e&&e.element&&(s=this.mapElement(e.element)),"position"in e&&e.position){const o=k(e.position.x),a=k(e.position.y);if(!x.isValidNumber(o)||!x.isValidNumber(a))throw new y(`Invalid position: (${e.position.x}, ${e.position.y}). Values must be a number or a percentage`);if(!x.isPositionWithinBounds(e.position))throw typeof e.position.x=="string"?new Error(`Invalid position: (${e.position.x}, ${e.position.y}) must be within (0%, 0%) and (100%, 100%)`):new Error(`Invalid position: (${e.position.x}, ${e.position.y}) must be within (0, 0) and (1, 1)`);this.platform==="android"?n=this.getCoordinates(e.position,{width:this.dipToPixel(this.screen.width)-1,height:this.dipToPixel(this.screen.height)-1}):n=this.getCoordinates(e.position,{width:this.screen.width-1,height:this.screen.height-1})}else if("coordinates"in e&&e.coordinates){if(!x.isValidNumber(e.coordinates.x)||!x.isValidNumber(e.coordinates.y))throw new y(`Invalid coordinates: (${e.coordinates.x}, ${e.coordinates.y}). Values must be a number`);if(!x.isCoordinatesWithinBounds(e.coordinates,{width:this.screen.width-1,height:this.screen.height-1}))throw new y(`Invalid coordinates: (${e.coordinates.x}, ${e.coordinates.y}) exceed screen bounds (${this.screen.width-1}, ${this.screen.height-1})`);this.platform==="android"?n={x:this.dipToPixel(e.coordinates.x),y:this.dipToPixel(e.coordinates.y)}:n=e.coordinates}if("localPosition"in e&&e.localPosition){const o=k(e.localPosition.x),a=k(e.localPosition.y);if(!x.isValidNumber(o)||!x.isValidNumber(a))throw new y(`Invalid localPosition: (${e.localPosition.x}, ${e.localPosition.y}). Values must be a number or a percentage`);r={x:o,y:a}}else s&&(r={x:.5,y:.5});if("duration"in e&&e.duration&&!x.isValidNumber(e.duration))throw new y(`Invalid duration: ${e.duration}. Value must be a number`);switch(e.type){case"tap":{const{position:o,...a}=e;return{...a,element:s,localPosition:r,coordinates:n}}case"swipe":{const{position:o,...a}=e;return{...a,element:s,localPosition:r,coordinates:n,moves:e.moves.map(c=>{if(this.platform==="android"){const{x:h,y:u}=this.getCoordinates(c,{width:this.dipToPixel(this.screen.width)-1,height:this.dipToPixel(this.screen.height)-1});return{...c,x:h,y:u}}else{const{x:h,y:u}=this.getCoordinates(c,{width:this.screen.width-1,height:this.screen.height-1});return{...c,x:h,y:u}}})}}case"keypress":{const o=this.mapHardwareKey(e.key),a=this.mapHardwareKey(e.character);return{...e,key:o,character:a,shiftKey:this.platform==="ios"?me(e.shiftKey):e.shiftKey}}case"findElements":return{...e,element:s}}return e})())}mapElement(e){const{attributes:t,bounds:s,...n}=e,r=()=>{if(s){const{x:a,y:c,width:h,height:u}=s;return this.platform==="android"?{x:this.dipToPixel(a),y:this.dipToPixel(c),width:this.dipToPixel(h),height:this.dipToPixel(u)}:{x:L(a),y:L(c),width:L(h),height:L(u)}}},o=()=>{if(t)return Object.keys(t).reduce((a,c)=>{if(this.platform==="ios")switch(c){case"userInteractionEnabled":case"isHidden":return{...a,[c]:t[c]?"1":"0"}}else this.platform;return{...a,[c]:t[c]}},{})};return E({...n,bounds:r(),attributes:o(),accessibilityElements:void 0})}}class ye{constructor({platform:e,screen:t,app:s}){this.platform=e,this.screen=t,this.app=s}pixelToDip(e){return e/(this.screen.devicePixelRatio||1)}dipToPixel(e){return e*(this.screen.devicePixelRatio||1)}getPosition(e,t){return{x:e.x/t.width,y:e.y/t.height}}mapHardwareKey(e){switch(e){case"home":return"HOME";case"volumeUp":return"VOLUME_UP";case"volumeDown":return"VOLUME_DOWN"}return e}mapAction(e){return E((()=>{let s,n,r,o="localPosition"in e?e.localPosition:void 0;switch("coordinates"in e&&e.coordinates&&(n={x:this.pixelToDip(e.coordinates.x),y:this.pixelToDip(e.coordinates.y)},r=this.getPosition(n,{width:this.screen.width-1,height:this.screen.height-1})),"element"in e&&e.element&&(s=this.mapElement(e.element),n&&s.bounds&&(o=this.getPosition({x:n.x-s.bounds.x,y:n.y-s.bounds.y},{width:s.bounds.width,height:s.bounds.height}))),e.type){case"tap":return{...e,element:s,position:r,localPosition:o};case"swipe":return{...e,element:s,position:r,localPosition:o,moves:e.moves.map(a=>{const{x:c,y:h}=this.getPosition({x:this.pixelToDip(a.x),y:this.pixelToDip(a.y)},{width:this.screen.width-1,height:this.screen.height-1});return{x:c,y:h,t:a.t}})};case"keypress":{const a=this.mapHardwareKey(e.key),c=this.mapHardwareKey(e.character);return{...e,key:a,character:c,shiftKey:typeof e.shiftKey=="number"?ge(e.shiftKey):Boolean(e.shiftKey)}}case"findElements":return{...e,element:s}}return e})())}mapUI(e){var o,a;const t=(o=e.ui)!=null?o:e.result,s=e.springboard,n=c=>{var h;return{...this.mapElement(c),children:(h=c.children)==null?void 0:h.map(n)}},r=[];return t&&(this.platform==="ios"?r.push({type:"app",appId:(a=this.app)==null?void 0:a.bundle,children:t.map(n)}):r.push({type:"app",children:t.map(n)})),s&&r.push({type:"app",appId:"com.apple.springboard",children:s.map(n)}),r}mapElement(e){const{attributes:t,bounds:s,accessibilityElements:n,...r}=e,o=h=>this.platform==="android"?{x:this.pixelToDip(h.x),y:this.pixelToDip(h.y),width:this.pixelToDip(h.width),height:this.pixelToDip(h.height)}:{x:U(h.x),y:U(h.y),width:U(h.width),height:U(h.height)},a=h=>Object.keys(h).reduce((u,l)=>{switch(l){case"userInteractionEnabled":case"isHidden":return{...u,[l]:h[l]==="1"};default:return{...u,[l]:h[l]}}},{}),c=h=>h.map(u=>{const{accessibilityFrame:l}=u;return{...a(u),accessibilityFrame:l?o(l):void 0}});return E({...r,bounds:s?o(s):void 0,attributes:t?a(t):void 0,accessibilityElements:n?c(n):void 0})}mapAppetizerEvent(e,t){var s,n;switch(e){case"debug":return{type:"log",value:t};case"interceptResponse":return{type:"network",value:{type:"response",...t}};case"interceptRequest":return{type:"network",value:{type:"request",...t}};case"interceptError":return{type:"network",value:{type:"error",...t}};case"userError":return{type:"error",value:t};case"recordedAction":return{type:"action",value:this.mapAction(t)};case"playbackFoundAndSent":{const r=t;return{type:"playbackFoundAndSent",value:{...r,playback:{...r.playback,action:r.playback.action?this.mapAction(r.playback.action):void 0},matchedElements:(s=r.matchedElements)==null?void 0:s.map(o=>{if(o)return this.mapElement(o)})}}}case"playbackError":{const r=t;return{type:"playbackError",value:{...r,playback:{...r.playback,action:r.playback.action?this.mapAction(r.playback.action):void 0},matchedElements:(n=r.matchedElements)==null?void 0:n.map(o=>{if(o)return this.mapElement(o)})}}}case"uiDump":return{type:"uiDump",value:this.mapUI(t)};case"userInteractionReceived":return{type:"interaction",value:t};case"countdownWarning":return{type:"inactivityWarning",value:t};case"h264Data":return{type:"video",value:{...t,codec:"h264"}};case"frameData":return{type:"video",value:{...t,codec:"jpeg"}};case"audioData":return{type:"audio",value:{...t,codec:"aac"}};case"deleteEvent":return null}}}class x{static isCoordinatesWithinBounds(e,t){return!(e.x<0||e.x>t.width||e.y<0||e.y>t.height)}static isPositionWithinBounds(e){const t=k(e.x),s=k(e.y);return!(t<0||t>1||s<0||s>1)}static isValidNumber(e){return!(typeof e!="number"||isNaN(e))}}function me(i){return i?1:0}function ge(i){return i===1}function U(i){return typeof i=="number"?i:i==="inf"?1/0:i==="-inf"?-1/0:parseFloat(i)}function L(i){return i===1/0?"inf":i===-1/0?"-inf":i}function be(i){if(typeof i!="object"||Array.isArray(i))throw new Error("Element must be an object");const e=Object.keys(i),s=ve(e,["text","accessibilityIdentifier","accessibilityLabel","resource-id","content-desc","class","baseClass"]);if(s.length>0){const n=s.map(r=>`'${r}'`).join(", ");throw new Error(`Element has invalid properties: ${n}. Did you mean to put these under 'attributes'?`)}return i}function ve(i,e){return i.filter(t=>e.includes(t))}function xe(i){const e=i.length;let t="";for(let s=0;s<e;s+=65535){let n=65535;s+65535>e&&(n=e-s),t+=String.fromCharCode.apply(null,i.subarray(s,s+n))}return t}function Ee(i,e){const t=xe(i),s=btoa(t);return`data:${e};base64,`+s}class ke{constructor({duration:e}){this.moves=[],this.duration=e,this.moves=[{x:0,y:0}]}to(e,t){if(typeof e!="string"||typeof t!="string")throw new y('x and y must be strings and in percentages (e.g. "50%")');if(!e.endsWith("%")||!t.endsWith("%"))throw new y('x and y must be in percentages (e.g. "50%")');return this.moves.push({x:parseFloat(e)/100,y:parseFloat(t)/100}),this}wait(e){var s;const t=this.moves[this.moves.length-1];return t&&(t.wait=e+((s=t.wait)!=null?s:0)),this}build(){var a;const t=(a=this.duration)!=null?a:Math.max(500,16*(this.moves.length-1)),s=Math.floor(t/16),n=[],r=Math.floor(s/(this.moves.length-1));let o=0;if(r===0){const c=(this.moves.length-1)*16;throw new Error(`Duration is too short for ${this.moves.length-1} moves, please set duration to at least ${c}ms`)}for(let c=0;c<this.moves.length-1;c++){const h=this.moves[c],u=this.moves[c+1],l=c===this.moves.length-2;for(let w=0;w<=r;w++){if(!l&&w===r)continue;const g=w/r,b=h.x+g*(u.x-h.x),$=h.y+g*(u.y-h.y),m=((c*r+w)*16+o)/1e3;n.push({x:b,y:$,t:m}),w===0&&h.wait&&(n.push({x:b,y:$,t:m+h.wait/1e3}),o+=h.wait)}}return n}up(e="50%"){const t=parseFloat(e);return this.to("0%",`-${t}%`)}down(e="50%"){const t=parseFloat(e);return this.to("0%",`${t}%`)}left(e="50%"){const t=parseFloat(e);return this.to(`-${t}%`,"0%")}right(e="50%"){const t=parseFloat(e);return this.to(`${t}%`,"0%")}}class V{constructor(){this.log=function(){const e="[Appetize]";return Function.prototype.bind.call(console.log,console,e)}(),this.warn=function(){const e="[Appetize]";return Function.prototype.bind.call(console.warn,console,e)}(),this.error=function(){const e="[Appetize]";return Function.prototype.bind.call(console.error,console,e)}(),this.debug=function(){const e="[Appetize]";return Function.prototype.bind.call(console.debug,console,e)}()}}class Ae extends f.EventEmitter{constructor({socket:t,config:s,path:n,token:r,app:o,device:a,logger:c=new V}){super();W(this,A,void 0);W(this,P,void 0);this.isEndingManually=!1,this.countdownWarning=!1,this.ready=!1,this._waitForAnimationsPromises=new Set,this.actionLogs=[],this.config=s,this.socket=t,this.device=a,this.app=o,this.path=n,this.token=r,this.logger=c;const h=({type:u,value:l})=>{const g=new ye({platform:this.config.platform,screen:this.device.screen,app:this.app}).mapAppetizerEvent(u,l);switch(u){case"ready":this.ready=!0;break;case"adbOverTcp":{B(this,A,{...l,command:Se(l)});break}case"networkInspectorUrl":B(this,P,l);break;case"countdownWarning":this.countdownWarning=!0;break;case"timeoutReset":this.countdownWarning=!1;break;case"deviceInfo":this.device=l;break}g?(this.emit(g.type,g.value),this.emit("*",g)):g!==null&&(this.emit(u,l),this.emit("*",{type:u,value:l}))};this.socket.on("*",h),this.on("disconnect",()=>{this.socket.off("*",h),this.isEndingManually||(this.countdownWarning?this.logger.warn("Appetize session has ended due to inactivity"):this.logger.warn("Session disconnected"))})}on(t,s){return t==="network"&&this.config.proxy!=="intercept"&&this.logger.warn('Session must be configured with `proxy: "intercept"` to listen to network events.'),t==="log"&&this.config.debug!==!0&&this.logger.warn("Session must be configured with `debug: true` to listen to log events."),t==="action"&&this.config.record!==!0&&this.logger.warn("Session must configured with `record: true` to listen to action events."),super.on(t,s)}async waitUntilReady(){let t=!0;const s=async r=>new Promise(o=>{const a=setInterval(()=>{r()&&o(void 0)},10);setTimeout(()=>{clearInterval(a),o(void 0)},3e3)}),n=()=>{t=!1};this.socket.once("disconnect",n);try{await H(r=>{if(!this.ready){if(t)throw new C("Timed out after 180s waiting for session to be ready");r(new Error("Session disconnected"))}},18e4)}finally{this.socket.off("disconnect",n)}await Promise.all([this.config.proxy==="intercept"?s(()=>Boolean(S(this,P))):Promise.resolve(),this.config.enableAdb?s(()=>Boolean(S(this,A))):Promise.resolve()])}async waitForEvent(t,s){try{return await D(this,t,s)}catch(n){throw d(n,this.waitForEvent),n}}async end(){this.isEndingManually=!0,await this.socket.disconnect()}get networkInspectorUrl(){return this.config.proxy!=="intercept"&&this.logger.warn('Session must be configured with `proxy: "intercept"` to use the network inspector'),S(this,P)}get adbConnection(){if(this.config.platform&&this.config.platform!=="android"&&this.logger.warn("Session must be connected to an Android device to use adb"),this.config.enableAdb||this.logger.warn("Session must be configured with `enableAdb: true` to use adb"),S(this,A))return S(this,A)}async rotate(t){try{const[s]=await Promise.all([this.waitForEvent("orientationChanged"),this.socket.send("userInteraction",{type:"keypress",key:t==="left"?"rotateLeft":"rotateRight",timeStamp:Date.now()})]);return s}catch(s){throw d(s,this.rotate),s}}async screenshot(t="buffer"){var s;try{this.socket.send("getScreenshot",{});const n=await D(this.socket,"screenshot",{timeout:6e4});if(!n.success)throw new y((s=n.error)!=null?s:"Screenshot failed");return{data:t==="buffer"?(a=>typeof window=="undefined"?Buffer.from(a):a)(n.data):Ee(new Uint8Array(n.data),n.mimeType),mimeType:n.mimeType}}catch(n){throw d(n,this.screenshot),n}}async heartbeat(){try{return await this.socket.send("heartbeat")}catch(t){throw d(t,this.heartbeat),t}}async type(t){try{await I(1e3);const s=await this.playAction({type:"typeText",text:t});return await I(500),s}catch(s){throw d(s,this.type),s}}async keypress(t,s){try{if(t==="ANDROID_KEYCODE_MENU")return await this.socket.send("androidKeycodeMenu");if((s==null?void 0:s.shift)||t==="HOME"){switch(t){case"ArrowUp":t="arrowUp";break;case"ArrowDown":t="arrowDown";break;case"ArrowLeft":t="arrowLeft";break;case"ArrowRight":t="arrowRight";break;case"Enter":t="\r";break;case"Tab":t=" ";break;case"Backspace":t="\b";break}return this.playAction({type:"keypress",key:t,shiftKey:!!(s!=null&&s.shift)})}else return this.playAction({type:"keypress",character:t})}catch(n){throw d(n,this.keypress),n}}async setLanguage(t){try{return this.config.language=t,await this.socket.send("setLanguage",{language:t,timeStamp:Date.now()})}catch(s){throw d(s,this.setLanguage),s}}async setLocation(t,s){try{if(typeof t!="number"||typeof s!="number")throw new y("setLocation requires latitude and longitude to be numbers");const n=[t,s];return this.config.location=n,await this.socket.send("setLocation",{location:n,timeStamp:Date.now()})}catch(n){throw d(n,this.setLocation),n}}async openUrl(t){try{return await this.socket.send("openUrl",{url:t,timeStamp:Date.now()})}catch(s){throw d(s,this.openUrl),s}}async shake(){try{return await this.socket.send("shakeDevice")}catch(t){throw d(t,this.swipe),t}}async toggleSoftKeyboard(){try{if(this.config.platform!=="ios")throw new Error("toggleSoftKeyboard is only available on iOS devices");return await this.socket.send("toggleSoftKeyboard")}catch(t){throw d(t,this.toggleSoftKeyboard),t}}async biometry({match:t}){try{return await this.socket.send(t?"biometryMatch":"biometryNoMatch")}catch(s){throw d(s,this.biometry),s}}async allowInteractions(t){try{return await this.socket.send(t?"enableInteractions":"disableInteractions")}catch(s){throw d(s,this.allowInteractions),s}}async restartApp(){try{this.socket.send("restartApp");const{platform:t}=this.config;t==="ios"?await this.waitForEvent("appLaunch",{timeout:6e4}):await I(1e3)}catch(t){throw d(t,this.restartApp),t}}async reinstallApp(){try{this.socket.send("reinstallApp"),await this.waitForEvent("appLaunch",{timeout:6e4})}catch(t){throw d(t,this.reinstallApp),t}}async adbShellCommand(t){if(this.config.platform!=="android")throw new Error("adbShellCommand is only available on Android devices");try{return await this.socket.send("adbShellCommand",{command:t,timeStamp:Date.now()})}catch(s){throw d(s,this.adbShellCommand),s}}async playAction(t,s={}){const{timeout:n=1e4}=s;try{if(!this.config.record)throw new M("playAction()");if(isNaN(n))throw new y(`Invalid timeout value: ${s.timeout}`);if(n<0)throw new y(`Timeout value cannot be negative: ${s.timeout}`);"element"in t&&t.element&&be(t.element);const r=new fe({platform:this.config.platform,screen:this.device.screen,app:this.app}),o=ce(),c=s.noMap?t:r.mapAction(t),h={id:o,action:c,options:{...s,timeout:Math.round(n/1e3)}},[u]=await Promise.all([new Promise((l,w)=>{const g=()=>{this.off("playbackFoundAndSent",b),this.off("playbackError",$)},b=async m=>{var R;((R=m.playback)==null?void 0:R.id)===o&&(await this.addActionLog({action:t,payload:h,result:m}),g(),l(m))},$=async m=>{var R;if(((R=m.playback)==null?void 0:R.id)===o)switch(await this.addActionLog({action:t,payload:h,error:m}),g(),m.errorId){case"internalError":w(new y(`An internal error has occurred for the action: | ||
${JSON.stringify(t,null,2)}`));break;case"notFound":if(m.playback!==void 0&&"element"in m.playback.action&&m.playback.action.element!==void 0){w(new le(m.playback.action.element));break}case"ambiguousMatch":if("matchedElements"in m&&m.matchedElements!==void 0){w(new de(m.matchedElements));break}case"invalidArgument":if("element"in t&&t.element&&m.message.match("outside the screen bounds")){w(new pe(t));break}default:w(new y(m.message));break}};this.once("playbackFoundAndSent",b),this.once("playbackError",$)}),this.socket.send("playAction",h)]);return u}catch(r){throw d(r,this.playAction),r}}async playActions(t,s={}){try{if(!this.config.record)throw new M("playActions()");const n=[];for(const r of t){const o=await this.playAction(r,s);n.push(o);const a=t[t.indexOf(r)+1];a&&a.type==="keypress"&&r.type==="keypress"||await I(1e3)}return n}catch(n){throw d(n,this.playActions),n}}async getUI({timeout:t=3e4}={}){try{return this.socket.send("dumpUi"),await D(this,"uiDump",{timeout:t})}catch(s){throw d(s,this.getUI),s}}async findElement(t,s){var n;try{return(n=(await this.playAction({type:"findElements",element:t,appId:s==null?void 0:s.appId},s)).matchedElements)==null?void 0:n[0]}catch(r){throw d(r,this.findElement),r}}async findElements(t,s){try{return(await this.playAction({type:"findElements",element:t,appId:s==null?void 0:s.appId},s)).matchedElements}catch(n){throw d(n,this.findElements),n}}async tap(t,s){var n;try{if(!this.config.record)throw new M("tap()");return await this.playAction({type:"tap",...t,duration:((n=t.duration)!=null?n:0)/1e3},s)}catch(r){throw d(r,this.tap),r}}async swipe({duration:t,gesture:s,...n},r){try{if(!this.config.record)throw new M("swipe()");let o;const a=new ke({duration:t});if(typeof s=="function")s(a);else switch(s){case"up":a.up();break;case"down":a.down();break;case"left":a.left();break;case"right":a.right();break}if("element"in n)o={type:"swipe",element:n.element,localPosition:n.localPosition,moves:a.build()};else if("position"in n)o={type:"swipe",position:n.position,moves:a.build()};else throw new Error("Either element or position must be specified");return this.playAction(o,r)}catch(o){throw d(o,this.swipe),o}}async waitForAnimations(t={}){try{const{imageThreshold:s=.001,timeout:n=1e4}=t;let r=1e3,o=1;t.imageThresholdDuration&&(r=t.imageThresholdDuration);const[a,c,h]=ue(),u=setTimeout(()=>{h(new C(`Timed out after ${n}ms waiting for animation to end. Waited for imageThreshold of ${s} but lowest was ${o.toFixed(2)}`))},n);let l;const w=({percentage:g,timestamp:b})=>{g<o&&(o=g),g<=s?(l||(l=b),l&&b-l>=r&&c()):l=void 0};return this.socket.send("enablePixelChangeDetection"),this.socket.on("pixelsChanged",w),this._waitForAnimationsPromises.add(a),await a.finally(()=>{clearTimeout(u),this.socket.off("pixelsChanged",w),this._waitForAnimationsPromises.delete(a),this._waitForAnimationsPromises.size===0&&this.socket.send("disablePixelChangeDetection")})}catch(s){throw d(s,this.waitForAnimations),s}}async addActionLog(t){this.actionLogs.push(t)}async getAdbInfo(){return this.logger.warn("getAdbInfo() is deprecated. Please use the `adbConnection` property instead."),Promise.resolve(S(this,A))}async getNetworkInspectorUrl(){return this.logger.warn("getNetworkInspectorUrl() is deprecated. Please use the `networkInspectorUrl` property instead."),Promise.resolve(S(this,P))}async getDeviceInfo(){return this.logger.warn("getDeviceInfo() is deprecated. Please use the `device` property instead."),Promise.resolve(this.device)}}A=new WeakMap,P=new WeakMap;function Se(i){const e="ssh -fN -o StrictHostKeyChecking=no -oHostKeyAlgorithms=+ssh-rsa -p SERVER_PORT USERNAME@HOSTNAME -L6000:FORWARD_DESTINATION:FORWARD_PORT && adb connect localhost:6000";if(!i||!i.forwards[0])return;let t=e;return t=t.replace(/SERVER_PORT/,i.port.toString()),t=t.replace(/USERNAME/,i.user),t=t.replace(/HOSTNAME/,i.hostname),t=t.replace(/FORWARD_DESTINATION/,i.forwards[0].destination),t=t.replace(/FORWARD_PORT/,i.forwards[0].port.toString()),t}v.expect.extend({toHaveElement:async(i,e,t={})=>{try{const s=await i.findElements(e,t);return{pass:typeof t.matches=="number"?s.length===t.matches:s.length>0,message:()=>`Element not found: | ||
${JSON.stringify(e,null,2)}`}}catch(s){return{pass:!1,message:()=>s.message}}}});class _e extends f.EventEmitter{constructor({socket:e,logger:t=new V}){super(),this.logger=t,this.socket=e,this.socket.on("*",({type:s,value:n})=>{const r=Te(s,n);r!==null&&(r?(this.emit(r.type,r.value),this.emit("*",r)):(this.emit(s,n),this.emit("*",{type:s,value:n})))})}on(e,t){return super.on(e,t)}async startSession(e){throw new Error("Not implemented")}async setConfig(e){throw new Error("Not implemented")}getConfig(){return this._config}async waitForSessionStart(e){return new Promise(async(t,s)=>{const n=()=>{s(new Error("Session disconnected before it was ready"))},r=a=>{s(new Error(`Session failed to start - ${typeof a.message=="object"?JSON.stringify(a.message):a.message}`))},o=a=>{a.message.match(/Too many requests/)&&s(new Error("Session failed to start due to too many requests"))};try{this.on("error",o),e.on("disconnect",n),e.on("error",r),await e.waitUntilReady()}finally{this.off("error",o),e.off("disconnect",n),e.off("error",r)}t(e)})}}function Te(i,e){switch(i){case"concurrentQueue":return{type:"queue",value:{type:"concurrent",name:e.name,position:e.position}};case"queue":return{type:"queue",value:{type:"session",position:e.position}};case"userError":return{type:"error",value:e};case"newSession":return null}}class Pe extends _e{constructor({socket:e,window:t,logger:s=new V,config:n}){super({socket:e,logger:s}),this.ready=!1,this.window=t,n&&(this._config=this.mapConfig(n)),this.window.on("*",async({type:r,value:o})=>{if(this.ready)switch(r){case"app":this.app=o,this.emit(r,o);break;case"deviceInfo":this.device=o,this.emit(r,o);break;case"config":this._config=this.mapConfig(o);break}}),this.window.on("reinit",()=>{this.ready=!1,this.session=void 0,this.init({isReinit:!0})}),this.socket.on("*",async({type:r,value:o})=>{if(this.ready)switch(r){case"newSession":try{this.session=this.createSession(this._config,{path:o.path,token:o.sessionToken}),await this.waitForSessionStart(this.session),this.emit("session",this.session)}catch(a){this.session=void 0,this.emit("sessionError",a)}}}),this.init()}async init(e={isReinit:!1}){await this.window.waitUntilReady();const t=async()=>{if(e.isReinit){const r=this._config,o=await this.setConfig({});return this.setConfig({record:!0,...r,...o})}else return this.setConfig({record:!0,...this._config})},[s,n]=await Promise.all([this.window.postMessage({type:"getApp"},!0),this.window.postMessage({type:"getDeviceInfo"},!0),t()]);this.app=s,this.device=n,this.ready=!0}async waitUntilReady(){if(!this.ready)return H(async()=>{if(!this.ready)throw new Error("Timed out waiting for client to be ready")},3e4)}async startSession(e){try{await this.waitUntilReady()}catch(s){const n=s instanceof Error?s.message:s;throw new Error(`Failed to start session. ${n}`)}this.session&&await this.session.end(),await this.setConfig(e!=null?e:{});const[t]=await Promise.all([new Promise((s,n)=>{const r=a=>{this.off("session",r),this.off("sessionError",o),s(a)},o=a=>{this.off("session",r),this.off("sessionError",o),n(a)};this.on("session",r),this.on("sessionError",o)}),this.window.postMessage({type:"requestSession"},!0)]);return t}async config(e){return this.logger.warn("client.config() is deprecated and will be removed in a future major release. Use client.setConfig() instead."),this.setConfig(e)}async setConfig({publicKey:e,...t}){if(e){const n=await this.window.postMessage({type:"loadApp",value:e},!0);if(n&&"error"in n)throw new Error(n.error)}const s=await this.window.postMessage({type:"setConfig",value:this.validateConfig(t!=null?t:{})},!0).then(this.mapConfig);return this._config=s,s}mapConfig(e){return{...E(e),device:e.deviceType||e.device}}validateConfig(e){return e}createSession(e,t){throw new Error("Not implemented")}}class $e extends V{constructor(){super(...arguments),this.logHistory=[],this.logLevel=process.env.CI==="true"?"warnings-errors":"verbose",this.log=(...e)=>{if(this.logHistory.push({method:"log",data:e}),this.logLevel==="verbose")return console.log(...e)},this.warn=(...e)=>{if(this.logHistory.push({method:"warn",data:e}),this.logLevel==="verbose"||this.logLevel==="warnings-errors")return console.warn(...e)},this.error=(...e)=>{if(this.logHistory.push({method:"error",data:e}),this.logLevel==="verbose"||this.logLevel==="warnings-errors")return console.error(...e)},this.debug=(...e)=>{if(this.logHistory.push({method:"debug",data:e}),this.logLevel==="verbose")return console.debug(...e)},this.clearLogHistory=()=>{this.logHistory=[]}}}const _=new $e;async function Fe(i){await i.pause()}function K(i){if(i.character)return i.character;const e=i.key;return z(e)?e:i.shiftKey?e.toUpperCase():e.toLowerCase()}function z(i){return/^[\b\t\r]/.test(i)}class Ce{constructor({testInfo:e,session:t}){this.currentRecord=0,this.session=t,this.testInfo=e}async record(){const e=this.testInfo.file,t=await F.default.promises.readFile(e,"utf8"),n=t.split(` | ||
`).map((r,o)=>({line:r,num:o+1})).slice(this.testInfo.line).filter(({line:r})=>r.includes("session.record()"))[this.currentRecord].num;if(n!==void 0){console.log(`\u{1F534} Recording at line ${n}`);const r=[],o=c=>{Ie(r,c),console.log(Y(c))};this.session.on("action",o),await Fe(this.session.page),await I(2e3),this.session.off("action",o);const a=t.split(` | ||
`).map((c,h)=>{var u,l;if(h===n-1){const w=(l=(u=c.match(/^\s*/))==null?void 0:u[0])!=null?l:0;return`${r.map(b=>Y(b)).reduce((b,$,m)=>`${b} | ||
// ${m+1}. ${$}`,"// Recorded using session.record()")} | ||
await session.playActions(${JSON.stringify(r,null," ")})`.split(` | ||
`).map(b=>w+b).join(` | ||
`)}return c});await C.default.promises.writeFile(e,a.join(` | ||
`)),console.log("\u{1F7E2} Finished"),this.currentRecord+=1}}}function Ie(i,e){const t=i[i.length-1];if(t)switch(e.type){case"keypress":{(t==null?void 0:t.type)==="keypress"&&!z(e.key)&&!z(t.key)?(i.pop(),i.push({type:"typeText",text:K(t)+K(e)})):(t==null?void 0:t.type)==="typeText"&&!z(e.key)?(i.pop(),i.push({type:"typeText",text:t.text+K(e)})):i.push(e);break}default:i.push(e)}else i.push(e)}function Y(i){var t,s,n,r,o,a;let e="";switch(i.type){case"swipe":case"tap":{const c=i.element;return typeof c=="string"?e=` on element "${c}"`:(t=c==null?void 0:c.attributes)!=null&&t.accessibilityIdentifier?e=`element with accessibilityIdentifier "${(s=c.attributes)==null?void 0:s.accessibilityIdentifier}"`:(n=c==null?void 0:c.attributes)!=null&&n.class?e=`element with class "${(r=c.attributes)==null?void 0:r.class}"`:"position"in i&&((o=i.position)==null?void 0:o.x)&&((a=i.position)==null?void 0:a.y)&&(e=`position ${Math.round(i.position.x*100)}%, ${Math.round(i.position.y*100)}%`),e?`${i.type} on ${e}`:i.type}case"keypress":return`type "${K(i)}"`;case"typeText":return`type "${i.text}"`}}function Q({type:i,value:e}){switch(i){case"deviceInfo":return{type:"deviceInfo",value:e};case"sessionRequested":return{type:"sessionRequested"};case"chromeDevToolsUrl":return{type:"networkInspectorUrl",value:e};case"orientationChanged":return{type:"orientationChanged",value:e}}}const De="1.1.0";class Oe extends f.EventEmitter{constructor({page:e}){super(),this.ready=!1,this.page=e,this.page.exposeFunction("__appetize_on",t=>{const s=t==="string"?t:t.type;this.emit(s,t.value),this.emit("*",{type:s,value:t.value})})}async init(){this.ready=!1,await this.page.evaluate(async([e])=>new Promise((t,s)=>{const n=setTimeout(()=>{clearInterval(r),s(new I("Timed out after 60000ms waiting for connection to Appetize page"))},6e4),r=setInterval(()=>{const o=new MessageChannel;o.port1.onmessage=()=>{clearInterval(r),clearTimeout(n),t(!1)},window.postMessage({type:"init",appetizeClient:!0,version:e},"*",[o.port2]),window.__appetize_postMessage=async(a,c=!1)=>{const h=new MessageChannel;if(window.postMessage(a,"*",[h.port2]),c)return new Promise((u,l)=>{const w=setTimeout(()=>{l(new I("Timed out after 60000ms while waiting for postMessage response"))},6e4);h.port1.onmessage=g=>{clearTimeout(w),u(g.data)}})}},100)}),[De]),await this.page.evaluate(()=>{window.__appetize__video_frames=[],window.__appetize__audio_frames=[],window.addEventListener("message",e=>{var t;if(e.source===window){const s=typeof e.data=="string"?e.data:(t=e.data)==null?void 0:t.type;if(s==="socketEvent")switch(e.data.value.type){case"h264Data":case"frameData":if(window.__appetize__video_frames.push(e.data.value.value),!window.__appetize_emit_video)return;break;case"audioData":if(window.__appetize__audio_frames.push(e.data.value.value),!window.__appetize_emit_audio)return;break}else switch(s){case"frameData":case"recordedAction":case"playbackFoundAndSent":case"playbackNotFound":case"debug":case"interceptRequest":case"interceptResponse":case"interceptError":case"uiDump":return}window.__appetize_on(e.data)}})},[]),this.ready=!0}async waitUntilReady(){return H(async()=>{if(!this.ready)throw new I("Timed out after 60000ms while waiting for Appetize window to be ready.")},6e4)}enableVideoEvents(e=!0){return this.page.evaluate(t=>{window.__appetize_emit_video=t},e)}enableAudioEvents(e=!0){return this.page.evaluate(t=>{window.__appetize_emit_audio=t},e)}async postMessage(e,t=!1){return await this.waitUntilReady(),this.page.evaluate(async([s,n])=>window.__appetize_postMessage(s,n),[e,t])}async getVideoFrames(){return this.page.evaluate(()=>window.__appetize__video_frames)}async getAudioFrames(){return this.page.evaluate(()=>window.__appetize__audio_frames)}async resetVideoFrames(){return this.page.evaluate(()=>{window.__appetize__video_frames=[]})}async resetAudioFrames(){return this.page.evaluate(()=>{window.__appetize__audio_frames=[]})}}class X extends f.EventEmitter{constructor({page:e,type:t,window:s}){super(),this.page=e,this.type=t,this.window=s,this.window.on("*",({type:n,value:r})=>{switch(n){case"socketEvent":r.socket===this.type&&(this.emit(r.type,r.value),this.emit("*",{type:r.type,value:r.value}));break;case"disconnect":this.emit("disconnect"),this.emit("*",{type:"disconnect"});break;case"sessionInfo":case"chromeDevToolsUrl":case"orientationChanged":case"deviceInfo":if(this.type==="appetizer"){const o=Q({type:n,value:r});o&&(this.emit(o.type,o.value),this.emit("*",o))}break;case"sessionRequested":if(this.type==="webserver"){const o=Q({type:n,value:r});o&&(this.emit(o.type,o.value),this.emit("*",o))}break}})}async send(e,t){return this.window.postMessage({type:"emitSocketEvent",value:{type:e,value:t,socket:this.type}})}async disconnect(){await this.send("disconnect")}waitForEvent(e,t){return _(this,e,t)}}class Re extends Ae{constructor({page:e,config:t,window:s,testInfo:n,...r}){const o=new X({page:e,window:s,type:"appetizer"});super({...r,socket:o,config:t,logger:T}),this.actionLogs=[],this.window=s,this.page=e,this.config=t,this.testInfo=n,this.page.on("load",()=>{this.emit("disconnect")}),t.record&&this.on("disconnect",()=>{this.teardownUi()})}async addActionLog(e){if(e.error){const t=await this.getUI().catch(this.logger.warn);t&&(e.ui=t)}this.actionLogs.push(e)}teardownUi(){return this.window.page.evaluate(()=>{const e=document.querySelector("app-ui");e&&e.remove()})}async rotate(e){try{const[t]=await Promise.all([_(this.window,"orientationChanged"),await this.window.postMessage(e==="left"?"rotateLeft":"rotateRight")]);return this.window.page.waitForTimeout(1e3),t}catch(t){throw d(t,this.rotate),t}}async screenshot(e="buffer"){try{const[t]=await Promise.all([_(this.socket,"screenshot",{timeout:6e4}),this.socket.send("getScreenshot",{})]),s=new Uint8Array(Object.values(t.data).map(Number));return{data:e==="buffer"?Buffer.from(s):t.data,mimeType:t.mimeType}}catch(t){throw d(t,this.screenshot),t}}async record(){try{if(!this.config.record)throw new m("Recording is not enabled, please enable it by setting `record: true` in session config");if(!this.testInfo)throw new m("session.record() requires using `session` from the test() arguments");return new Ce({session:this,testInfo:this.testInfo}).record()}catch(e){throw d(e,this.record),e}}async waitForEvent(e,t){try{return await _(this,e,t)}catch(s){throw d(s,this.waitForEvent),s}}async waitForTimeout(e){try{return await D(e)}catch(t){throw d(t,this.waitForTimeout),t}}async waitForElement(e,t){try{const s=await this.findElements(e,t);if(s.length){if((t==null?void 0:t.matches)&&s.length!==t.matches)throw new Error(`Expected ${t.matches} elements, found ${s.length}`);return s}else throw new Error(`Element not found: | ||
${JSON.stringify(e)}`)}catch(s){throw d(s,this.waitForElement),s}}on(e,t){return e==="video"&&(q.onVideo||(this.logger.warn("Listening to the `video` event will significantly slow down your tests. It is recommended to use session.getVideoFrames() instead."),q.onVideo=!0),this.window.enableVideoEvents()),e==="audio"&&(q.onAudio||(this.logger.warn("Listening to the `audio` event will significantly slow down your tests. It is recommended to use session.getAudioFrames() instead."),q.onAudio=!0),this.window.enableAudioEvents()),super.on(e,t)}once(e,t){return e==="video"&&this.window.enableVideoEvents(),e==="audio"&&this.window.enableAudioEvents(),super.once(e,t)}async getVideoFrames(){return(await this.window.getVideoFrames()).map(t=>({...t,buffer:new Uint8Array(Object.values(t.buffer).map(Number))}))}async getAudioFrames(){return(await this.window.getAudioFrames()).map(t=>({...t,buffer:new Uint8Array(Object.values(t.buffer).map(Number))}))}}const q={onVideo:!1,onAudio:!1},G=new WeakMap;class Ne extends Pe{constructor({page:e}){var r;const t=(r=G.get(e))!=null?r:new Oe({page:e});G.set(e,t),t.init();const s=new X({type:"webserver",page:e,window:t});super({socket:s,window:t,logger:T}),this.window=t,this.page=e;let n=!1;this.on("queue",o=>{n||(n=!0,o.type==="concurrent"?this.logger.log(`Entered ${o.name}. Please wait until a slot becomes available.`):this.logger.log("All devices are currently in use. Please wait until requested device becomes available.")),o.position>0&&(o.type==="concurrent"?this.logger.log(`Position in ${o.name}: ${o.position}`):this.logger.log(`Position in queue: ${o.position}`))}),this.on("session",()=>{n&&(n=!1)})}validateConfig(e){var s;return{codec:((s=this.page.context().browser())==null?void 0:s.browserType().name())==="chromium"?"jpeg":"h264",...e}}createSession(e,t){return this.session=new Re({config:e,page:this.page,window:this.window,path:t.path,token:t.token,device:this.device,app:this.app}),this.session}}class Me{constructor(e){this.queue=null,this.page=e}async start(e){const{config:t,baseURL:s}=e,{publicKey:n,...r}=t;await this.page.goto(`${s!=null?s:"https://appetize.io"}/embed/${n}?${he(r)}`),this.client=new Ne({page:this.page}),this.client.on("queue",a=>{this.queue=a});const o=async a=>{a!=null&&a.embed&&await this.page.setViewportSize({width:a.embed.width,height:a.embed.height})};this.client.on("deviceInfo",o),await this.client.waitUntilReady(),this.client.device&&o(this.client.device),this.session=await ae(()=>this.client.startSession({...t}),{retries:5,timeout:3e4,predicate:(a,c)=>a instanceof Error&&a.message.match(/too many requests/)?(console.warn(`Too many session requests. Retrying in 30 seconds... (attempt #${c})`),!0):!1})}}const Z=new Set;function ee(i){Z.has(i)||(Z.add(i),console.warn(i))}let O,te;const j=v.test.extend({config:[async({_useConfig:i},e,t)=>{await e({...t.project.use.config,...i,autoplay:!1})},{auto:!0}],page:async({appetizePage:i},e)=>{await e(i.page)},appetizePage:async({context:i,config:e},t)=>{if(O&&JSON.stringify(te)!==JSON.stringify(e)&&(await O.page.close(),O=null),!O&&(O=new Me(await i.newPage()),te=e,!e.publicKey))throw new Error('Appetize public key not set. Make sure you have run test.use({ config: { publicKey: "..." } })');await t(O)},session:async({appetizePage:i,config:e,baseURL:t,_doSetupAndTeardown:s},n,r)=>{i.session||await P.step("Start Appetize session",async()=>{if(await i.start({config:e,baseURL:t}),!i.session)throw new Error("Appetize session failed to start");await P.step(`${i.session.path}/client?sessionToken=${i.session.token}`,()=>{P.info().annotations.push({type:"session.path",description:i.session.path},{type:"session.token",description:i.session.token}),Object.entries(i.session.config).forEach(([o,a])=>{P.info().annotations.push({type:`session.config.${o}`,description:JSON.stringify(a,null,2)})}),P.info().attach("Appetize Session Info",{contentType:"application/json",body:Buffer.from(JSON.stringify({path:i.session.path,token:i.session.token,config:i.session.config},null,2))})})}),i.session.testInfo=r,await n(i.session)},client:async({appetizePage:i},e)=>{await e(i.client)},_useConfig:[{},{option:!0}],_autoSnapshotSuffix:[async({},i,e)=>{e.snapshotSuffix="",await i()},{auto:!0}],_doSetupAndTeardown:[async({appetizePage:i},e,t)=>{var s,n;T.clearLogHistory(),i.session&&(i.session.actionLogs=[],await i.session.window.resetVideoFrames(),await i.session.window.resetAudioFrames()),await e(),await ne(i,t),t.status==="timedOut"&&((n=(s=i.queue)==null?void 0:s.position)!=null?n:0)>0&&T.warn("Test timed out while in queue for a device. You may increase your test timeout to account for higher queue times.")},{auto:!0}],context:[async({_browserContext:i,video:e,contextOptions:t},s)=>{e&&e!=="off"&&ee("Video recording is not yet supported with @appetize/playwright. Use tracing instead to view recordings of your tests https://docs.appetize.io/javascript-sdk/playwright/trace-viewer"),Object.keys(t).length&&ee("contextOptions are not supported with @appetize/playwright"),await s(i)},{scope:"test"}],_browserContext:[async({browser:i},e)=>{const t=await i.newContext();await e(t),await t.close()},{scope:"worker"}]}),Ue=j.use,se=j.afterEach;Object.assign(j,{setup(i){return{}.__APPETIZE__SETUP_WARNED||T.warn("test.setup() is deprecated and will be removed in a future release. Use test.use({ config: {...} }) instead"),P.use({config:i})},use(i){const{config:e,...t}=i;return Ue({...t,_useConfig:e})},afterEach(i){return se(async({appetizePage:e},t)=>{e&&await ne(e,t)}),se(i)}});const P=j,ie=new WeakMap;async function ne(i,e){if(ie.get(e.fn))return;ie.set(e.fn,!0);const t=i.session,s="fail-output";if(e.status==="failed"||e.status==="timedOut"){if(t){const o=t.actionLogs;await C.default.promises.mkdir(e.outputPath(s));const a=async()=>{try{const h=await t.screenshot("buffer");await e.attach("screenshot",{body:h.data,contentType:"image/png"});const u=e.outputPath(s,"screenshot.png");await C.default.promises.writeFile(u,Buffer.from(h.data))}catch{}},c=async()=>{try{const h=o.map(w=>{if("screenshot"in w){const{screenshot:g,...b}=w;return b}return w});if(!h.length)return;const u=JSON.stringify(h,null,2);await e.attach("actions",{body:u,contentType:"application/json"});const l=e.outputPath(s,"actions.json");await C.default.promises.writeFile(l,u)}catch{}};await Promise.all([a(),c()])}await(async()=>{if(!!T.logHistory.length)try{const o=`${T.logHistory.map(c=>`[${c.method}] ${JSON.stringify(c.data).slice(2,-2)}`).join(` | ||
`)}`;await e.attach("sdk-logs",{body:o,contentType:"application/text"});const a=e.outputPath(s,"sdk-logs.txt");await C.default.promises.writeFile(a,o)}catch{}})()}}Object.defineProperty(p,"expect",{enumerable:!0,get:function(){return v.expect}}),p.test=P,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); | ||
`)}return c});await F.default.promises.writeFile(e,a.join(` | ||
`)),console.log("\u{1F7E2} Finished"),this.currentRecord+=1}}}function Ie(i,e){const t=i[i.length-1];if(t)switch(e.type){case"keypress":{(t==null?void 0:t.type)==="keypress"&&!z(e.key)&&!z(t.key)?(i.pop(),i.push({type:"typeText",text:K(t)+K(e)})):(t==null?void 0:t.type)==="typeText"&&!z(e.key)?(i.pop(),i.push({type:"typeText",text:t.text+K(e)})):i.push(e);break}default:i.push(e)}else i.push(e)}function Y(i){var t,s,n,r,o,a;let e="";switch(i.type){case"swipe":case"tap":{const c=i.element;return typeof c=="string"?e=` on element "${c}"`:(t=c==null?void 0:c.attributes)!=null&&t.accessibilityIdentifier?e=`element with accessibilityIdentifier "${(s=c.attributes)==null?void 0:s.accessibilityIdentifier}"`:(n=c==null?void 0:c.attributes)!=null&&n.class?e=`element with class "${(r=c.attributes)==null?void 0:r.class}"`:"position"in i&&((o=i.position)==null?void 0:o.x)&&((a=i.position)==null?void 0:a.y)&&(e=`position ${Math.round(i.position.x*100)}%, ${Math.round(i.position.y*100)}%`),e?`${i.type} on ${e}`:i.type}case"keypress":return`type "${K(i)}"`;case"typeText":return`type "${i.text}"`}}function Q({type:i,value:e}){switch(i){case"deviceInfo":return{type:"deviceInfo",value:e};case"sessionRequested":return{type:"sessionRequested"};case"chromeDevToolsUrl":return{type:"networkInspectorUrl",value:e};case"orientationChanged":return{type:"orientationChanged",value:e}}}const De="1.1.2";class Oe extends f.EventEmitter{constructor({page:e}){super(),this.ready=!1,this.page=e,this.page.exposeFunction("__appetize_on",t=>{const s=t==="string"?t:t.type,n=t.value;this.emit(s,n),this.emit("*",{type:s,value:n})})}async init(){this.ready=!1,await this.page.evaluate(async([e])=>new Promise((t,s)=>{const n=setTimeout(()=>{clearInterval(r),s(new C("Timed out after 60000ms waiting for connection to Appetize page"))},6e4),r=setInterval(()=>{const o=new MessageChannel;o.port1.onmessage=()=>{clearInterval(r),clearTimeout(n),t(!1)},window.postMessage({type:"init",appetizeClient:!0,version:e},"*",[o.port2]),window.__appetize_postMessage=async(a,c=!1)=>{const h=new MessageChannel;if(window.postMessage(a,"*",[h.port2]),c)return new Promise((u,l)=>{const w=setTimeout(()=>{l(new C("Timed out after 60000ms while waiting for postMessage response"))},6e4);h.port1.onmessage=g=>{clearTimeout(w),u(g.data)}})}},100)}),[De]),await this.page.evaluate(()=>{window.__appetize__video_frames=[],window.__appetize__audio_frames=[],window.addEventListener("message",e=>{var t;if(e.source===window){const s=typeof e.data=="string"?e.data:(t=e.data)==null?void 0:t.type;if(s==="socketEvent")switch(e.data.value.type){case"h264Data":case"frameData":if(window.__appetize__video_frames.push(e.data.value.value),!window.__appetize_emit_video)return;break;case"audioData":if(window.__appetize__audio_frames.push(e.data.value.value),!window.__appetize_emit_audio)return;break}else switch(s){case"frameData":case"recordedAction":case"playbackFoundAndSent":case"playbackNotFound":case"debug":case"interceptRequest":case"interceptResponse":case"interceptError":case"uiDump":return}window.__appetize_on(e.data)}})},[]),this.ready=!0}async waitUntilReady(){return H(async()=>{if(!this.ready)throw new C("Timed out after 60000ms while waiting for Appetize window to be ready.")},6e4)}enableVideoEvents(e=!0){return this.page.evaluate(t=>{window.__appetize_emit_video=t},e)}enableAudioEvents(e=!0){return this.page.evaluate(t=>{window.__appetize_emit_audio=t},e)}async postMessage(e,t=!1){return await this.waitUntilReady(),this.page.evaluate(async([s,n])=>window.__appetize_postMessage(s,n),[e,t])}async getVideoFrames(){return this.page.evaluate(()=>window.__appetize__video_frames)}async getAudioFrames(){return this.page.evaluate(()=>window.__appetize__audio_frames)}async resetVideoFrames(){return this.page.evaluate(()=>{window.__appetize__video_frames=[]})}async resetAudioFrames(){return this.page.evaluate(()=>{window.__appetize__audio_frames=[]})}}class X extends f.EventEmitter{constructor({page:e,type:t,window:s}){super(),this.page=e,this.type=t,this.window=s,this.window.on("*",({type:n,value:r})=>{switch(n){case"socketEvent":if(r.socket===this.type){const o=r.type,a=r.value;o==="screenshot"&&a.data&&(a.data=new Uint8Array(Object.values(a.data).map(Number))),this.emit(o,a),this.emit("*",{type:o,value:a})}break;case"disconnect":this.emit("disconnect"),this.emit("*",{type:"disconnect"});break;case"sessionInfo":case"chromeDevToolsUrl":case"orientationChanged":case"deviceInfo":if(this.type==="appetizer"){const o=Q({type:n,value:r});o&&(this.emit(o.type,o.value),this.emit("*",o))}break;case"sessionRequested":if(this.type==="webserver"){const o=Q({type:n,value:r});o&&(this.emit(o.type,o.value),this.emit("*",o))}break}})}async send(e,t){return this.window.postMessage({type:"emitSocketEvent",value:{type:e,value:t,socket:this.type}})}async disconnect(){await this.send("disconnect")}waitForEvent(e,t){return D(this,e,t)}}class Re extends Ae{constructor({page:e,config:t,window:s,testInfo:n,...r}){const o=new X({page:e,window:s,type:"appetizer"});super({...r,socket:o,config:t,logger:_}),this.actionLogs=[],this.window=s,this.page=e,this.config=t,this.testInfo=n,this.page.on("load",()=>{this.emit("disconnect")}),t.record&&this.on("disconnect",()=>{this.teardownUi()})}async addActionLog(e){if(e.error){const t=await this.getUI().catch(this.logger.warn);t&&(e.ui=t)}this.actionLogs.push(e)}teardownUi(){return this.window.page.evaluate(()=>{const e=document.querySelector("app-ui");e&&e.remove()})}async rotate(e){try{const[t]=await Promise.all([D(this.window,"orientationChanged"),await this.window.postMessage(e==="left"?"rotateLeft":"rotateRight")]);return this.window.page.waitForTimeout(1e3),t}catch(t){throw d(t,this.rotate),t}}async record(){try{if(!this.config.record)throw new y("Recording is not enabled, please enable it by setting `record: true` in session config");if(!this.testInfo)throw new y("session.record() requires using `session` from the test() arguments");return new Ce({session:this,testInfo:this.testInfo}).record()}catch(e){throw d(e,this.record),e}}async waitForEvent(e,t){try{return await D(this,e,t)}catch(s){throw d(s,this.waitForEvent),s}}async waitForTimeout(e){try{return await I(e)}catch(t){throw d(t,this.waitForTimeout),t}}async waitForElement(e,t){try{const s=await this.findElements(e,t);if(s.length){if((t==null?void 0:t.matches)&&s.length!==t.matches)throw new Error(`Expected ${t.matches} elements, found ${s.length}`);return s}else throw new Error(`Element not found: | ||
${JSON.stringify(e)}`)}catch(s){throw d(s,this.waitForElement),s}}on(e,t){return e==="video"&&(q.onVideo||(this.logger.warn("Listening to the `video` event will significantly slow down your tests. It is recommended to use session.getVideoFrames() instead."),q.onVideo=!0),this.window.enableVideoEvents()),e==="audio"&&(q.onAudio||(this.logger.warn("Listening to the `audio` event will significantly slow down your tests. It is recommended to use session.getAudioFrames() instead."),q.onAudio=!0),this.window.enableAudioEvents()),super.on(e,t)}once(e,t){return e==="video"&&this.window.enableVideoEvents(),e==="audio"&&this.window.enableAudioEvents(),super.once(e,t)}async getVideoFrames(){return(await this.window.getVideoFrames()).map(t=>({...t,buffer:new Uint8Array(Object.values(t.buffer).map(Number))}))}async getAudioFrames(){return(await this.window.getAudioFrames()).map(t=>({...t,buffer:new Uint8Array(Object.values(t.buffer).map(Number))}))}}const q={onVideo:!1,onAudio:!1},G=new WeakMap;class Ne extends Pe{constructor({page:e}){var r;const t=(r=G.get(e))!=null?r:new Oe({page:e});G.set(e,t),t.init();const s=new X({type:"webserver",page:e,window:t});super({socket:s,window:t,logger:_}),this.window=t,this.page=e;let n=!1;this.on("queue",o=>{n||(n=!0,o.type==="concurrent"?this.logger.log(`Entered ${o.name}. Please wait until a slot becomes available.`):this.logger.log("All devices are currently in use. Please wait until requested device becomes available.")),o.position>0&&(o.type==="concurrent"?this.logger.log(`Position in ${o.name}: ${o.position}`):this.logger.log(`Position in queue: ${o.position}`))}),this.on("session",()=>{n&&(n=!1)})}validateConfig(e){var s;return{codec:((s=this.page.context().browser())==null?void 0:s.browserType().name())==="chromium"?"jpeg":"h264",...e}}createSession(e,t){return this.session=new Re({config:e,page:this.page,window:this.window,path:t.path,token:t.token,device:this.device,app:this.app}),this.session}}class Me{constructor(e){this.queue=null,this.page=e}async start(e){const{config:t,baseURL:s}=e,{publicKey:n,...r}=t;await this.page.goto(`${s!=null?s:"https://appetize.io"}/embed/${n}?${he(r)}`),this.client=new Ne({page:this.page}),this.client.on("queue",a=>{this.queue=a});const o=async a=>{a!=null&&a.embed&&await this.page.setViewportSize({width:a.embed.width,height:a.embed.height})};this.client.on("deviceInfo",o),await this.client.waitUntilReady(),this.client.device&&o(this.client.device),this.session=await ae(()=>this.client.startSession({...t}),{retries:5,timeout:3e4,predicate:(a,c)=>a instanceof Error&&a.message.match(/too many requests/)?(console.warn(`Too many session requests. Retrying in 30 seconds... (attempt #${c})`),!0):!1})}}const Z=new Set;function ee(i){Z.has(i)||(Z.add(i),console.warn(i))}let O,te;const j=v.test.extend({config:[async({_useConfig:i},e,t)=>{await e({...t.project.use.config,...i,autoplay:!1})},{auto:!0}],page:async({appetizePage:i},e)=>{await e(i.page)},appetizePage:async({context:i,config:e},t)=>{if(O&&JSON.stringify(te)!==JSON.stringify(e)&&(await O.page.close(),O=null),!O&&(O=new Me(await i.newPage()),te=e,!e.publicKey))throw new Error('Appetize public key not set. Make sure you have run test.use({ config: { publicKey: "..." } })');await t(O)},session:async({appetizePage:i,config:e,baseURL:t,_doSetupAndTeardown:s},n,r)=>{i.session||await T.step("Start Appetize session",async()=>{if(await i.start({config:e,baseURL:t}),!i.session)throw new Error("Appetize session failed to start");await T.step(`${i.session.path}/client?sessionToken=${i.session.token}`,()=>{T.info().annotations.push({type:"session.path",description:i.session.path},{type:"session.token",description:i.session.token}),Object.entries(i.session.config).forEach(([o,a])=>{T.info().annotations.push({type:`session.config.${o}`,description:JSON.stringify(a,null,2)})}),T.info().attach("Appetize Session Info",{contentType:"application/json",body:Buffer.from(JSON.stringify({path:i.session.path,token:i.session.token,config:i.session.config},null,2))})})}),i.session.testInfo=r,await n(i.session)},client:async({appetizePage:i},e)=>{await e(i.client)},_useConfig:[{},{option:!0}],_autoSnapshotSuffix:[async({},i,e)=>{e.snapshotSuffix="",await i()},{auto:!0}],_doSetupAndTeardown:[async({appetizePage:i},e,t)=>{var s,n;_.clearLogHistory(),i.session&&(i.session.actionLogs=[],await i.session.window.resetVideoFrames(),await i.session.window.resetAudioFrames()),await e(),await ne(i,t),t.status==="timedOut"&&((n=(s=i.queue)==null?void 0:s.position)!=null?n:0)>0&&_.warn("Test timed out while in queue for a device. You may increase your test timeout to account for higher queue times.")},{auto:!0}],context:[async({_browserContext:i,video:e,contextOptions:t},s)=>{e&&e!=="off"&&ee("Video recording is not yet supported with @appetize/playwright. Use tracing instead to view recordings of your tests https://docs.appetize.io/javascript-sdk/playwright/trace-viewer"),Object.keys(t).length&&ee("contextOptions are not supported with @appetize/playwright"),await s(i)},{scope:"test"}],_browserContext:[async({browser:i},e)=>{const t=await i.newContext();await e(t),await t.close()},{scope:"worker"}]}),Ue=j.use,se=j.afterEach;Object.assign(j,{setup(i){return{}.__APPETIZE__SETUP_WARNED||_.warn("test.setup() is deprecated and will be removed in a future release. Use test.use({ config: {...} }) instead"),T.use({config:i})},use(i){const{config:e,...t}=i;return Ue({...t,_useConfig:e})},afterEach(i){return se(async({appetizePage:e},t)=>{e&&await ne(e,t)}),se(i)}});const T=j,ie=new WeakMap;async function ne(i,e){if(ie.get(e.fn))return;ie.set(e.fn,!0);const t=i.session,s="fail-output";if(e.status==="failed"||e.status==="timedOut"){if(t){const o=t.actionLogs;await F.default.promises.mkdir(e.outputPath(s));const a=async()=>{try{const h=await t.screenshot("buffer");await e.attach("screenshot",{body:h.data,contentType:"image/png"});const u=e.outputPath(s,"screenshot.png");await F.default.promises.writeFile(u,Buffer.from(h.data))}catch{}},c=async()=>{try{const h=o.map(w=>{if("screenshot"in w){const{screenshot:g,...b}=w;return b}return w});if(!h.length)return;const u=JSON.stringify(h,null,2);await e.attach("actions",{body:u,contentType:"application/json"});const l=e.outputPath(s,"actions.json");await F.default.promises.writeFile(l,u)}catch{}};await Promise.all([a(),c()])}await(async()=>{if(!!_.logHistory.length)try{const o=`${_.logHistory.map(c=>`[${c.method}] ${JSON.stringify(c.data).slice(2,-2)}`).join(` | ||
`)}`;await e.attach("sdk-logs",{body:o,contentType:"application/text"});const a=e.outputPath(s,"sdk-logs.txt");await F.default.promises.writeFile(a,o)}catch{}})()}}Object.defineProperty(p,"expect",{enumerable:!0,get:function(){return v.expect}}),p.test=T,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); | ||
//# sourceMappingURL=index.umd.js.map |
@@ -1,2 +0,1 @@ | ||
/// <reference types="node" /> | ||
import { Page, TestInfo } from '@playwright/test'; | ||
@@ -31,6 +30,2 @@ import type { Action, ElementSelector, PlayActionError, PlayActionOptions, PlayActionResult, RecordedAction } from '../../core/api/recorder'; | ||
rotate(direction: 'left' | 'right'): Promise<"portrait" | "landscape">; | ||
screenshot<T extends 'buffer' | 'base64', Data = T extends 'buffer' ? Buffer : string>(format?: T): Promise<{ | ||
data: Data; | ||
mimeType: string; | ||
}>; | ||
record(): Promise<void>; | ||
@@ -37,0 +32,0 @@ waitForEvent<K extends keyof SessionEvents>(event: K, options?: WaitForEventOptionsOrPredicate<SessionEvents[K]>): Promise<SessionEvents[K]>; |
{ | ||
"name": "@appetize/playwright", | ||
"version": "1.1.0", | ||
"version": "1.1.2", | ||
"description": "Test your mobile apps on Appetize.io with Playwright", | ||
@@ -5,0 +5,0 @@ "files": [ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
591446
4432