Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@appetize/playwright

Package Overview
Dependencies
Maintainers
0
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@appetize/playwright - npm Package Compare versions

Comparing version 1.4.0-beta.1 to 1.4.0

2

dist/core/api/types/recorder/internal.d.ts

@@ -75,3 +75,3 @@ import { StrictUnion } from '../../../util';

export interface PlayActionResult<A extends Action = Action> {
playback: {
playback?: {
id?: string;

@@ -78,0 +78,0 @@ action: A;

@@ -20,3 +20,3 @@ import { AppetizeApp } from '../api/types/app';

logger?: Logger;
config?: UserSessionConfig;
config?: SessionConfig;
});

@@ -23,0 +23,0 @@ protected init(args?: {

@@ -167,4 +167,2 @@ import { LiteralUnion, OmitUnion } from '../../core/util';

enableAdb?: boolean;
publicKey?: string;
buildId?: string;
grantPermissions?: boolean;

@@ -201,2 +199,3 @@ hidePasswords?: boolean;

publicKey?: string;
buildId?: string;
}

@@ -203,0 +202,0 @@ export interface NetworkRequest {

import { ClientSocketMapper } from '../api/mappers/client-socket';
import { HeadfulClient } from '../client/headful-client';
import { SessionConfig, UserSessionConfig } from '../session';
import { MockSession } from './mock-session';
import { MockSocket } from './mock-socket';
import { UserSessionConfig } from '../session';
export declare class MockHeadfulClient extends HeadfulClient<any, any, any> {
export declare class MockHeadfulClient extends HeadfulClient<any, any, MockSession> {
ready: boolean;

@@ -13,2 +14,3 @@ socket: Omit<ClientSocketMapper, 'socket'> & {

});
protected createSession(config: SessionConfig): MockSession;
}
import { SessionSocketMapper } from '../api/mappers/session-socket';
import { AppetizeApp } from '../api/types/app';
import { DeviceInfo } from '../client';

@@ -9,6 +10,8 @@ import { Session, SessionConfig } from '../session';

};
constructor({ config, device, }: {
constructor({ config, device, app, }: {
config: SessionConfig;
device: DeviceInfo;
app?: AppetizeApp;
});
waitUntilReady(): Promise<void>;
}

@@ -1,7 +0,7 @@

var Se=(d,g,A)=>{if(!g.has(d))throw TypeError("Cannot "+A)};var F=(d,g,A)=>(Se(d,g,"read from private field"),A?A.call(d):g.get(d)),Z=(d,g,A)=>{if(g.has(d))throw TypeError("Cannot add the same private member more than once");g instanceof WeakSet?g.add(d):g.set(d,A)},ee=(d,g,A,K)=>(Se(d,g,"write to private field"),K?K.call(d,A):g.set(d,A),A);(function(d,g){typeof exports=="object"&&typeof module!="undefined"?g(exports,require("@playwright/test"),require("events"),require("fs"),require("jmuxer"),require("stream"),require("os"),require("path")):typeof define=="function"&&define.amd?define(["exports","@playwright/test","events","fs","jmuxer","stream","os","path"],g):(d=typeof globalThis!="undefined"?globalThis:d||self,g(d.playwright={},d.test$1,d.events,d.fs,d.JMuxer,d.stream,d.os,d.path))})(this,function(d,g,A,K,xe,Ee,Ae,ve){var I,$;"use strict";function j(r){return r&&typeof r=="object"&&"default"in r?r:{default:r}}var v=j(K),ke=j(xe),Te=j(Ae),C=j(ve);g.expect.extend({toHaveElement:async(r,e,t={})=>{try{const s=await r.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}}}});async function Pe(r,{retries:e=3,timeout:t=1e3,predicate:s=()=>!0}){for(let i=1;i<=e;i++)try{return await r()}catch(o){if(i===e||!s(o,i))throw o;await new Promise(a=>setTimeout(a,t))}throw null}function Ie(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{const e=Math.random()*16|0;return(r==="x"?e:e&3|8).toString(16)})}function Fe(r){return Object.entries(r).map(([e,t])=>typeof t!="undefined"?`${e}=${encodeURIComponent(t)}`:"").join("&")}function Ce(){let r,e,t,s;return{promise:new Promise((o,a)=>{t=n=>{r=n,o(n)},s=n=>{r=n,a(n)}}),resolve:t,reject:s,resolved:r,rejected:e}}function T(r){return Array.isArray(r)?r.map(T).filter(e=>e!=null):typeof r=="object"&&r!==null?Object.entries(r).reduce((e,[t,s])=>{const i=T(s);return i!=null&&(e[t]=i),e},{}):r}function Re(r){const[e,t,s]=r.split(".");return{major:e?parseInt(e):0,minor:t?parseInt(t):0,patch:s?parseInt(s):0}}class V{constructor(){this.log=this.createLogFn("log"),this.warn=this.createLogFn("warn"),this.error=this.createLogFn("error"),this.debug=this.createLogFn("log")}createLogFn(e){const t=new Set,s="[Appetize]",i=Function.prototype.bind.call(console[e],console,s);return i.once=o=>{if(!t.has(o))return t.add(o),i.call(console,o)},i}}class D extends A.EventEmitter{constructor(){super(),this.on("error",()=>{})}}function te(r,e){if("captureStackTrace"in Error)Error.captureStackTrace(r,e);else{const t=new Error;Object.defineProperty(r,"stack",{configurable:!0,get(){const{stack:s}=t;return Object.defineProperty(this,"stack",{value:s}),s}})}}async function f(r,e){r instanceof S&&te(r,e)}class S extends Error{constructor(e){super(e),this.name="Error",this.isOperational=!0,te(this,this.constructor)}}class O extends S{constructor(e,t){super(t!=null?t:e.message),this.errorId=e.errorId,this.playback=e.playback}}class $e extends O{constructor(e){super(e,`No element found for selector
${JSON.stringify(e.playback.action.element,null,2)}`)}}class De extends O{constructor(e){super(e,`Action requires 1 unique element but the selector returned ${e.matchedElements.length}. Provide a \`matchIndex\` to pick an element below or add additional attributes to your selector.
var be=(d,g,A)=>{if(!g.has(d))throw TypeError("Cannot "+A)};var F=(d,g,A)=>(be(d,g,"read from private field"),A?A.call(d):g.get(d)),Z=(d,g,A)=>{if(g.has(d))throw TypeError("Cannot add the same private member more than once");g instanceof WeakSet?g.add(d):g.set(d,A)},ee=(d,g,A,K)=>(be(d,g,"write to private field"),K?K.call(d,A):g.set(d,A),A);(function(d,g){typeof exports=="object"&&typeof module!="undefined"?g(exports,require("@playwright/test"),require("events"),require("fs"),require("jmuxer"),require("stream"),require("os"),require("path")):typeof define=="function"&&define.amd?define(["exports","@playwright/test","events","fs","jmuxer","stream","os","path"],g):(d=typeof globalThis!="undefined"?globalThis:d||self,g(d.playwright={},d.test$1,d.events,d.fs,d.JMuxer,d.stream,d.os,d.path))})(this,function(d,g,A,K,Se,xe,Ee,Ae){var I,$;"use strict";function j(n){return n&&typeof n=="object"&&"default"in n?n:{default:n}}var v=j(K),ve=j(Se),ke=j(Ee),C=j(Ae);g.expect.extend({toHaveElement:async(n,e,t={})=>{try{const s=await n.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}}}});async function Te(n,{retries:e=3,timeout:t=1e3,predicate:s=()=>!0}){for(let i=1;i<=e;i++)try{return await n()}catch(o){if(i===e||!s(o,i))throw o;await new Promise(a=>setTimeout(a,t))}throw null}function Pe(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,n=>{const e=Math.random()*16|0;return(n==="x"?e:e&3|8).toString(16)})}function Ie(n){return Object.entries(n).map(([e,t])=>typeof t!="undefined"?`${e}=${encodeURIComponent(t)}`:"").join("&")}function Fe(){let n,e,t,s;return{promise:new Promise((o,a)=>{t=r=>{n=r,o(r)},s=r=>{n=r,a(r)}}),resolve:t,reject:s,resolved:n,rejected:e}}function T(n){return Array.isArray(n)?n.map(T).filter(e=>e!=null):typeof n=="object"&&n!==null?Object.entries(n).reduce((e,[t,s])=>{const i=T(s);return i!=null&&(e[t]=i),e},{}):n}function Ce(n){const[e,t,s]=n.split(".");return{major:e?parseInt(e):0,minor:t?parseInt(t):0,patch:s?parseInt(s):0}}class V{constructor(){this.log=this.createLogFn("log"),this.warn=this.createLogFn("warn"),this.error=this.createLogFn("error"),this.debug=this.createLogFn("log")}createLogFn(e){const t=new Set,s="[Appetize]",i=Function.prototype.bind.call(console[e],console,s);return i.once=o=>{if(!t.has(o))return t.add(o),i.call(console,o)},i}}class D extends A.EventEmitter{constructor(){super(),this.on("error",()=>{})}}function te(n,e){if("captureStackTrace"in Error)Error.captureStackTrace(n,e);else{const t=new Error;Object.defineProperty(n,"stack",{configurable:!0,get(){const{stack:s}=t;return Object.defineProperty(this,"stack",{value:s}),s}})}}async function f(n,e){n instanceof x&&te(n,e)}class x extends Error{constructor(e){super(e),this.name="Error",this.isOperational=!0,te(this,this.constructor)}}class O extends x{constructor(e,t){super(t!=null?t:e.message),this.errorId=e.errorId,this.playback=e.playback}}class Re extends O{constructor(e){super(e,`No element found for selector
${JSON.stringify(e.playback.action.element,null,2)}`)}}class $e extends O{constructor(e){super(e,`Action requires 1 unique element but the selector returned ${e.matchedElements.length}. Provide a \`matchIndex\` to pick an element below or add additional attributes to your selector.
${_e(e.matchedElements)}`)}}class Me extends O{constructor(e){let t=e.message;if(e.message.match("outside the screen bounds")){const{action:s}=e.playback;"localPosition"in s&&s.localPosition?t=`localPosition (${s.localPosition.x}, ${s.localPosition.y}) for the element evaluates to a coordinate outside of screen bounds.`:t="Element is outside of screen bounds."}super(e,t)}}class se extends O{constructor(e){super(e,`An internal error has occurred for the action:
${JSON.stringify(e.playback.action,null,2)}`)}}class M extends S{}class ie extends S{constructor(e,t){super(t),this.playback=e}}class z extends S{constructor(e){super(`App Recorder must be enabled to use ${e}. Please set "record" to true in the config.`)}}function _e(r){const t=r.slice(0,5),s=r.length>5;return`${t.map((o,a)=>`// ${a}
${Me(e.matchedElements)}`)}}class De extends O{constructor(e){let t=e.message;if(e.message.match("outside the screen bounds")){const{action:s}=e.playback;"localPosition"in s&&s.localPosition?t=`localPosition (${s.localPosition.x}, ${s.localPosition.y}) for the element evaluates to a coordinate outside of screen bounds.`:t="Element is outside of screen bounds."}super(e,t)}}class se extends O{constructor(e){super(e,`An internal error has occurred for the action:
${JSON.stringify(e.playback.action,null,2)}`)}}class M extends x{}class ie extends x{constructor(e,t){super(t),this.playback=e}}class z extends x{constructor(e){super(`App Recorder must be enabled to use ${e}. Please set "record" to true in the config.`)}}function Me(n){const t=n.slice(0,5),s=n.length>5;return`${t.map((o,a)=>`// ${a}
${JSON.stringify(o,null,2)}`).join(`

@@ -11,12 +11,12 @@

...and ${r.length-5} more`:""}`}class k{static isValidElementSelector(e){if(typeof e!="object"||Array.isArray(e))throw new Error("Element must be an object");const t=Object.keys(e),i=Oe(t,["text","accessibilityIdentifier","accessibilityLabel","resource-id","content-desc","class","baseClass"]);if(i.length>0){const o=i.map(a=>`'${a}'`).join(", ");throw new Error(`Element has invalid properties: ${o}. Did you mean to put these under 'attributes'?`)}return e}static isCoordinatesWithinBounds(e,t){return!(e.x<0||e.x>t.width||e.y<0||e.y>t.height)}static isPositionWithinBounds(e){const t=x.toPositionValue(e.x),s=x.toPositionValue(e.y);return!(t<0||t>1||s<0||s>1)}static isValidNumber(e){return!(typeof e!="number"||isNaN(e))}}class x{static toBoolean(e){return e===1}static toNumber(e){return typeof e=="number"?e:typeof e=="boolean"||e===void 0?e?1:0:e==="inf"?1/0:e==="-inf"?-1/0:parseFloat(e)}static toObjCNumber(e){return e===1/0?"inf":e===-1/0?"-inf":e}static toPositionValue(e){if(typeof e=="string"){if(e.endsWith("%"))return parseInt(e,10)/100;throw new Error(`Invalid position value: ${e}. Must be a number between 0 and 1, or a string ending with %`)}return e}}function Oe(r,e){return r.filter(t=>e.includes(t))}class ne{constructor({platform:e,screen:t}){this.platform=e,this.screen=t}pixelToDip(e){return e/(this.screen.devicePixelRatio||1)}dipToPixel(e){return e*(this.screen.devicePixelRatio||1)}toInternal(e){const{attributes:t,bounds:s,...i}=e,o=()=>{if(s){const{x:n,y:c,width:h,height:u}=s;return this.platform==="android"?{x:this.dipToPixel(n),y:this.dipToPixel(c),width:this.dipToPixel(h),height:this.dipToPixel(u)}:{x:x.toObjCNumber(n),y:x.toObjCNumber(c),width:x.toObjCNumber(h),height:x.toObjCNumber(u)}}},a=()=>{if(t)return Object.keys(t).reduce((n,c)=>{if(this.platform==="ios")switch(c){case"userInteractionEnabled":case"isHidden":return{...n,[c]:t[c]?"1":"0"}}else this.platform;return{...n,[c]:t[c]}},{})};return T({...i,bounds:o(),attributes:a(),accessibilityElements:void 0})}toPublic(e){const{attributes:t,bounds:s,accessibilityElements:i,...o}=e,a=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:x.toNumber(h.x),y:x.toNumber(h.y),width:x.toNumber(h.width),height:x.toNumber(h.height)},n=h=>Object.keys(h).reduce((u,p)=>{switch(p){case"userInteractionEnabled":case"isHidden":return{...u,[p]:h[p]==="1"};default:return{...u,[p]:h[p]}}},{}),c=h=>h.map(u=>{const{accessibilityFrame:p}=u;return{...n(u),accessibilityFrame:p?a(p):void 0}});return T({...o,bounds:s?a(s):void 0,attributes:t?n(t):void 0,accessibilityElements:i?c(i):void 0})}}class Ne{constructor({platform:e,screen:t}){this.platform=e,this.screen=t,this.elementMapper=new ne({platform:e,screen:t})}pixelToDip(e){return e/(this.screen.devicePixelRatio||1)}dipToPixel(e){return e*(this.screen.devicePixelRatio||1)}getCoordinates(e,t){const s=x.toPositionValue(e.x),i=x.toPositionValue(e.y);return{x:s*t.width,y:i*t.height}}getPosition(e,t){return{x:e.x/t.width,y:e.y/t.height}}toInternalKey(e){switch(e){case"HOME":return"home";case"VOLUME_UP":return"volumeUp";case"VOLUME_DOWN":return"volumeDown"}return e}toPublicKey(e){switch(e){case"home":return"HOME";case"volumeUp":return"VOLUME_UP";case"volumeDown":return"VOLUME_DOWN"}return e}toInternal(e){return T((()=>{e=T(e);let s,i,o;if("element"in e&&e.element&&(s=this.elementMapper.toInternal(e.element)),"position"in e&&e.position){const a=x.toPositionValue(e.position.x),n=x.toPositionValue(e.position.y);if(!k.isValidNumber(a)||!k.isValidNumber(n))throw new S(`Invalid position: (${e.position.x}, ${e.position.y}). Values must be a number or a percentage`);if(!k.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"?i=this.getCoordinates(e.position,{width:this.dipToPixel(this.screen.width)-1,height:this.dipToPixel(this.screen.height)-1}):i=this.getCoordinates(e.position,{width:this.screen.width-1,height:this.screen.height-1})}else if("coordinates"in e&&e.coordinates){if(!k.isValidNumber(e.coordinates.x)||!k.isValidNumber(e.coordinates.y))throw new S(`Invalid coordinates: (${e.coordinates.x}, ${e.coordinates.y}). Values must be a number`);if(!k.isCoordinatesWithinBounds(e.coordinates,{width:this.screen.width-1,height:this.screen.height-1}))throw new S(`Invalid coordinates: (${e.coordinates.x}, ${e.coordinates.y}) exceed screen bounds (${this.screen.width-1}, ${this.screen.height-1})`);this.platform==="android"?i={x:this.dipToPixel(e.coordinates.x),y:this.dipToPixel(e.coordinates.y)}:i=e.coordinates}if("localPosition"in e&&e.localPosition){const a=x.toPositionValue(e.localPosition.x),n=x.toPositionValue(e.localPosition.y);if(!k.isValidNumber(a)||!k.isValidNumber(n))throw new S(`Invalid localPosition: (${e.localPosition.x}, ${e.localPosition.y}). Values must be a number or a percentage`);o={x:a,y:n}}else s&&(o={x:.5,y:.5});if("duration"in e&&e.duration&&!k.isValidNumber(e.duration))throw new S(`Invalid duration: ${e.duration}. Value must be a number`);switch(e.type){case"tap":{const{position:a,...n}=e;return{...n,element:s,localPosition:o,coordinates:i}}case"swipe":{const{position:a,...n}=e;return{...n,element:s,localPosition:o,coordinates:i,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 a=this.toInternalKey(e.key),n=this.toInternalKey(e.character);return{...e,key:a,character:n,shiftKey:this.platform==="ios"?x.toNumber(e.shiftKey):e.shiftKey}}case"findElements":return{...e,element:s}}return e})())}toPublic(e){return T((()=>{let s,i,o,a="localPosition"in e?e.localPosition:void 0;switch("coordinates"in e&&e.coordinates&&(i={x:this.pixelToDip(e.coordinates.x),y:this.pixelToDip(e.coordinates.y)},o=this.getPosition(i,{width:this.screen.width-1,height:this.screen.height-1})),"element"in e&&e.element&&(s=this.elementMapper.toPublic(e.element),i&&s.bounds&&(a=this.getPosition({x:i.x-s.bounds.x,y:i.y-s.bounds.y},{width:s.bounds.width,height:s.bounds.height}))),e.type){case"tap":return{...e,coordinates:i,element:s,position:o,localPosition:a};case"swipe":return{...e,coordinates:i,element:s,position:o,localPosition:a,moves:e.moves.map(n=>{const{x:c,y:h}=this.getPosition({x:this.pixelToDip(n.x),y:this.pixelToDip(n.y)},{width:this.screen.width-1,height:this.screen.height-1});return{x:c,y:h,t:n.t}})};case"keypress":{const n=this.toPublicKey(e.key),c=this.toPublicKey(e.character);return{...e,key:n,character:c,shiftKey:typeof e.shiftKey=="number"?x.toBoolean(e.shiftKey):Boolean(e.shiftKey)}}case"findElements":return{...e,element:s}}return e})())}}class re{constructor({platform:e,screen:t,app:s}){this.app=s,this.platform=e,this.screen=t,this.actionMapper=new Ne({platform:e,screen:t}),this.elementMapper=new ne({platform:e,screen:t})}toInternal(e,t){switch(e){case"playAction":{const s=t,o=t.__noMap__?t.action:this.actionMapper.toInternal(s.action);return{type:e,value:{...s,action:o}}}}return{type:e,value:t}}toPublic(e,t){var s,i,o,a;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"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"concurrentQueue":return{type:"queue",value:{type:"concurrent",name:t.name,position:t.position}};case"queue":return{type:"queue",value:{type:"session",position:t.position}};case"orientationChanged":return{type:e,value:t};case"chromeDevToolsUrl":return{type:"networkInspectorUrl",value:t};case"recordedAction":return{type:"action",value:this.actionMapper.toPublic(t)};case"playbackFoundAndSent":{const n=t;return{type:"playbackFoundAndSent",value:{...n,playback:{...n.playback,action:n.playback.action?this.actionMapper.toPublic(n.playback.action):void 0},matchedElements:(s=n.matchedElements)==null?void 0:s.map(c=>{if(c)return this.elementMapper.toPublic(c)})}}}case"playbackError":{const n=t;return{type:"playbackError",value:{...n,playback:{...n.playback,action:n.playback.action?this.actionMapper.toPublic(n.playback.action):void 0},matchedElements:(i=n.matchedElements)==null?void 0:i.map(c=>{if(c)return this.elementMapper.toPublic(c)})}}}case"uiDump":{const n=(o=t.ui)!=null?o:t.result,c=t.springboard,h=p=>{var y;return{...this.elementMapper.toPublic(p),children:(y=p.children)==null?void 0:y.map(h)}},u=[];return n&&(this.platform==="ios"?u.push({type:"app",appId:(a=this.app)==null?void 0:a.bundle,children:n.map(h)}):u.push({type:"app",children:n.map(h)})),c&&u.push({type:"app",appId:"com.apple.springboard",children:c.map(h)}),{type:"uiDump",value:u}}case"deleteEvent":return null}return{type:e,value:t}}}class qe{toInternal(e,t){return{type:e,value:t}}toPublic(e,t){switch(e){case"userError":return{type:"error",value:t};case"concurrentQueue":return{type:"queue",value:{type:"concurrent",name:t.name,position:t.position}};case"queue":return{type:"queue",value:{type:"session",position:t.position}};case"deviceInfo":case"sessionInfo":case"sessionRequested":return{type:e,value:t}}return{type:e,value:t}}}class Ue extends D{constructor({socket:e}){super(),this.eventMapper=new qe,this._socket=e,e.on("*",({type:t,value:s})=>{const i=this.mapEmit(t,s);i===null||(this.emit(i.type,i.value),this.emit("*",i))})}mapEmit(e,t){return this.eventMapper.toPublic(e,t)}mapSend(e,t){return this.eventMapper.toInternal(e,t)}send(e,t){const s=this.mapSend(e,t);return this._socket.send(s.type,s.value)}disconnect(){return this._socket.disconnect()}}class Le extends D{constructor({socket:e,logger:t=new V}){super(),this.logger=t,this.socket=new Ue({socket:e}),this.socket.on("*",({type:s,value:i})=>{s!=="newSession"&&(this.emit(s,i),this.emit("*",{type:s,value:i}))}),this.socket.on("newSession",()=>{this.queue&&(this.emit("queueEnd"),this.queue=void 0)}),this.on("queue",s=>{this.queue=s})}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 i=()=>{s(new Error("Session disconnected before it was ready"))},o=n=>{s(new Error(`Session failed to start - ${typeof n.message=="object"?JSON.stringify(n.message):n.message}`))},a=n=>{var c;s(new Error(`Session failed to start - ${(c=n==null?void 0:n.message)!=null?c:"Unknown error"}`))};try{this.on("error",a),e.on("disconnect",i),e.on("error",o),await e.waitUntilReady()}catch(n){s(n)}finally{this.off("error",a),e.off("disconnect",i),e.off("error",o)}t(e)})}}async function H(r,e=5e3){const t=Date.now();let s=!1;for(;;)try{return await r(o=>{if(o)throw s=!0,o})}catch(i){if(await new Promise(o=>setTimeout(o,100)),s||e!==null&&Date.now()-t>e)throw i}}async function J(r){return new Promise(e=>setTimeout(e,r))}async function _(r,e,t){const s=typeof t=="function"?{}:t,i=typeof t=="function"?t:t==null?void 0:t.predicate,o=typeof(s==null?void 0:s.timeout)!="undefined"?s.timeout:1e4;return new Promise((a,n)=>{const c=h=>{(!i||i(h))&&(r.off(e,c),a(h))};r.on(e,c),o!==null&&setTimeout(()=>{r.off(e,c),n(new M(`Timeout ${o}ms exceeded while waiting for event "${e}"`))},o)})}function oe(r){return r?{...T(r),device:r.deviceType||r.device}:{}}class Ke extends Le{constructor({socket:e,window:t,logger:s=new V,config:i,autoInit:o=!0}){super({socket:e,logger:s}),this.ready=!1,this.isRequestingSession=!1,this._lastSetConfigCallId=null,this.window=t,i&&this.assignConfig(i),this.window.on("*",async({type:a,value:n})=>{if(this.ready)switch(a){case"app":this.app=n,this.emit(a,n);break;case"deviceInfo":this.device=n,this.emit(a,n);break;case"config":this.assignConfig(n);break}}),this.window.on("reinit",()=>{this.ready=!1,this.session=void 0,this.init({isReinit:!0})}),this.socket.on("*",async({type:a,value:n})=>{if(this.ready)switch(a){case"newSession":try{this.isRequestingSession=!1,this.session=this.createSession(this._config,{path:n.path,token:n.sessionToken}),await this.waitForSessionStart(this.session),this.emit("session",this.session)}catch(c){this.session=void 0,this.emit("sessionError",c)}}}),o!==!1&&this.init()}async init(e={isReinit:!1}){await this.window.waitUntilReady();const t=async()=>{if(e.isReinit){const o=this._config,a=await this.setConfig({});return this.setConfig({record:!0,...o,...a})}else return this.setConfig({record:!0,...this._config})},[s,i]=await Promise.all([this.window.postMessage({type:"getApp"},!0),this.window.postMessage({type:"getDeviceInfo"},!0),t()]);this.app=s,this.device=i,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){const t=this.isRequestingSession,s=()=>this.isRequestingSession===!1;this.isRequestingSession=!0;try{try{await this.waitUntilReady()}catch(i){const o=i instanceof Error?i.message:i;throw new Error(`Failed to start session. ${o}`)}if(s()||(this.session?await this.session.end():t&&(await this.cancelSessionRequest(),this.isRequestingSession=!0)),s()||await this.setConfig(e!=null?e:{}),s())throw new Error("Session request was cancelled");{const[i]=await Promise.all([new Promise((o,a)=>{const n=h=>{this.off("session",n),this.off("sessionError",c),this.off("error",c),o(h)},c=h=>{this.off("session",n),this.off("sessionError",c),this.off("error",c),h instanceof Error?a(h):h&&typeof h.message=="string"?a(new Error(`Session failed to start - ${h.message}`)):a(h)};this.on("session",n),this.on("sessionError",c),this.on("error",c)}),this.window.postMessage({type:"requestSession"},!0)]);return i}}finally{this.isRequestingSession=!1}}async endSession(){this.session?await this.session.end():this.isRequestingSession&&await this.cancelSessionRequest()}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({buildId:e,publicKey:t,...s}){this._lastSetConfigCallId=Math.random().toString(36);const i=this._lastSetConfigCallId;if(!e&&t&&(e=t),e){const a=await this.window.postMessage({type:"loadApp",value:e},!0);if(a&&"error"in a){if(a.error==="cancelled")return this._config;throw new Error(a.error)}if(i!==this._lastSetConfigCallId)return this._config}const o=await this.window.postMessage({type:"setConfig",value:this.validateConfig({...s,...e?{publicKey:e}:{}})},!0);return this.assignConfig({buildId:e,publicKey:t,...o})}assignConfig(e){var t,s,i;if(e.autoplay===!0&&this.logger.warn.once("autoplay=true may cause the session to start before the SDK is ready. You should start the session programmatically using client.startSession() instead."),e.buildId||e.publicKey){const o=(t=e.buildId)!=null?t:e.publicKey;this._config=oe({...e,buildId:o,publicKey:o})}else this._config=oe({buildId:(s=this._config)==null?void 0:s.buildId,publicKey:(i=this._config)==null?void 0:i.publicKey,...e});return this._config}validateConfig(e){return e}async cancelSessionRequest(){this.isRequestingSession&&(this.isRequestingSession=!1,await this.window.postMessage("endSession"),this.emit("sessionEnded"))}createSession(e,t){throw new Error("Not implemented")}}class je extends V{constructor(){super(...arguments),this.logHistory=[],this.logLevel=process.env.CI==="true"?"warnings-errors":"verbose",this.log=this.createPlaywrightLogFn("log",()=>this.logLevel==="verbose"),this.warn=this.createPlaywrightLogFn("warn",()=>this.logLevel==="verbose"||this.logLevel==="warnings-errors"),this.error=this.createPlaywrightLogFn("error",()=>this.logLevel==="verbose"||this.logLevel==="warnings-errors"),this.debug=this.createPlaywrightLogFn("debug",()=>this.logLevel==="verbose"),this.clearLogHistory=()=>{this.logHistory=[]}}createPlaywrightLogFn(e,t){const s=new Set,i="[Appetize]",o=(...a)=>{this.logHistory.push({method:e,data:a}),t()&&console[e](i,...a)};return o.once=a=>{if(!s.has(a))return s.add(a),o.call(console,a)},o}}const b=new je;function Ve(r){const e=r.length;let t="";for(let s=0;s<e;s+=65535){let i=65535;s+65535>e&&(i=e-s),t+=String.fromCharCode.apply(null,r.subarray(s,s+i))}return t}function ze(r,e){if(typeof window=="undefined"&&typeof Buffer!="undefined"){const t=Buffer.from(r).toString("base64");return`data:${e};base64,`+t}else{const t=Ve(r),s=btoa(t);return`data:${e};base64,`+s}}class Je{constructor({duration:e,stepDuration:t}){this.moves=[],this.duration=e,this.stepDuration=t!=null?t:16,this.moves=[{x:0,y:0}]}to(e,t){if(typeof e!="string"||typeof t!="string")throw new S('x and y must be strings and in percentages (e.g. "50%")');if(!e.endsWith("%")||!t.endsWith("%"))throw new S('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 n;const e=this.stepDuration,t=(n=this.duration)!=null?n:Math.max(500,e*(this.moves.length-1)),s=Math.floor(t/e),i=Math.floor(s/(this.moves.length-1)),o=[];let a=0;if(i===0){const c=(this.moves.length-1)*e;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],p=c===this.moves.length-2;for(let y=0;y<=i;y++){if(!p&&y===i)continue;const E=y/i,l=h.x+E*(u.x-h.x),w=h.y+E*(u.y-h.y),m=((c*i+y)*e+a)/1e3;o.push({x:l,y:w,t:m}),y===0&&h.wait&&(o.push({x:l,y:w,t:m+h.wait/1e3}),a+=h.wait)}if(c===this.moves.length-2&&u.wait){const y=o[o.length-1];o.push({x:y.x,y:y.y,t:y.t+u.wait/1e3})}}return o}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 We extends D{constructor({socket:e,platform:t,screen:s,app:i}){super(),this._socket=e,this.platform=t,this.screen=s,this.app=i,e.on("*",({type:o,value:a})=>{const n=this.mapEmit(o,a);n===null||(this.handleEvent(n.type,n.value),this.emit(n.type,n.value),this.emit("*",n))})}send(e,t){const s=this.mapSend(e,t);return this._socket.send(s.type,s.value)}disconnect(){return this._socket.disconnect()}handleEvent(e,t){switch(e){case"app":this.app=t;break;case"deviceInfo":{const s=t;s!=null&&s.screen&&(this.screen=s.screen);break}case"config":{const s=t;s.platform&&(this.platform=s.platform);break}}}mapEmit(e,t){return new re({platform:this.platform,screen:this.screen,app:this.app}).toPublic(e,t)}mapSend(e,t){return new re({platform:this.platform,screen:this.screen,app:this.app}).toInternal(e,t)}}class Be extends D{constructor({socket:t,config:s,path:i,token:o,app:a,device:n,logger:c=new V}){super();Z(this,I,void 0);Z(this,$,void 0);this.isEndingManually=!1,this.countdownWarning=!1,this.ready=!1,this._waitForAnimationsPromises=new Set,this.config=s,this.socket=new We({socket:t,app:a,screen:n.screen,platform:s.platform}),this.device=n,this.app=a,this.path=i,this.token=o,this.logger=c;const h=({type:u,value:p})=>{switch(u){case"ready":this.ready=!0;break;case"adbOverTcp":{ee(this,I,{...p,command:He(p)});break}case"networkInspectorUrl":ee(this,$,p);break;case"countdownWarning":this.countdownWarning=!0;break;case"timeoutReset":this.countdownWarning=!1;break;case"deviceInfo":this.device=p;break;case"disconnect":this.emit("end"),this.emit("*",{type:"end"});break}this.emit(u,p),this.emit("*",{type:u,value:p})};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 o=>new Promise(a=>{const n=setInterval(()=>{o()&&a(void 0)},10);setTimeout(()=>{clearInterval(n),a(void 0)},3e3)}),i=()=>{t=!1};this.socket.once("disconnect",i);try{await H(o=>{if(!this.ready){if(t)throw new M("Timed out after 180s waiting for session to be ready");o(new Error("Session disconnected"))}},18e4)}finally{this.socket.off("disconnect",i)}await Promise.all([this.config.proxy==="intercept"?s(()=>Boolean(F(this,$))):Promise.resolve(),this.config.enableAdb?s(()=>Boolean(F(this,I))):Promise.resolve()])}async waitForEvent(t,s){try{return await _(this,t,s)}catch(i){throw f(i,this.waitForEvent),i}}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'),F(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"),F(this,I))return F(this,I)}async rotate(t){try{if(this.config.platform==="android"&&this.config.osVersion&&Re(this.config.osVersion).major===14)throw new Error("Rotation is not supported for devices running Android 14");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 f(s,this.rotate),s}}async screenshot(t="buffer"){var s;try{this.socket.send("getScreenshot",{});const i=await _(this.socket,"screenshot",{timeout:6e4});if(!i.success)throw new S((s=i.error)!=null?s:"Screenshot failed");return{data:t==="buffer"?(n=>typeof window=="undefined"?Buffer.from(n):n)(i.data):ze(new Uint8Array(i.data),i.mimeType),mimeType:i.mimeType}}catch(i){throw f(i,this.screenshot),i}}async heartbeat(){try{return await this.socket.send("heartbeat")}catch(t){throw f(t,this.heartbeat),t}}async type(t){try{await J(1e3);const s=await this.playAction({type:"typeText",text:t});return await J(500),s}catch(s){throw f(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(i){throw f(i,this.keypress),i}}async setLanguage(t){try{return this.config.language=t,await this.socket.send("setLanguage",{language:t,timeStamp:Date.now()})}catch(s){throw f(s,this.setLanguage),s}}async setLocation(t,s){try{if(typeof t!="number"||typeof s!="number")throw new S("setLocation requires latitude and longitude to be numbers");const i=[t,s];return this.config.location=i,await this.socket.send("setLocation",{location:i,timeStamp:Date.now()})}catch(i){throw f(i,this.setLocation),i}}async openUrl(t){try{return await this.socket.send("openUrl",{url:t,timeStamp:Date.now()})}catch(s){throw f(s,this.openUrl),s}}async launchApp(t){try{return await this.socket.send("launchApp",{appId:t,timeStamp:Date.now()})}catch(s){throw f(s,this.launchApp),s}}async shake(){try{return await this.socket.send("shakeDevice")}catch(t){throw f(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 f(t,this.toggleSoftKeyboard),t}}async biometry({match:t}){try{return await this.socket.send(t?"biometryMatch":"biometryNonMatch")}catch(s){throw f(s,this.biometry),s}}async biometryEnrollment(t){try{if(this.config.platform!=="ios")throw new Error("biometryEnrollment is only available on iOS devices");return await this.socket.send("biometryEnrollment",{isEnrolled:t})}catch(s){throw f(s,this.biometryEnrollment),s}}async allowInteractions(t){try{return await this.socket.send(t?"enableInteractions":"disableInteractions")}catch(s){throw f(s,this.allowInteractions),s}}async restartApp(){try{this.isStandalone?this.logger.warn("restartApp has no effect on a Standalone"):(this.socket.send("restartApp"),await this.waitForEvent("appLaunch",{timeout:6e4}))}catch(t){throw f(t,this.restartApp),t}}async reinstallApp(){try{this.isStandalone?this.logger.warn("reinstallApp has no effect on a Standalone"):(this.socket.send("reinstallApp"),await this.waitForEvent("appLaunch",{timeout:6e4}))}catch(t){throw f(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 f(s,this.adbShellCommand),s}}async playAction(t,s={}){const{timeout:i=1e4}=s,o=1e4,a=i+3e4;try{if(!this.config.record)throw new z("playAction()");if(isNaN(i))throw new S(`Invalid timeout value: ${s.timeout}`);if(i<0)throw new S(`Timeout value cannot be negative: ${s.timeout}`);"element"in t&&t.element&&k.isValidElementSelector(t.element);const n={id:Ie(),action:t,options:{...s,timeout:Math.round(Math.min(i,o)/1e3)}};try{return await new Promise((h,u)=>{const p=setTimeout(()=>{y(),u(new ie({id:n.id,action:t,timeout:n.options.timeout},"Timed out waiting for response from device"))},a),y=()=>{this.off("playbackFoundAndSent",E),this.off("playbackError",l),clearTimeout(p)},E=async w=>{var m;((m=w.playback)==null?void 0:m.id)===n.id&&(y(),h(w))},l=async w=>{var m;if(((m=w.playback)==null?void 0:m.id)===n.id)switch(y(),w.errorId){case"internalError":u(new se(w));break;case"notFound":{u(new $e(w));break}case"ambiguousMatch":u(new De(w));break;case"invalidArgument":{u(new Me(w));break}default:u(new O(w));break}};this.on("playbackFoundAndSent",E),this.on("playbackError",l),this.socket.send("playAction",n)})}catch(c){const h=Math.max(0,i-o);if(h>0&&!(c instanceof ie)&&!(c instanceof se))return await this.playAction(t,{...s,timeout:h});throw c}}catch(n){throw f(n,this.playAction),n}}async playActions(t,s={}){try{if(!this.config.record)throw new z("playActions()");const i=[];for(const o of t){const a=await this.playAction(o,s);i.push(a);const n=t[t.indexOf(o)+1];n&&n.type==="keypress"&&o.type==="keypress"||await this.waitForAnimations({timeout:2e3}).catch(()=>{})}return i}catch(i){throw f(i,this.playActions),i}}async getUI({timeout:t=3e4}={}){try{return this.socket.send("dumpUi"),await _(this,"uiDump",{timeout:t})}catch(s){throw f(s,this.getUI),s}}async findElement(t,s){var i;try{return(i=(await this.playAction({type:"findElements",element:t,appId:s==null?void 0:s.appId},s)).matchedElements)==null?void 0:i[0]}catch(o){throw f(o,this.findElement),o}}async findElements(t,s){try{return(await this.playAction({type:"findElements",element:t,appId:s==null?void 0:s.appId},s)).matchedElements}catch(i){throw f(i,this.findElements),i}}async tap(t,s){var i;try{if(!this.config.record)throw new z("tap()");return await this.playAction({type:"tap",...t,duration:((i=t.duration)!=null?i:0)/1e3},s)}catch(o){throw f(o,this.tap),o}}async swipe({duration:t,gesture:s,...i},o){try{if(!this.config.record)throw new z("swipe()");let a;const n=new Je({duration:t,stepDuration:i.stepDuration});if(typeof s=="function")s(n);else switch(s){case"up":n.up();break;case"down":n.down();break;case"left":n.left();break;case"right":n.right();break}if("element"in i)a={type:"swipe",element:i.element,localPosition:i.localPosition,moves:n.build()};else if("position"in i)a={type:"swipe",position:i.position,moves:n.build()};else throw new Error("Either element or position must be specified");return this.playAction(a,o)}catch(a){throw f(a,this.swipe),a}}async waitForAnimations(t={}){try{const{imageThreshold:s=.001,timeout:i=1e4}=t;let o=1e3,a=1;t.imageThresholdDuration&&(o=t.imageThresholdDuration);const{promise:n,resolve:c,reject:h}=Ce(),u=setTimeout(()=>{let E=`Timed out after ${i}ms waiting for animation to end.`;s<a&&(E+=` Waited for imageThreshold of ${s} but lowest was ${Math.round(a*1e4)/1e4}`),h(new M(E))},i);let p;const y=({percentage:E,timestamp:l})=>{E<a&&(a=E),E<=s?(p||(p=l),p&&l-p>=o&&c()):p=void 0};return this.socket.send("enablePixelChangeDetection"),this.socket.on("pixelsChanged",y),this._waitForAnimationsPromises.add(n),await n.finally(()=>{clearTimeout(u),this.socket.off("pixelsChanged",y),this._waitForAnimationsPromises.delete(n),this._waitForAnimationsPromises.size===0&&this.socket.send("disablePixelChangeDetection")})}catch(s){throw f(s,this.waitForAnimations),s}}async getAdbInfo(){return this.logger.warn("getAdbInfo() is deprecated. Please use the `adbConnection` property instead."),Promise.resolve(F(this,I))}async getNetworkInspectorUrl(){return this.logger.warn("getNetworkInspectorUrl() is deprecated. Please use the `networkInspectorUrl` property instead."),Promise.resolve(F(this,$))}async getDeviceInfo(){return this.logger.warn("getDeviceInfo() is deprecated. Please use the `device` property instead."),Promise.resolve(this.device)}get isStandalone(){var t;return(t=this.config.buildId)==null?void 0:t.startsWith("standalone_")}}I=new WeakMap,$=new WeakMap;function He(r){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(!r||!r.forwards[0])return;let t=e;return t=t.replace(/SERVER_PORT/,r.port.toString()),t=t.replace(/USERNAME/,r.user),t=t.replace(/HOSTNAME/,r.hostname),t=t.replace(/FORWARD_DESTINATION/,r.forwards[0].destination),t=t.replace(/FORWARD_PORT/,r.forwards[0].port.toString()),t}async function Ye(r){await r.pause()}function W(r){if(r.character)return r.character;const e=r.key;return B(e)?e:r.shiftKey?e.toUpperCase():e.toLowerCase()}function B(r){return/^[\b\t\r]/.test(r)}class Qe{constructor({testInfo:e,session:t}){this.currentRecord=0,this.session=t,this.testInfo=e}async record(){const e=this.testInfo.file,t=await v.default.promises.readFile(e,"utf8"),i=t.split(`
`).map((o,a)=>({line:o,num:a+1})).slice(this.testInfo.line).filter(({line:o})=>o.includes("session.record()"))[this.currentRecord].num;if(i!==void 0){console.log(`\u{1F534} Recording at line ${i}`);const o=[],a=c=>{Xe(o,c),console.log(ae(c))};this.session.on("action",a),await Ye(this.session.page),await J(2e3),this.session.off("action",a);const n=t.split(`
`).map((c,h)=>{var u,p;if(h===i-1){const y=(p=(u=c.match(/^\s*/))==null?void 0:u[0])!=null?p:0;return`${o.map(l=>ae(l)).reduce((l,w,m)=>`${l}
...and ${n.length-5} more`:""}`}class k{static isValidElementSelector(e){if(typeof e!="object"||Array.isArray(e))throw new Error("Element must be an object");const t=Object.keys(e),i=_e(t,["text","accessibilityIdentifier","accessibilityLabel","resource-id","content-desc","class","baseClass"]);if(i.length>0){const o=i.map(a=>`'${a}'`).join(", ");throw new Error(`Element has invalid properties: ${o}. Did you mean to put these under 'attributes'?`)}return e}static isCoordinatesWithinBounds(e,t){return!(e.x<0||e.x>t.width||e.y<0||e.y>t.height)}static isPositionWithinBounds(e){const t=E.toPositionValue(e.x),s=E.toPositionValue(e.y);return!(t<0||t>1||s<0||s>1)}static isValidNumber(e){return!(typeof e!="number"||isNaN(e))}}class E{static toBoolean(e){return e===1}static toNumber(e){return typeof e=="number"?e:typeof e=="boolean"||e===void 0?e?1:0:e==="inf"?1/0:e==="-inf"?-1/0:parseFloat(e)}static toObjCNumber(e){return e===1/0?"inf":e===-1/0?"-inf":e}static toPositionValue(e){if(typeof e=="string"){if(e.endsWith("%"))return parseInt(e,10)/100;throw new Error(`Invalid position value: ${e}. Must be a number between 0 and 1, or a string ending with %`)}return e}}function _e(n,e){return n.filter(t=>e.includes(t))}class ne{constructor({platform:e,screen:t}){this.platform=e,this.screen=t}pixelToDip(e){return e/(this.screen.devicePixelRatio||1)}dipToPixel(e){return e*(this.screen.devicePixelRatio||1)}toInternal(e){const{attributes:t,bounds:s,...i}=e,o=()=>{if(s){const{x:r,y:c,width:h,height:u}=s;return this.platform==="android"?{x:this.dipToPixel(r),y:this.dipToPixel(c),width:this.dipToPixel(h),height:this.dipToPixel(u)}:{x:E.toObjCNumber(r),y:E.toObjCNumber(c),width:E.toObjCNumber(h),height:E.toObjCNumber(u)}}},a=()=>{if(t)return Object.keys(t).reduce((r,c)=>{if(this.platform==="ios")switch(c){case"userInteractionEnabled":case"isHidden":return{...r,[c]:t[c]?"1":"0"}}else this.platform;return{...r,[c]:t[c]}},{})};return T({...i,bounds:o(),attributes:a(),accessibilityElements:void 0})}toPublic(e){const{attributes:t,bounds:s,accessibilityElements:i,...o}=e,a=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:E.toNumber(h.x),y:E.toNumber(h.y),width:E.toNumber(h.width),height:E.toNumber(h.height)},r=h=>Object.keys(h).reduce((u,p)=>{switch(p){case"userInteractionEnabled":case"isHidden":return{...u,[p]:h[p]==="1"};default:return{...u,[p]:h[p]}}},{}),c=h=>h.map(u=>{const{accessibilityFrame:p}=u;return{...r(u),accessibilityFrame:p?a(p):void 0}});return T({...o,bounds:s?a(s):void 0,attributes:t?r(t):void 0,accessibilityElements:i?c(i):void 0})}}class Oe{constructor({platform:e,screen:t}){this.platform=e,this.screen=t,this.elementMapper=new ne({platform:e,screen:t})}pixelToDip(e){return e/(this.screen.devicePixelRatio||1)}dipToPixel(e){return e*(this.screen.devicePixelRatio||1)}getCoordinates(e,t){const s=E.toPositionValue(e.x),i=E.toPositionValue(e.y);return{x:s*t.width,y:i*t.height}}getPosition(e,t){return{x:e.x/t.width,y:e.y/t.height}}toInternalKey(e){switch(e){case"HOME":return"home";case"VOLUME_UP":return"volumeUp";case"VOLUME_DOWN":return"volumeDown"}return e}toPublicKey(e){switch(e){case"home":return"HOME";case"volumeUp":return"VOLUME_UP";case"volumeDown":return"VOLUME_DOWN"}return e}toInternal(e){return T((()=>{e=T(e);let s,i,o;if("element"in e&&e.element&&(s=this.elementMapper.toInternal(e.element)),"position"in e&&e.position){const a=E.toPositionValue(e.position.x),r=E.toPositionValue(e.position.y);if(!k.isValidNumber(a)||!k.isValidNumber(r))throw new x(`Invalid position: (${e.position.x}, ${e.position.y}). Values must be a number or a percentage`);if(!k.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"?i=this.getCoordinates(e.position,{width:this.dipToPixel(this.screen.width)-1,height:this.dipToPixel(this.screen.height)-1}):i=this.getCoordinates(e.position,{width:this.screen.width-1,height:this.screen.height-1})}else if("coordinates"in e&&e.coordinates){if(!k.isValidNumber(e.coordinates.x)||!k.isValidNumber(e.coordinates.y))throw new x(`Invalid coordinates: (${e.coordinates.x}, ${e.coordinates.y}). Values must be a number`);if(!k.isCoordinatesWithinBounds(e.coordinates,{width:this.screen.width-1,height:this.screen.height-1}))throw new x(`Invalid coordinates: (${e.coordinates.x}, ${e.coordinates.y}) exceed screen bounds (${this.screen.width-1}, ${this.screen.height-1})`);this.platform==="android"?i={x:this.dipToPixel(e.coordinates.x),y:this.dipToPixel(e.coordinates.y)}:i=e.coordinates}if("localPosition"in e&&e.localPosition){const a=E.toPositionValue(e.localPosition.x),r=E.toPositionValue(e.localPosition.y);if(!k.isValidNumber(a)||!k.isValidNumber(r))throw new x(`Invalid localPosition: (${e.localPosition.x}, ${e.localPosition.y}). Values must be a number or a percentage`);o={x:a,y:r}}else s&&(o={x:.5,y:.5});if("duration"in e&&e.duration&&!k.isValidNumber(e.duration))throw new x(`Invalid duration: ${e.duration}. Value must be a number`);switch(e.type){case"tap":{const{position:a,...r}=e;return{...r,element:s,localPosition:o,coordinates:i}}case"swipe":{const{position:a,...r}=e;return{...r,element:s,localPosition:o,coordinates:i,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 a=this.toInternalKey(e.key),r=this.toInternalKey(e.character);return{...e,key:a,character:r,shiftKey:this.platform==="ios"?E.toNumber(e.shiftKey):e.shiftKey}}case"findElements":return{...e,element:s}}return e})())}toPublic(e){return T((()=>{let s,i,o,a="localPosition"in e?e.localPosition:void 0;switch("coordinates"in e&&e.coordinates&&(i={x:this.pixelToDip(e.coordinates.x),y:this.pixelToDip(e.coordinates.y)},o=this.getPosition(i,{width:this.screen.width-1,height:this.screen.height-1})),"element"in e&&e.element&&(s=this.elementMapper.toPublic(e.element),i&&s.bounds&&(a=this.getPosition({x:i.x-s.bounds.x,y:i.y-s.bounds.y},{width:s.bounds.width,height:s.bounds.height}))),e.type){case"tap":return{...e,coordinates:i,element:s,position:o,localPosition:a};case"swipe":return{...e,coordinates:i,element:s,position:o,localPosition:a,moves:e.moves.map(r=>{const{x:c,y:h}=this.getPosition({x:this.pixelToDip(r.x),y:this.pixelToDip(r.y)},{width:this.screen.width-1,height:this.screen.height-1});return{x:c,y:h,t:r.t}})};case"keypress":{const r=this.toPublicKey(e.key),c=this.toPublicKey(e.character);return{...e,key:r,character:c,shiftKey:typeof e.shiftKey=="number"?E.toBoolean(e.shiftKey):Boolean(e.shiftKey)}}case"findElements":return{...e,element:s}}return e})())}}class re{constructor({platform:e,screen:t,app:s}){this.app=s,this.platform=e,this.screen=t,this.actionMapper=new Oe({platform:e,screen:t}),this.elementMapper=new ne({platform:e,screen:t})}toInternal(e,t){switch(e){case"playAction":{const s=t,o=t.__noMap__?t.action:this.actionMapper.toInternal(s.action);return{type:e,value:{...s,action:o}}}}return{type:e,value:t}}toPublic(e,t){var s,i,o,a,r,c;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"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"concurrentQueue":return{type:"queue",value:{type:"concurrent",name:t.name,position:t.position}};case"queue":return{type:"queue",value:{type:"session",position:t.position}};case"orientationChanged":return{type:e,value:t};case"chromeDevToolsUrl":return{type:"networkInspectorUrl",value:t};case"recordedAction":return{type:"action",value:this.actionMapper.toPublic(t)};case"playbackFoundAndSent":{const h=t;return{type:"playbackFoundAndSent",value:{...h,playback:{...h.playback,action:(s=h.playback)!=null&&s.action?this.actionMapper.toPublic(h.playback.action):void 0},matchedElements:(i=h.matchedElements)==null?void 0:i.map(u=>{if(u)return this.elementMapper.toPublic(u)})}}}case"playbackError":{const h=t;return{type:"playbackError",value:{...h,playback:{...h.playback,action:(o=h.playback)!=null&&o.action?this.actionMapper.toPublic(h.playback.action):void 0},matchedElements:(a=h.matchedElements)==null?void 0:a.map(u=>{if(u)return this.elementMapper.toPublic(u)})}}}case"uiDump":{const h=(r=t.ui)!=null?r:t.result,u=t.springboard,p=b=>{var l;return{...this.elementMapper.toPublic(b),children:(l=b.children)==null?void 0:l.map(p)}},y=[];return h&&(this.platform==="ios"?y.push({type:"app",appId:(c=this.app)==null?void 0:c.bundle,children:h.map(p)}):y.push({type:"app",children:h.map(p)})),u&&y.push({type:"app",appId:"com.apple.springboard",children:u.map(p)}),{type:"uiDump",value:y}}case"deleteEvent":return null}return{type:e,value:t}}}class Ne{toInternal(e,t){return{type:e,value:t}}toPublic(e,t){switch(e){case"userError":return{type:"error",value:t};case"concurrentQueue":return{type:"queue",value:{type:"concurrent",name:t.name,position:t.position}};case"queue":return{type:"queue",value:{type:"session",position:t.position}};case"deviceInfo":case"sessionInfo":case"sessionRequested":return{type:e,value:t}}return{type:e,value:t}}}class qe extends D{constructor({socket:e}){super(),this.eventMapper=new Ne,this._socket=e,e.on("*",({type:t,value:s})=>{const i=this.mapEmit(t,s);i===null||(this.emit(i.type,i.value),this.emit("*",i))})}mapEmit(e,t){return this.eventMapper.toPublic(e,t)}mapSend(e,t){return this.eventMapper.toInternal(e,t)}send(e,t){const s=this.mapSend(e,t);return this._socket.send(s.type,s.value)}disconnect(){return this._socket.disconnect()}}class Ue extends D{constructor({socket:e,logger:t=new V}){super(),this.logger=t,this.socket=new qe({socket:e}),this.socket.on("*",({type:s,value:i})=>{s!=="newSession"&&(this.emit(s,i),this.emit("*",{type:s,value:i}))}),this.socket.on("newSession",()=>{this.queue&&(this.emit("queueEnd"),this.queue=void 0)}),this.on("queue",s=>{this.queue=s})}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 i=()=>{s(new Error("Session disconnected before it was ready"))},o=r=>{s(new Error(`Session failed to start - ${typeof r.message=="object"?JSON.stringify(r.message):r.message}`))},a=r=>{var c;s(new Error(`Session failed to start - ${(c=r==null?void 0:r.message)!=null?c:"Unknown error"}`))};try{this.on("error",a),e.on("disconnect",i),e.on("error",o),await e.waitUntilReady()}catch(r){s(r)}finally{this.off("error",a),e.off("disconnect",i),e.off("error",o)}t(e)})}}async function H(n,e=5e3){const t=Date.now();let s=!1;for(;;)try{return await n(o=>{if(o)throw s=!0,o})}catch(i){if(await new Promise(o=>setTimeout(o,100)),s||e!==null&&Date.now()-t>e)throw i}}async function J(n){return new Promise(e=>setTimeout(e,n))}async function _(n,e,t){const s=typeof t=="function"?{}:t,i=typeof t=="function"?t:t==null?void 0:t.predicate,o=typeof(s==null?void 0:s.timeout)!="undefined"?s.timeout:1e4;return new Promise((a,r)=>{const c=h=>{(!i||i(h))&&(n.off(e,c),a(h))};n.on(e,c),o!==null&&setTimeout(()=>{n.off(e,c),r(new M(`Timeout ${o}ms exceeded while waiting for event "${e}"`))},o)})}function Le(n){return n?{...T(n),device:n.deviceType||n.device}:{}}class Ke extends Ue{constructor({socket:e,window:t,logger:s=new V,config:i,autoInit:o=!0}){super({socket:e,logger:s}),this.ready=!1,this.isRequestingSession=!1,this._lastSetConfigCallId=null,this.window=t,i&&this.assignConfig(i),this.window.on("*",async({type:a,value:r})=>{if(this.ready)switch(a){case"app":this.app=r,this.emit(a,r);break;case"deviceInfo":this.device=r,this.emit(a,r);break;case"config":this.assignConfig(r);break}}),this.window.on("reinit",()=>{this.ready=!1,this.session=void 0,this.init({isReinit:!0})}),this.socket.on("*",async({type:a,value:r})=>{if(this.ready)switch(a){case"newSession":try{this.isRequestingSession=!1,this.session=this.createSession(this._config,{path:r.path,token:r.sessionToken}),await this.waitForSessionStart(this.session),this.emit("session",this.session)}catch(c){this.session=void 0,this.emit("sessionError",c)}}}),o!==!1&&this.init()}async init(e={isReinit:!1}){await this.window.waitUntilReady();const t=async()=>{if(e.isReinit){const o=this._config,a=await this.setConfig({});return this.setConfig({record:!0,...o,...a})}else return this.setConfig({record:!0,...this._config})},[s,i]=await Promise.all([this.window.postMessage({type:"getApp"},!0),this.window.postMessage({type:"getDeviceInfo"},!0),t()]);this.app=s,this.device=i,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){const t=this.isRequestingSession,s=()=>this.isRequestingSession===!1;this.isRequestingSession=!0;try{try{await this.waitUntilReady()}catch(i){const o=i instanceof Error?i.message:i;throw new Error(`Failed to start session. ${o}`)}if(s()||(this.session?await this.session.end():t&&(await this.cancelSessionRequest(),this.isRequestingSession=!0)),s()||await this.setConfig(e!=null?e:{}),s())throw new Error("Session request was cancelled");{const[i]=await Promise.all([new Promise((o,a)=>{const r=h=>{this.off("session",r),this.off("sessionError",c),this.off("error",c),o(h)},c=h=>{this.off("session",r),this.off("sessionError",c),this.off("error",c),h instanceof Error?a(h):h&&typeof h.message=="string"?a(new Error(`Session failed to start - ${h.message}`)):a(h)};this.on("session",r),this.on("sessionError",c),this.on("error",c)}),this.window.postMessage({type:"requestSession"},!0)]);return i}}finally{this.isRequestingSession=!1}}async endSession(){this.session?await this.session.end():this.isRequestingSession&&await this.cancelSessionRequest()}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({buildId:e,publicKey:t,...s}){this._lastSetConfigCallId=Math.random().toString(36);const i=this._lastSetConfigCallId;if(!e&&t&&(e=t),e){const a=await this.window.postMessage({type:"loadApp",value:e},!0);if(a&&"error"in a){if(a.error==="cancelled")return this._config;throw new Error(a.error)}if(i!==this._lastSetConfigCallId)return this._config}const o=await this.window.postMessage({type:"setConfig",value:this.validateConfig({...s,...e?{publicKey:e}:{}})},!0);return this.assignConfig(o)}assignConfig(e){return e.autoplay===!0&&this.logger.warn.once("autoplay=true may cause the session to start before the SDK is ready. You should start the session programmatically using client.startSession() instead."),this._config=Le(e),this._config}validateConfig(e){return e}async cancelSessionRequest(){this.isRequestingSession&&(this.isRequestingSession=!1,await this.window.postMessage("endSession"),this.emit("sessionEnded"))}createSession(e,t){throw new Error("Not implemented")}}class je extends V{constructor(){super(...arguments),this.logHistory=[],this.logLevel=process.env.CI==="true"?"warnings-errors":"verbose",this.log=this.createPlaywrightLogFn("log",()=>this.logLevel==="verbose"),this.warn=this.createPlaywrightLogFn("warn",()=>this.logLevel==="verbose"||this.logLevel==="warnings-errors"),this.error=this.createPlaywrightLogFn("error",()=>this.logLevel==="verbose"||this.logLevel==="warnings-errors"),this.debug=this.createPlaywrightLogFn("debug",()=>this.logLevel==="verbose"),this.clearLogHistory=()=>{this.logHistory=[]}}createPlaywrightLogFn(e,t){const s=new Set,i="[Appetize]",o=(...a)=>{this.logHistory.push({method:e,data:a}),t()&&console[e](i,...a)};return o.once=a=>{if(!s.has(a))return s.add(a),o.call(console,a)},o}}const S=new je;function Ve(n){const e=n.length;let t="";for(let s=0;s<e;s+=65535){let i=65535;s+65535>e&&(i=e-s),t+=String.fromCharCode.apply(null,n.subarray(s,s+i))}return t}function ze(n,e){if(typeof window=="undefined"&&typeof Buffer!="undefined"){const t=Buffer.from(n).toString("base64");return`data:${e};base64,`+t}else{const t=Ve(n),s=btoa(t);return`data:${e};base64,`+s}}class Je{constructor({duration:e,stepDuration:t}){this.moves=[],this.duration=e,this.stepDuration=t!=null?t:16,this.moves=[{x:0,y:0}]}to(e,t){if(typeof e!="string"||typeof t!="string")throw new x('x and y must be strings and in percentages (e.g. "50%")');if(!e.endsWith("%")||!t.endsWith("%"))throw new x('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 r;const e=this.stepDuration,t=(r=this.duration)!=null?r:Math.max(500,e*(this.moves.length-1)),s=Math.floor(t/e),i=Math.floor(s/(this.moves.length-1)),o=[];let a=0;if(i===0){const c=(this.moves.length-1)*e;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],p=c===this.moves.length-2;for(let y=0;y<=i;y++){if(!p&&y===i)continue;const b=y/i,l=h.x+b*(u.x-h.x),w=h.y+b*(u.y-h.y),m=((c*i+y)*e+a)/1e3;o.push({x:l,y:w,t:m}),y===0&&h.wait&&(o.push({x:l,y:w,t:m+h.wait/1e3}),a+=h.wait)}if(c===this.moves.length-2&&u.wait){const y=o[o.length-1];o.push({x:y.x,y:y.y,t:y.t+u.wait/1e3})}}return o}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 We extends D{constructor({socket:e,platform:t,screen:s,app:i}){super(),this._socket=e,this.platform=t,this.screen=s,this.app=i,e.on("*",({type:o,value:a})=>{const r=this.mapEmit(o,a);r===null||(this.handleEvent(r.type,r.value),this.emit(r.type,r.value),this.emit("*",r))})}send(e,t){const s=this.mapSend(e,t);return this._socket.send(s.type,s.value)}disconnect(){return this._socket.disconnect()}handleEvent(e,t){switch(e){case"app":this.app=t;break;case"deviceInfo":{const s=t;s!=null&&s.screen&&(this.screen=s.screen);break}case"config":{const s=t;s.platform&&(this.platform=s.platform);break}}}mapEmit(e,t){return new re({platform:this.platform,screen:this.screen,app:this.app}).toPublic(e,t)}mapSend(e,t){return new re({platform:this.platform,screen:this.screen,app:this.app}).toInternal(e,t)}}class Be extends D{constructor({socket:t,config:s,path:i,token:o,app:a,device:r,logger:c=new V}){super();Z(this,I,void 0);Z(this,$,void 0);this.isEndingManually=!1,this.countdownWarning=!1,this.ready=!1,this._waitForAnimationsPromises=new Set,this.config=s,this.socket=new We({socket:t,app:a,screen:r.screen,platform:s.platform}),this.device=r,this.app=a,this.path=i,this.token=o,this.logger=c;const h=({type:u,value:p})=>{switch(u){case"ready":this.ready=!0;break;case"adbOverTcp":{ee(this,I,{...p,command:He(p)});break}case"networkInspectorUrl":ee(this,$,p);break;case"countdownWarning":this.countdownWarning=!0;break;case"timeoutReset":this.countdownWarning=!1;break;case"deviceInfo":this.device=p;break;case"disconnect":this.emit("end"),this.emit("*",{type:"end"});break}this.emit(u,p),this.emit("*",{type:u,value:p})};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 o=>new Promise(a=>{const r=setInterval(()=>{o()&&a(void 0)},10);setTimeout(()=>{clearInterval(r),a(void 0)},3e3)}),i=()=>{t=!1};this.socket.once("disconnect",i);try{await H(o=>{if(!this.ready){if(t)throw new M("Timed out after 180s waiting for session to be ready");o(new Error("Session disconnected"))}},18e4)}finally{this.socket.off("disconnect",i)}await Promise.all([this.config.proxy==="intercept"?s(()=>Boolean(F(this,$))):Promise.resolve(),this.config.enableAdb?s(()=>Boolean(F(this,I))):Promise.resolve()])}async waitForEvent(t,s){try{return await _(this,t,s)}catch(i){throw f(i,this.waitForEvent),i}}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'),F(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"),F(this,I))return F(this,I)}async rotate(t){try{if(this.config.platform==="android"&&this.config.osVersion&&Ce(this.config.osVersion).major===14)throw new Error("Rotation is not supported for devices running Android 14");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 f(s,this.rotate),s}}async screenshot(t="buffer"){var s;try{this.socket.send("getScreenshot",{});const i=await _(this.socket,"screenshot",{timeout:6e4});if(!i.success)throw new x((s=i.error)!=null?s:"Screenshot failed");return{data:t==="buffer"?(r=>typeof window=="undefined"?Buffer.from(r):r)(i.data):ze(new Uint8Array(i.data),i.mimeType),mimeType:i.mimeType}}catch(i){throw f(i,this.screenshot),i}}async heartbeat(){try{return await this.socket.send("heartbeat")}catch(t){throw f(t,this.heartbeat),t}}async type(t){try{await J(1e3);const s=await this.playAction({type:"typeText",text:t});return await J(500),s}catch(s){throw f(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(i){throw f(i,this.keypress),i}}async setLanguage(t){try{return this.config.language=t,await this.socket.send("setLanguage",{language:t,timeStamp:Date.now()})}catch(s){throw f(s,this.setLanguage),s}}async setLocation(t,s){try{if(typeof t!="number"||typeof s!="number")throw new x("setLocation requires latitude and longitude to be numbers");const i=[t,s];return this.config.location=i,await this.socket.send("setLocation",{location:i,timeStamp:Date.now()})}catch(i){throw f(i,this.setLocation),i}}async openUrl(t){try{return await this.socket.send("openUrl",{url:t,timeStamp:Date.now()})}catch(s){throw f(s,this.openUrl),s}}async launchApp(t){try{return await this.socket.send("launchApp",{appId:t,timeStamp:Date.now()})}catch(s){throw f(s,this.launchApp),s}}async shake(){try{return await this.socket.send("shakeDevice")}catch(t){throw f(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 f(t,this.toggleSoftKeyboard),t}}async biometry({match:t}){try{return await this.socket.send(t?"biometryMatch":"biometryNonMatch")}catch(s){throw f(s,this.biometry),s}}async biometryEnrollment(t){try{if(this.config.platform!=="ios")throw new Error("biometryEnrollment is only available on iOS devices");return await this.socket.send("biometryEnrollment",{isEnrolled:t})}catch(s){throw f(s,this.biometryEnrollment),s}}async allowInteractions(t){try{return await this.socket.send(t?"enableInteractions":"disableInteractions")}catch(s){throw f(s,this.allowInteractions),s}}async restartApp(){try{this.isStandalone?this.logger.warn("restartApp has no effect on a Standalone"):(this.socket.send("restartApp"),await this.waitForEvent("appLaunch",{timeout:6e4}))}catch(t){throw f(t,this.restartApp),t}}async reinstallApp(){try{this.isStandalone?this.logger.warn("reinstallApp has no effect on a Standalone"):(this.socket.send("reinstallApp"),await this.waitForEvent("appLaunch",{timeout:6e4}))}catch(t){throw f(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 f(s,this.adbShellCommand),s}}async playAction(t,s={}){const{timeout:i=1e4}=s,o=1e4,a=i+3e4;try{if(!this.config.record)throw new z("playAction()");if(isNaN(i))throw new x(`Invalid timeout value: ${s.timeout}`);if(i<0)throw new x(`Timeout value cannot be negative: ${s.timeout}`);"element"in t&&t.element&&k.isValidElementSelector(t.element);const r={id:Pe(),action:t,options:{...s,timeout:Math.round(Math.min(i,o)/1e3)}};try{return await new Promise((h,u)=>{const p=setTimeout(()=>{y(),u(new ie({id:r.id,action:t,timeout:r.options.timeout},"Timed out waiting for response from device"))},a),y=()=>{this.off("playbackFoundAndSent",b),this.off("playbackError",l),clearTimeout(p)},b=async w=>{var m;((m=w.playback)==null?void 0:m.id)===r.id&&(y(),h(w))},l=async w=>{var m;if(((m=w.playback)==null?void 0:m.id)===r.id)switch(y(),w.errorId){case"internalError":u(new se(w));break;case"notFound":{u(new Re(w));break}case"ambiguousMatch":u(new $e(w));break;case"invalidArgument":{u(new De(w));break}default:u(new O(w));break}};this.on("playbackFoundAndSent",b),this.on("playbackError",l),this.socket.send("playAction",r)})}catch(c){const h=Math.max(0,i-o);if(h>0&&!(c instanceof ie)&&!(c instanceof se))return await this.playAction(t,{...s,timeout:h});throw c}}catch(r){throw f(r,this.playAction),r}}async playActions(t,s={}){try{if(!this.config.record)throw new z("playActions()");const i=[];for(const o of t){const a=await this.playAction(o,s);i.push(a);const r=t[t.indexOf(o)+1];r&&r.type==="keypress"&&o.type==="keypress"||await this.waitForAnimations({timeout:2e3}).catch(()=>{})}return i}catch(i){throw f(i,this.playActions),i}}async getUI({timeout:t=3e4}={}){try{return this.socket.send("dumpUi"),await _(this,"uiDump",{timeout:t})}catch(s){throw f(s,this.getUI),s}}async findElement(t,s){var i;try{return(i=(await this.playAction({type:"findElements",element:t,appId:s==null?void 0:s.appId},s)).matchedElements)==null?void 0:i[0]}catch(o){throw f(o,this.findElement),o}}async findElements(t,s){try{return(await this.playAction({type:"findElements",element:t,appId:s==null?void 0:s.appId},s)).matchedElements}catch(i){throw f(i,this.findElements),i}}async tap(t,s){var i;try{if(!this.config.record)throw new z("tap()");return await this.playAction({type:"tap",...t,duration:((i=t.duration)!=null?i:0)/1e3},s)}catch(o){throw f(o,this.tap),o}}async swipe({duration:t,gesture:s,...i},o){try{if(!this.config.record)throw new z("swipe()");let a;const r=new Je({duration:t,stepDuration:i.stepDuration});if(typeof s=="function")s(r);else switch(s){case"up":r.up();break;case"down":r.down();break;case"left":r.left();break;case"right":r.right();break}if("element"in i)a={type:"swipe",element:i.element,localPosition:i.localPosition,moves:r.build()};else if("position"in i)a={type:"swipe",position:i.position,moves:r.build()};else throw new Error("Either element or position must be specified");return this.playAction(a,o)}catch(a){throw f(a,this.swipe),a}}async waitForAnimations(t={}){try{const{imageThreshold:s=.001,timeout:i=1e4}=t;let o=1e3,a=1;t.imageThresholdDuration&&(o=t.imageThresholdDuration);const{promise:r,resolve:c,reject:h}=Fe(),u=setTimeout(()=>{let b=`Timed out after ${i}ms waiting for animation to end.`;s<a&&(b+=` Waited for imageThreshold of ${s} but lowest was ${Math.round(a*1e4)/1e4}`),h(new M(b))},i);let p;const y=({percentage:b,timestamp:l})=>{b<a&&(a=b),b<=s?(p||(p=l),p&&l-p>=o&&c()):p=void 0};return this.socket.send("enablePixelChangeDetection"),this.socket.on("pixelsChanged",y),this._waitForAnimationsPromises.add(r),await r.finally(()=>{clearTimeout(u),this.socket.off("pixelsChanged",y),this._waitForAnimationsPromises.delete(r),this._waitForAnimationsPromises.size===0&&this.socket.send("disablePixelChangeDetection")})}catch(s){throw f(s,this.waitForAnimations),s}}async getAdbInfo(){return this.logger.warn("getAdbInfo() is deprecated. Please use the `adbConnection` property instead."),Promise.resolve(F(this,I))}async getNetworkInspectorUrl(){return this.logger.warn("getNetworkInspectorUrl() is deprecated. Please use the `networkInspectorUrl` property instead."),Promise.resolve(F(this,$))}async getDeviceInfo(){return this.logger.warn("getDeviceInfo() is deprecated. Please use the `device` property instead."),Promise.resolve(this.device)}get isStandalone(){var t;return(t=this.app)!=null&&t.buildId?this.app.buildId.startsWith("standalone_"):!1}}I=new WeakMap,$=new WeakMap;function He(n){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(!n||!n.forwards[0])return;let t=e;return t=t.replace(/SERVER_PORT/,n.port.toString()),t=t.replace(/USERNAME/,n.user),t=t.replace(/HOSTNAME/,n.hostname),t=t.replace(/FORWARD_DESTINATION/,n.forwards[0].destination),t=t.replace(/FORWARD_PORT/,n.forwards[0].port.toString()),t}async function Ye(n){await n.pause()}function W(n){if(n.character)return n.character;const e=n.key;return B(e)?e:n.shiftKey?e.toUpperCase():e.toLowerCase()}function B(n){return/^[\b\t\r]/.test(n)}class Qe{constructor({testInfo:e,session:t}){this.currentRecord=0,this.session=t,this.testInfo=e}async record(){const e=this.testInfo.file,t=await v.default.promises.readFile(e,"utf8"),i=t.split(`
`).map((o,a)=>({line:o,num:a+1})).slice(this.testInfo.line).filter(({line:o})=>o.includes("session.record()"))[this.currentRecord].num;if(i!==void 0){console.log(`\u{1F534} Recording at line ${i}`);const o=[],a=c=>{Xe(o,c),console.log(oe(c))};this.session.on("action",a),await Ye(this.session.page),await J(2e3),this.session.off("action",a);const r=t.split(`
`).map((c,h)=>{var u,p;if(h===i-1){const y=(p=(u=c.match(/^\s*/))==null?void 0:u[0])!=null?p:0;return`${o.map(l=>oe(l)).reduce((l,w,m)=>`${l}
// ${m+1}. ${w}`,"// Recorded using session.record()")}
await session.playActions(${JSON.stringify(o,null," ")})`.split(`
`).map(l=>y+l).join(`
`)}return c});await v.default.promises.writeFile(e,n.join(`
`)),console.log("\u{1F7E2} Finished"),this.currentRecord+=1}}}function Xe(r,e){const t=r[r.length-1];if(t)switch(e.type){case"keypress":{(t==null?void 0:t.type)==="keypress"&&!B(e.key)&&!B(t.key)?(r.pop(),r.push({type:"typeText",text:W(t)+W(e)})):(t==null?void 0:t.type)==="typeText"&&!B(e.key)?(r.pop(),r.push({type:"typeText",text:t.text+W(e)})):r.push(e);break}default:r.push(e)}else r.push(e)}function ae(r){var t,s,i,o,a,n;let e="";switch(r.type){case"swipe":case"tap":{const c=r.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}"`:(i=c==null?void 0:c.attributes)!=null&&i.class?e=`element with class "${(o=c.attributes)==null?void 0:o.class}"`:"position"in r&&((a=r.position)==null?void 0:a.x)&&((n=r.position)==null?void 0:n.y)&&(e=`position ${Math.round(r.position.x*100)}%, ${Math.round(r.position.y*100)}%`),e?`${r.type} on ${e}`:r.type}case"keypress":return`type "${W(r)}"`;case"typeText":return`type "${r.text}"`}}const Ge="1.4.0-beta.1";class Ze extends D{constructor({page:e,testFixture:t}){super(),this.ready=!1,this.page=e,this.testFixture=t}async init(){this.ready=!1,await this.testFixture.step("Connect to Appetize page",async()=>{await this.page.exposeFunction("__appetize_on",e=>{const t=JSON.parse(e,function(o,a){try{if("flag"in a&&a.flag==="TYPED_ARRAY")return global[a.constructor].from(a.data.split(",").map(Number))}catch{}return a}),s=t==="string"?t:t.type,i=t.value;this.emit(s,i),this.emit("*",{type:s,value:i})}),await this.page.evaluate(async([e])=>new Promise((t,s)=>{const i=setTimeout(()=>{clearInterval(o),s(new M("Timed out after 60000ms waiting for connection to Appetize page"))},6e4),o=setInterval(()=>{const a=new MessageChannel;a.port1.onmessage=()=>{clearInterval(o),clearTimeout(i),a.port1.close(),a.port2.close(),t(!1)},window.postMessage({type:"init",appetizeClient:!0,version:e},"*",[a.port2]),window.__appetize_postMessage=async(n,c=!1)=>{const h=new MessageChannel;if(window.postMessage(n,"*",[h.port2]),c)return new Promise((u,p)=>{const y=setTimeout(()=>{p(new M("Timed out after 60000ms while waiting for postMessage response"))},6e4);h.port1.onmessage=E=>{clearTimeout(y),h.port1.close(),h.port2.close(),u(E.data)}});h.port1.close(),h.port2.close()}},100)}),[Ge]),await this.page.evaluate(()=>{window.addEventListener("message",e=>{var t;if(e.source===window){switch(typeof e.data=="string"?e.data:(t=e.data)==null?void 0:t.type){case"frameData":case"recordedAction":case"playbackFoundAndSent":case"playbackNotFound":case"debug":case"interceptRequest":case"interceptResponse":case"interceptError":case"uiDump":return}window.__appetize_on(JSON.stringify(e.data,function(i,o){return o instanceof Int8Array||o instanceof Uint8Array||o instanceof Uint8ClampedArray||o instanceof Int16Array||o instanceof Uint16Array||o instanceof Int32Array||o instanceof Uint32Array||o instanceof Float32Array||o instanceof Float64Array?{constructor:o.constructor.name,data:o.join(","),flag:"TYPED_ARRAY"}:o}))}})},[])}),this.ready=!0}async waitUntilReady(){return H(async()=>{if(!this.ready)throw new M("Timed out after 60000ms while waiting for Appetize window to be ready.")},6e4)}async postMessage(e,t=!1){await this.waitUntilReady();try{return await this.testFixture.step("postMessage",async()=>this.page.evaluate(async([s,i])=>window.__appetize_postMessage(s,i),[e,t]))}catch(s){throw b.error("Error sending postMessage: ",e),s}}}class ce extends D{constructor({page:e,type:t,window:s}){super(),this.page=e,this.type=t,this.window=s,this.window.on("*",({type:i,value:o})=>{switch(i){case"socketEvent":if(o.socket===this.type){const a=o.type,n=o.value;this.emit(a,n),this.emit("*",{type:a,value:n})}break;case"disconnect":this.emit("disconnect"),this.emit("*",{type:"disconnect"});break;case"sessionInfo":case"chromeDevToolsUrl":case"orientationChanged":case"deviceInfo":this.type==="appetizer"&&(this.emit(i,o),this.emit("*",{type:i,value:o}));break;case"sessionRequested":this.type==="webserver"&&(this.emit(i,o),this.emit("*",{type:i,value: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 he extends Be{constructor({page:e,config:t,window:s,testFixture:i,...o}){const a=new ce({page:e,window:s,type:"appetizer"});super({...o,socket:a,config:t,logger:b}),this.actionLogs=[],this.window=s,this.page=e,this.config=t,this.testFixture=i,this.page.on("load",()=>{this.emit("disconnect")}),this.adbShellCommand=this.wrapAsStep(this.adbShellCommand),this.biometry=this.wrapAsStep(this.biometry),this.findElement=this.wrapAsStep(this.findElement,{subStepTitle:n=>JSON.stringify(n)}),this.findElements=this.wrapAsStep(this.findElements,{subStepTitle:n=>JSON.stringify(n)}),this.getUI=this.wrapAsStep(this.getUI),this.keypress=this.wrapAsStep(this.keypress,{subStepTitle:n=>JSON.stringify(n)}),this.launchApp=this.wrapAsStep(this.launchApp,{subStepTitle:n=>JSON.stringify(n)}),this.openUrl=this.wrapAsStep(this.openUrl,{subStepTitle:n=>JSON.stringify(n)}),this.playAction=this.wrapAsStep(this.playAction,{subStepTitle:n=>JSON.stringify(n)}),this.playActions=this.wrapAsStep(this.playActions,{subStepTitle:n=>JSON.stringify(n)}),this.reinstallApp=this.wrapAsStep(this.reinstallApp),this.restartApp=this.wrapAsStep(this.restartApp),this.rotate=this.wrapAsStep(this.rotate,{subStepTitle:n=>JSON.stringify(n)}),this.screenshot=this.wrapAsStep(this.screenshot),this.setLanguage=this.wrapAsStep(this.setLanguage,{subStepTitle:n=>JSON.stringify(n)}),this.setLocation=this.wrapAsStep(this.setLocation,{subStepTitle:n=>JSON.stringify(n)}),this.shake=this.wrapAsStep(this.shake),this.swipe=this.wrapAsStep(this.swipe,{subStepTitle:n=>JSON.stringify(n)}),this.tap=this.wrapAsStep(this.tap,{subStepTitle:n=>JSON.stringify(n)}),this.type=this.wrapAsStep(this.type,{subStepTitle:n=>JSON.stringify(n)}),this.waitForAnimations=this.wrapAsStep(this.waitForAnimations),this.waitForElement=this.wrapAsStep(this.waitForElement,{subStepTitle:n=>JSON.stringify(n)}),this.waitForEvent=this.wrapAsStep(this.waitForEvent,{title:n=>`session.waitForEvent - ${JSON.stringify(n)}`}),this.waitForTimeout=this.wrapAsStep(this.waitForTimeout,{title:n=>`session.waitForTimeout - ${JSON.stringify(n)}`})}async addActionLog(e){if(e.error){const t=await this.getUI().catch(this.logger.warn);t&&(e.ui=t)}this.actionLogs.push(e)}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 f(t,this.rotate),t}}async record(){try{if(!this.config.record)throw new S("Recording is not enabled, please enable it by setting `record: true` in session config");if(!this.testFixture)throw new S("session.record() requires using `session` from the test() arguments");return new Qe({session:this,testInfo:this.testFixture.info()}).record()}catch(e){throw f(e,this.record),e}}async waitForEvent(e,t){try{return await _(this,e,t)}catch(s){throw f(s,this.waitForEvent),s}}async waitForTimeout(e){try{return await J(e)}catch(t){throw f(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 f(s,this.waitForElement),s}}on(e,t){return super.on(e,t)}once(e,t){return super.once(e,t)}async getVideoFrames(){return console.warn("getVideoFrames() is deprecated. Use session.on('video') event instead"),[]}async getAudioFrames(){return console.warn("getAudioFrames() is deprecated. Use session.on('audio') event instead"),[]}wrapAsStep(e,t={}){return(...s)=>{var a;let i=`session.${e.name}`;t!=null&&t.title&&(i=t.title(...s));const o=(a=t==null?void 0:t.subStepTitle)==null?void 0:a.call(t,...s);return o?this.testFixture.step(i,()=>this.testFixture.step(o,()=>e.apply(this,s)),{box:!0}):this.testFixture.step(i,()=>e.apply(this,s),{box:!0})}}}const le=new WeakMap;class ue extends Ke{constructor({page:e,testFixture:t}){var a;const s=(a=le.get(e))!=null?a:new Ze({page:e,testFixture:t});le.set(e,s);const i=new ce({type:"webserver",page:e,window:s});super({socket:i,window:s,logger:b,autoInit:!1}),this.window=s,this.page=e,this.testFixture=t;let o=!1;this.on("queue",n=>{o||(o=!0,n.type==="concurrent"?this.logger.log(`Entered ${n.name}. Please wait until a slot becomes available.`):this.logger.log("All devices are currently in use. Please wait until requested device becomes available.")),n.position>0&&(n.type==="concurrent"?this.logger.log(`Position in ${n.name}: ${n.position}`):this.logger.log(`Position in queue: ${n.position}`))}),this.on("session",()=>{o&&(o=!1)})}async init(){return this.testFixture.step("Initialize client",async()=>{await this.window.init(),await super.init()})}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 he({config:e,page:this.page,window:this.window,path:t.path,token:t.token,device:this.device,app:this.app,testFixture:this.testFixture}),this.session}}class et{constructor(e){this.queueStart=null,this.queueEnd=null,this.baseURL="https://appetize.io",this.sessionDebugInfo={playedActions:[],videoFrames:[],audioFrames:[],debugLogs:[]},this.page=e.page,this.testFixture=e.testFixture,this.config=e.config,e.baseURL&&(this.baseURL=e.baseURL)}get queueTime(){var e;return this.queueStart?((e=this.queueEnd)!=null?e:Date.now())-this.queueStart:null}async init(){var s;const e={};for(const i in this.config)switch(i){case"device":case"osVersion":case"scale":case"orientation":e[i]=this.config[i];break}const t=await this.page.goto(`${this.baseURL}/embed/${this.config.buildId}?${Fe(e)}`);if((t==null?void 0:t.status())===404){const i=this.config.publicKey?"publicKey":"buildId";throw new Error(`App not found for ${i} "${(s=this.config.publicKey)!=null?s:this.config.buildId}"`)}this.client=new ue({page:this.page,testFixture:this.testFixture}),await this.client.init()}async start(e){this.queueStart=null,this.queueEnd=null,this.client.on("queue",()=>{this.queueStart||(this.queueStart=Date.now())}),this.client.on("queueEnd",()=>{this.queueStart&&(this.queueEnd=Date.now())});const t=async i=>{i!=null&&i.embed&&await this.page.setViewportSize({width:i.embed.width+8,height:i.embed.height+8})};this.client.on("deviceInfo",t),await this.client.waitUntilReady(),this.client.device&&t(this.client.device);const s=await Pe(()=>this.client.startSession(e.config),{retries:5,timeout:3e4,predicate:(i,o)=>i instanceof Error&&i.message.match(/too many requests/)?(console.warn(`Too many session requests. Retrying in 30 seconds... (attempt #${o})`),!0):!1});return this.config=s.config,this.requestKeyFrame(),s.config.debug===!0&&s.on("log",i=>{this.sessionDebugInfo.debugLogs.push(i.message)}),s.on("playbackFoundAndSent",i=>{this.sessionDebugInfo.playedActions.push(i)}),s.on("playbackError",i=>{this.sessionDebugInfo.playedActions.push(i)}),s.on("video",i=>{this.sessionDebugInfo.videoFrames.push(i)}),s.on("audio",i=>{this.sessionDebugInfo.audioFrames.push(i)}),s.on("end",()=>{this.session=void 0}),this.session=s,s}onTestStart(){this.clearSessionDebugInfo(),this.requestKeyFrame()}clearSessionDebugInfo(){this.sessionDebugInfo.playedActions=[],this.sessionDebugInfo.videoFrames=[],this.sessionDebugInfo.audioFrames=[],this.sessionDebugInfo.debugLogs=[]}requestKeyFrame(){this.session&&this.testFixture.step("",async()=>{var e;return(e=this.session)==null?void 0:e.socket.send("requestKeyFrame").catch(()=>{})})}}let R=null,Y=null;const N=g.test.extend({config:[async({_useConfig:r},e,t)=>{const s={...t.project.use.config,...r,autoplay:!1};"publicKey"in s&&!!s.publicKey&&("buildId"in s&&!!s.buildId?(b.warn(`Both "buildId" ("${s.buildId}") and "publicKey" ("${s.publicKey}") were defined in the test config. Using buildId.`),s.publicKey=s.buildId):s.buildId=s.publicKey),await e(s)},{auto:!0}],async page({appetizePage:r},e){await e(r.page)},async appetizePage({context:r,config:e,baseURL:t},s){if(R){const{session:i,page:o}=R;if(i){let a=!1;if(Y){for(const n in e)if(JSON.stringify(Y[n])!==JSON.stringify(e[n])){a=!0;break}}else a=!0;a&&(i&&await i.end().catch(()=>{}),await o.close(),R=null)}}if(!R){if(!e.buildId)throw new Error('Appetize buildId not set. Make sure you have set it with `test.use({ config: { buildId: "..." } })` or in your Playwright config file.');R=new et({page:await r.newPage(),testFixture:P,config:e,baseURL:t}),await R.init()}Y=e,await s(R)},async session({appetizePage:r,config:e,_doSetupAndTeardown:t},s){let i=r.session;i||(i=await P.step("Start Appetize session",async()=>{if(await r.start({config:e}),r.queueTime&&P.info().annotations.push({type:"queueTime",description:`${r.queueTime}ms`}),!r.session)throw new Error("Appetize session failed to start");return r.session},{box:!0}),P.info().annotations.push({type:"Appetize Documentation",description:"https://docs.appetize.io/javascript-sdk/playwright"})),await P.step(`${i.path}/client?sessionToken=${i.token}`,()=>{}),i.testFixture=P,await s(i)},async client({appetizePage:r},e){await e(r.client)},_useConfig:[{},{option:!0}],_autoSnapshotSuffix:[async({},r,e)=>{e.snapshotSuffix="",await r()},{auto:!0}],_doSetupAndTeardown:[async({appetizePage:r},e,t)=>{b.clearLogHistory(),r&&r.onTestStart(),await e();try{await ye({appetizePage:r,testInfo:t})}catch(s){b.error("Failed to save attachments",s)}t.status==="timedOut"&&r.queueTime&&b.error("Test timed out while in queue for a device. You may increase your test timeout to account for higher queue times.");try{me(t)}catch{}},{auto:!0}],context:[async({_browserContext:r,video:e,contextOptions:t},s)=>{e&&e!=="off"&&b.warn.once("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&&b.warn.once("contextOptions are not supported with @appetize/playwright"),await s(r)},{scope:"test"}],_browserContext:[async({browser:r},e)=>{const t=await r.newContext();await e(t),await t.close()},{scope:"worker"}]}),pe=r=>{const e=r.use;return t=>{const{config:s,...i}=t;return e({...i,_useConfig:s})}},de=r=>{const e=r.afterEach;return t=>(e(async({appetizePage:s},i)=>{if(s)try{await ye({appetizePage:s,testInfo:i})}catch(o){b.error("Failed to save attachments",o)}}),e(t))},fe=r=>{const e=r.extend;return t=>{const s=e(t);return s.afterEach=de(s).bind(s),s.use=pe(s).bind(s),s.extend=fe(s).bind(s),s}};Object.assign(N,{use:pe(N),afterEach:de(N),extend:fe(N),setup(r){return{}.__APPETIZE__SETUP_WARNED||b.warn("test.setup() is deprecated and will be removed in a future release. Use test.use({ config: {...} }) instead"),P.use({config:r})}});const P=N,we=new WeakMap;async function ye(r){const{appetizePage:e,testInfo:t}=r,s=e.session;if(!(t.status==="failed"||t.status==="timedOut"||t.status==="interrupted")||we.get(t.fn))return;we.set(t.fn,!0);const o=C.default.join(Te.default.tmpdir(),`appetize-playwright-${t.testId}-${t.workerIndex}`),a=async()=>{v.default.existsSync(o)&&await v.default.promises.rm(o,{recursive:!0,force:!0}).catch(()=>{})};try{await a(),await v.default.promises.mkdir(o);const n=e.sessionDebugInfo.playedActions,c=async()=>{try{if(s){const l=await s.screenshot("buffer"),w=C.default.join(o,"screenshot.png");await v.default.promises.writeFile(w,Buffer.from(l.data)),await t.attach("screenshot",{path:w,contentType:"image/png"})}}catch(l){b.error("Failed to attach screenshot.png",l instanceof Error?l.message:void 0)}},h=async()=>{try{const l=n.map(q=>{if("screenshot"in q){const{screenshot:Q,...U}=q;return U}return q});if(!l.length)return;const w=JSON.stringify(l,null,2),m=C.default.join(o,"actions.json");await v.default.promises.writeFile(m,w),await t.attach("actions",{path:m,contentType:"application/json"})}catch(l){b.error("Failed to attach actions.json",l instanceof Error?l.message:void 0)}},u=async()=>{try{const{videoFrames:l}=e.sessionDebugInfo;if(l.length===0||l.some(U=>U.codec!=="h264"))return;const w="video",m=new ke.default({mode:w,fps:15}),q=await new Promise((U,ge)=>{const be=setTimeout(()=>{ge(new Error("Timed out muxing session video"))},3e4),X=new Ee.Readable({objectMode:!0,read(){}}),st=Buffer.concat(l.map(L=>Buffer.from(L.buffer)));X.push({video:st}),X.push(null);let G=Buffer.from([]);X.pipe(m.createStream()).on("data",L=>{G=Buffer.concat([G,L])}).on("error",L=>{clearTimeout(be),ge(L)}).on("end",()=>{clearTimeout(be),U(G)})}),Q=C.default.join(o,"video.mp4");await v.default.promises.writeFile(Q,q),await t.attach("video.mp4",{path:Q,contentType:"video/mp4"})}catch(l){b.error("Failed to attach video.mp4",l instanceof Error?l.message:void 0)}},p=async()=>{if(!!b.logHistory.length)try{const l=`${b.logHistory.map(m=>`[${m.method}] ${JSON.stringify(m.data).slice(2,-2)}`).join(`
`)}`,w=C.default.join(o,"sdk-logs.txt");await v.default.promises.writeFile(w,l),await t.attach("sdk-logs",{path:w,contentType:"application/text"})}catch(l){b.error("Failed to attach sdk-logs.txt",l)}},y=async()=>{const{debugLogs:l}=e.sessionDebugInfo;if(l.length>0)try{const w=l.join(""),m=C.default.join(o,"debug-logs.txt");await v.default.promises.writeFile(m,w),await t.attach("debug-logs",{path:m,contentType:"application/text"})}catch(w){b.error("Failed to attach debug-logs.txt",w)}},E=async()=>{try{if(e.session){const l=C.default.join(o,"session.json"),w=JSON.stringify({path:e.session.path,token:e.session.token,config:e.session.config},null,2);await v.default.promises.writeFile(l,w),await t.attach("session",{path:l,contentType:"application/json"})}}catch(l){b.error("Failed to attach session.json",l)}};await Promise.all([c(),h(),u(),y(),E()]),await p()}finally{await a()}}function me(r){const e=r.steps||r._steps;!e||e.forEach((t,s)=>{t.title===""&&e.splice(s,1),me(t)})}var tt=Object.freeze(Object.defineProperty({__proto__:null},Symbol.toStringTag,{value:"Module"}));Object.defineProperty(d,"expect",{enumerable:!0,get:function(){return g.expect}}),d.InternalRecorderAPI=tt,d.PlaywrightClient=ue,d.PlaywrightSession=he,d.test=P,Object.defineProperties(d,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
`)}return c});await v.default.promises.writeFile(e,r.join(`
`)),console.log("\u{1F7E2} Finished"),this.currentRecord+=1}}}function Xe(n,e){const t=n[n.length-1];if(t)switch(e.type){case"keypress":{(t==null?void 0:t.type)==="keypress"&&!B(e.key)&&!B(t.key)?(n.pop(),n.push({type:"typeText",text:W(t)+W(e)})):(t==null?void 0:t.type)==="typeText"&&!B(e.key)?(n.pop(),n.push({type:"typeText",text:t.text+W(e)})):n.push(e);break}default:n.push(e)}else n.push(e)}function oe(n){var t,s,i,o,a,r;let e="";switch(n.type){case"swipe":case"tap":{const c=n.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}"`:(i=c==null?void 0:c.attributes)!=null&&i.class?e=`element with class "${(o=c.attributes)==null?void 0:o.class}"`:"position"in n&&((a=n.position)==null?void 0:a.x)&&((r=n.position)==null?void 0:r.y)&&(e=`position ${Math.round(n.position.x*100)}%, ${Math.round(n.position.y*100)}%`),e?`${n.type} on ${e}`:n.type}case"keypress":return`type "${W(n)}"`;case"typeText":return`type "${n.text}"`}}const Ge="1.4.0";class Ze extends D{constructor({page:e,testFixture:t}){super(),this.ready=!1,this.page=e,this.testFixture=t}async init(){this.ready=!1,await this.testFixture.step("Connect to Appetize page",async()=>{await this.page.exposeFunction("__appetize_on",e=>{const t=JSON.parse(e,function(o,a){try{if("flag"in a&&a.flag==="TYPED_ARRAY")return global[a.constructor].from(a.data.split(",").map(Number))}catch{}return a}),s=t==="string"?t:t.type,i=t.value;this.emit(s,i),this.emit("*",{type:s,value:i})}),await this.page.evaluate(async([e])=>new Promise((t,s)=>{const i=setTimeout(()=>{clearInterval(o),s(new M("Timed out after 60000ms waiting for connection to Appetize page"))},6e4),o=setInterval(()=>{const a=new MessageChannel;a.port1.onmessage=()=>{clearInterval(o),clearTimeout(i),a.port1.close(),a.port2.close(),t(!1)},window.postMessage({type:"init",appetizeClient:!0,version:e},"*",[a.port2]),window.__appetize_postMessage=async(r,c=!1)=>{const h=new MessageChannel;if(window.postMessage(r,"*",[h.port2]),c)return new Promise((u,p)=>{const y=setTimeout(()=>{p(new M("Timed out after 60000ms while waiting for postMessage response"))},6e4);h.port1.onmessage=b=>{clearTimeout(y),h.port1.close(),h.port2.close(),u(b.data)}});h.port1.close(),h.port2.close()}},100)}),[Ge]),await this.page.evaluate(()=>{window.addEventListener("message",e=>{var t;if(e.source===window){switch(typeof e.data=="string"?e.data:(t=e.data)==null?void 0:t.type){case"frameData":case"recordedAction":case"playbackFoundAndSent":case"playbackNotFound":case"debug":case"interceptRequest":case"interceptResponse":case"interceptError":case"uiDump":return}window.__appetize_on(JSON.stringify(e.data,function(i,o){return o instanceof Int8Array||o instanceof Uint8Array||o instanceof Uint8ClampedArray||o instanceof Int16Array||o instanceof Uint16Array||o instanceof Int32Array||o instanceof Uint32Array||o instanceof Float32Array||o instanceof Float64Array?{constructor:o.constructor.name,data:o.join(","),flag:"TYPED_ARRAY"}:o}))}})},[])}),this.ready=!0}async waitUntilReady(){return H(async()=>{if(!this.ready)throw new M("Timed out after 60000ms while waiting for Appetize window to be ready.")},6e4)}async postMessage(e,t=!1){await this.waitUntilReady();try{return await this.testFixture.step("postMessage",async()=>this.page.evaluate(async([s,i])=>window.__appetize_postMessage(s,i),[e,t]))}catch(s){throw S.error("Error sending postMessage: ",e),s}}}class ae extends D{constructor({page:e,type:t,window:s}){super(),this.page=e,this.type=t,this.window=s,this.window.on("*",({type:i,value:o})=>{switch(i){case"socketEvent":if(o.socket===this.type){const a=o.type,r=o.value;this.emit(a,r),this.emit("*",{type:a,value:r})}break;case"disconnect":this.emit("disconnect"),this.emit("*",{type:"disconnect"});break;case"sessionInfo":case"chromeDevToolsUrl":case"orientationChanged":case"deviceInfo":this.type==="appetizer"&&(this.emit(i,o),this.emit("*",{type:i,value:o}));break;case"sessionRequested":this.type==="webserver"&&(this.emit(i,o),this.emit("*",{type:i,value: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 ce extends Be{constructor({page:e,config:t,window:s,testFixture:i,...o}){const a=new ae({page:e,window:s,type:"appetizer"});super({...o,socket:a,config:t,logger:S}),this.actionLogs=[],this.window=s,this.page=e,this.config=t,this.testFixture=i,this.page.on("load",()=>{this.emit("disconnect")}),this.adbShellCommand=this.wrapAsStep(this.adbShellCommand),this.biometry=this.wrapAsStep(this.biometry),this.findElement=this.wrapAsStep(this.findElement,{subStepTitle:r=>JSON.stringify(r)}),this.findElements=this.wrapAsStep(this.findElements,{subStepTitle:r=>JSON.stringify(r)}),this.getUI=this.wrapAsStep(this.getUI),this.keypress=this.wrapAsStep(this.keypress,{subStepTitle:r=>JSON.stringify(r)}),this.launchApp=this.wrapAsStep(this.launchApp,{subStepTitle:r=>JSON.stringify(r)}),this.openUrl=this.wrapAsStep(this.openUrl,{subStepTitle:r=>JSON.stringify(r)}),this.playAction=this.wrapAsStep(this.playAction,{subStepTitle:r=>JSON.stringify(r)}),this.playActions=this.wrapAsStep(this.playActions,{subStepTitle:r=>JSON.stringify(r)}),this.reinstallApp=this.wrapAsStep(this.reinstallApp),this.restartApp=this.wrapAsStep(this.restartApp),this.rotate=this.wrapAsStep(this.rotate,{subStepTitle:r=>JSON.stringify(r)}),this.screenshot=this.wrapAsStep(this.screenshot),this.setLanguage=this.wrapAsStep(this.setLanguage,{subStepTitle:r=>JSON.stringify(r)}),this.setLocation=this.wrapAsStep(this.setLocation,{subStepTitle:r=>JSON.stringify(r)}),this.shake=this.wrapAsStep(this.shake),this.swipe=this.wrapAsStep(this.swipe,{subStepTitle:r=>JSON.stringify(r)}),this.tap=this.wrapAsStep(this.tap,{subStepTitle:r=>JSON.stringify(r)}),this.type=this.wrapAsStep(this.type,{subStepTitle:r=>JSON.stringify(r)}),this.waitForAnimations=this.wrapAsStep(this.waitForAnimations),this.waitForElement=this.wrapAsStep(this.waitForElement,{subStepTitle:r=>JSON.stringify(r)}),this.waitForEvent=this.wrapAsStep(this.waitForEvent,{title:r=>`session.waitForEvent - ${JSON.stringify(r)}`}),this.waitForTimeout=this.wrapAsStep(this.waitForTimeout,{title:r=>`session.waitForTimeout - ${JSON.stringify(r)}`})}async addActionLog(e){if(e.error){const t=await this.getUI().catch(this.logger.warn);t&&(e.ui=t)}this.actionLogs.push(e)}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 f(t,this.rotate),t}}async record(){try{if(!this.config.record)throw new x("Recording is not enabled, please enable it by setting `record: true` in session config");if(!this.testFixture)throw new x("session.record() requires using `session` from the test() arguments");return new Qe({session:this,testInfo:this.testFixture.info()}).record()}catch(e){throw f(e,this.record),e}}async waitForEvent(e,t){try{return await _(this,e,t)}catch(s){throw f(s,this.waitForEvent),s}}async waitForTimeout(e){try{return await J(e)}catch(t){throw f(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 f(s,this.waitForElement),s}}on(e,t){return super.on(e,t)}once(e,t){return super.once(e,t)}async getVideoFrames(){return console.warn("getVideoFrames() is deprecated. Use session.on('video') event instead"),[]}async getAudioFrames(){return console.warn("getAudioFrames() is deprecated. Use session.on('audio') event instead"),[]}wrapAsStep(e,t={}){return(...s)=>{var a;let i=`session.${e.name}`;t!=null&&t.title&&(i=t.title(...s));const o=(a=t==null?void 0:t.subStepTitle)==null?void 0:a.call(t,...s);return o?this.testFixture.step(i,()=>this.testFixture.step(o,()=>e.apply(this,s)),{box:!0}):this.testFixture.step(i,()=>e.apply(this,s),{box:!0})}}}const he=new WeakMap;class le extends Ke{constructor({page:e,testFixture:t}){var a;const s=(a=he.get(e))!=null?a:new Ze({page:e,testFixture:t});he.set(e,s);const i=new ae({type:"webserver",page:e,window:s});super({socket:i,window:s,logger:S,autoInit:!1}),this.window=s,this.page=e,this.testFixture=t;let o=!1;this.on("queue",r=>{o||(o=!0,r.type==="concurrent"?this.logger.log(`Entered ${r.name}. Please wait until a slot becomes available.`):this.logger.log("All devices are currently in use. Please wait until requested device becomes available.")),r.position>0&&(r.type==="concurrent"?this.logger.log(`Position in ${r.name}: ${r.position}`):this.logger.log(`Position in queue: ${r.position}`))}),this.on("session",()=>{o&&(o=!1)})}async init(){return this.testFixture.step("Initialize client",async()=>{await this.window.init(),await super.init()})}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 ce({config:e,page:this.page,window:this.window,path:t.path,token:t.token,device:this.device,app:this.app,testFixture:this.testFixture}),this.session}}class et{constructor(e){var t;this.queueStart=null,this.queueEnd=null,this.baseURL="https://appetize.io",this.sessionDebugInfo={playedActions:[],videoFrames:[],audioFrames:[],debugLogs:[]},this.page=e.page,this.testFixture=e.testFixture,this.config={...e.config,buildId:(t=e.config.buildId)!=null?t:e.config.publicKey,...e.config.publicKey?{publicKey:e.config.publicKey}:{}},e.baseURL&&(this.baseURL=e.baseURL)}get queueTime(){var e;return this.queueStart?((e=this.queueEnd)!=null?e:Date.now())-this.queueStart:null}async init(){var s;const e={};for(const i in this.config)switch(i){case"device":case"osVersion":case"scale":case"orientation":e[i]=this.config[i];break}const t=await this.page.goto(`${this.baseURL}/embed/${this.config.buildId}?${Ie(e)}`);if((t==null?void 0:t.status())===404){const i=this.config.publicKey?"publicKey":"buildId";throw new Error(`App not found for ${i} "${(s=this.config.publicKey)!=null?s:this.config.buildId}"`)}this.client=new le({page:this.page,testFixture:this.testFixture}),await this.client.init()}async start(e){this.queueStart=null,this.queueEnd=null,this.client.on("queue",()=>{this.queueStart||(this.queueStart=Date.now())}),this.client.on("queueEnd",()=>{this.queueStart&&(this.queueEnd=Date.now())});const t=async i=>{i!=null&&i.embed&&await this.page.setViewportSize({width:i.embed.width+8,height:i.embed.height+8})};this.client.on("deviceInfo",t),await this.client.waitUntilReady(),this.client.device&&t(this.client.device);const s=await Te(()=>this.client.startSession(e.config),{retries:5,timeout:3e4,predicate:(i,o)=>i instanceof Error&&i.message.match(/too many requests/)?(console.warn(`Too many session requests. Retrying in 30 seconds... (attempt #${o})`),!0):!1});return this.config=s.config,this.requestKeyFrame(),s.config.debug===!0&&s.on("log",i=>{this.sessionDebugInfo.debugLogs.push(i.message)}),s.on("playbackFoundAndSent",i=>{this.sessionDebugInfo.playedActions.push(i)}),s.on("playbackError",i=>{this.sessionDebugInfo.playedActions.push(i)}),s.on("video",i=>{this.sessionDebugInfo.videoFrames.push(i)}),s.on("audio",i=>{this.sessionDebugInfo.audioFrames.push(i)}),s.on("end",()=>{this.session=void 0}),this.session=s,s}onTestStart(){this.clearSessionDebugInfo(),this.requestKeyFrame()}clearSessionDebugInfo(){this.sessionDebugInfo.playedActions=[],this.sessionDebugInfo.videoFrames=[],this.sessionDebugInfo.audioFrames=[],this.sessionDebugInfo.debugLogs=[]}requestKeyFrame(){this.session&&this.testFixture.step("",async()=>{var e;return(e=this.session)==null?void 0:e.socket.send("requestKeyFrame").catch(()=>{})})}}let R=null,Y=null;const N=g.test.extend({config:[async({_useConfig:n},e,t)=>{const s={...t.project.use.config,...n,autoplay:!1};"publicKey"in s&&!!s.publicKey&&("buildId"in s&&!!s.buildId?(S.warn(`Both "buildId" ("${s.buildId}") and "publicKey" ("${s.publicKey}") were defined in the test config. Using buildId.`),s.publicKey=s.buildId):s.buildId=s.publicKey),await e(s)},{auto:!0}],async page({appetizePage:n},e){await e(n.page)},async appetizePage({context:n,config:e,baseURL:t},s){if(R){const{session:i,page:o}=R;if(i){let a=!1;if(Y){for(const r in e)if(JSON.stringify(Y[r])!==JSON.stringify(e[r])){a=!0;break}}else a=!0;a&&(i&&await i.end().catch(()=>{}),await o.close(),R=null)}}if(!R){if(!e.buildId)throw new Error('Appetize buildId not set. Make sure you have set it with `test.use({ config: { buildId: "..." } })` or in your Playwright config file.');R=new et({page:await n.newPage(),testFixture:P,config:e,baseURL:t}),await R.init()}Y=e,await s(R)},async session({appetizePage:n,config:e,_doSetupAndTeardown:t},s){let i=n.session;i||(i=await P.step("Start Appetize session",async()=>{if(await n.start({config:e}),n.queueTime&&P.info().annotations.push({type:"queueTime",description:`${n.queueTime}ms`}),!n.session)throw new Error("Appetize session failed to start");return n.session},{box:!0}),P.info().annotations.push({type:"Appetize Documentation",description:"https://docs.appetize.io/javascript-sdk/playwright"})),await P.step(`${i.path}/client?sessionToken=${i.token}`,()=>{}),i.testFixture=P,await s(i)},async client({appetizePage:n},e){await e(n.client)},_useConfig:[{},{option:!0}],_autoSnapshotSuffix:[async({},n,e)=>{e.snapshotSuffix="",await n()},{auto:!0}],_doSetupAndTeardown:[async({appetizePage:n},e,t)=>{S.clearLogHistory(),n&&n.onTestStart(),await e();try{await we({appetizePage:n,testInfo:t})}catch(s){S.error("Failed to save attachments",s)}t.status==="timedOut"&&n.queueTime&&S.error("Test timed out while in queue for a device. You may increase your test timeout to account for higher queue times.");try{ye(t)}catch{}},{auto:!0}],context:[async({_browserContext:n,video:e,contextOptions:t},s)=>{e&&e!=="off"&&S.warn.once("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&&S.warn.once("contextOptions are not supported with @appetize/playwright"),await s(n)},{scope:"test"}],_browserContext:[async({browser:n},e)=>{const t=await n.newContext();await e(t),await t.close()},{scope:"worker"}]}),ue=n=>{const e=n.use;return t=>{const{config:s,...i}=t;return e({...i,_useConfig:s})}},pe=n=>{const e=n.afterEach;return t=>(e(async({appetizePage:s},i)=>{if(s)try{await we({appetizePage:s,testInfo:i})}catch(o){S.error("Failed to save attachments",o)}}),e(t))},de=n=>{const e=n.extend;return t=>{const s=e(t);return s.afterEach=pe(s).bind(s),s.use=ue(s).bind(s),s.extend=de(s).bind(s),s}};Object.assign(N,{use:ue(N),afterEach:pe(N),extend:de(N),setup(n){return{}.__APPETIZE__SETUP_WARNED||S.warn("test.setup() is deprecated and will be removed in a future release. Use test.use({ config: {...} }) instead"),P.use({config:n})}});const P=N,fe=new WeakMap;async function we(n){const{appetizePage:e,testInfo:t}=n,s=e.session;if(!(t.status==="failed"||t.status==="timedOut"||t.status==="interrupted")||fe.get(t.fn))return;fe.set(t.fn,!0);const o=C.default.join(ke.default.tmpdir(),`appetize-playwright-${t.testId}-${t.workerIndex}`),a=async()=>{v.default.existsSync(o)&&await v.default.promises.rm(o,{recursive:!0,force:!0}).catch(()=>{})};try{await a(),await v.default.promises.mkdir(o);const r=e.sessionDebugInfo.playedActions,c=async()=>{try{if(s){const l=await s.screenshot("buffer"),w=C.default.join(o,"screenshot.png");await v.default.promises.writeFile(w,Buffer.from(l.data)),await t.attach("screenshot",{path:w,contentType:"image/png"})}}catch(l){S.error("Failed to attach screenshot.png",l instanceof Error?l.message:void 0)}},h=async()=>{try{const l=r.map(q=>{if("screenshot"in q){const{screenshot:Q,...U}=q;return U}return q});if(!l.length)return;const w=JSON.stringify(l,null,2),m=C.default.join(o,"actions.json");await v.default.promises.writeFile(m,w),await t.attach("actions",{path:m,contentType:"application/json"})}catch(l){S.error("Failed to attach actions.json",l instanceof Error?l.message:void 0)}},u=async()=>{try{const{videoFrames:l}=e.sessionDebugInfo;if(l.length===0||l.some(U=>U.codec!=="h264"))return;const w="video",m=new ve.default({mode:w,fps:15}),q=await new Promise((U,me)=>{const ge=setTimeout(()=>{me(new Error("Timed out muxing session video"))},3e4),X=new xe.Readable({objectMode:!0,read(){}}),st=Buffer.concat(l.map(L=>Buffer.from(L.buffer)));X.push({video:st}),X.push(null);let G=Buffer.from([]);X.pipe(m.createStream()).on("data",L=>{G=Buffer.concat([G,L])}).on("error",L=>{clearTimeout(ge),me(L)}).on("end",()=>{clearTimeout(ge),U(G)})}),Q=C.default.join(o,"video.mp4");await v.default.promises.writeFile(Q,q),await t.attach("video.mp4",{path:Q,contentType:"video/mp4"})}catch(l){S.error("Failed to attach video.mp4",l instanceof Error?l.message:void 0)}},p=async()=>{if(!!S.logHistory.length)try{const l=`${S.logHistory.map(m=>`[${m.method}] ${JSON.stringify(m.data).slice(2,-2)}`).join(`
`)}`,w=C.default.join(o,"sdk-logs.txt");await v.default.promises.writeFile(w,l),await t.attach("sdk-logs",{path:w,contentType:"application/text"})}catch(l){S.error("Failed to attach sdk-logs.txt",l)}},y=async()=>{const{debugLogs:l}=e.sessionDebugInfo;if(l.length>0)try{const w=l.join(""),m=C.default.join(o,"debug-logs.txt");await v.default.promises.writeFile(m,w),await t.attach("debug-logs",{path:m,contentType:"application/text"})}catch(w){S.error("Failed to attach debug-logs.txt",w)}},b=async()=>{try{if(e.session){const l=C.default.join(o,"session.json"),w=JSON.stringify({path:e.session.path,token:e.session.token,config:e.session.config},null,2);await v.default.promises.writeFile(l,w),await t.attach("session",{path:l,contentType:"application/json"})}}catch(l){S.error("Failed to attach session.json",l)}};await Promise.all([c(),h(),u(),y(),b()]),await p()}finally{await a()}}function ye(n){const e=n.steps||n._steps;!e||e.forEach((t,s)=>{t.title===""&&e.splice(s,1),ye(t)})}var tt=Object.freeze(Object.defineProperty({__proto__:null},Symbol.toStringTag,{value:"Module"}));Object.defineProperty(d,"expect",{enumerable:!0,get:function(){return g.expect}}),d.InternalRecorderAPI=tt,d.PlaywrightClient=le,d.PlaywrightSession=ce,d.test=P,Object.defineProperties(d,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
//# sourceMappingURL=index.umd.js.map
import { Page } from '@playwright/test';
import { SessionConfig } from '../../core/session';
import { PlaywrightClient } from './client';
import { PlaywrightSession } from './session';
import { PlaywrightSession, PlaywrightSessionConfig } from './session';
import { PlayActionResult, PlayActionErrorResponse } from '../../core/api/types/recorder';

@@ -14,3 +14,3 @@ import { AppetizeTestFixture } from './fixture';

queueEnd: number | null;
config: SessionConfig;
config: PlaywrightSessionConfig;
baseURL: string;

@@ -32,3 +32,3 @@ sessionDebugInfo: {

testFixture: AppetizeTestFixture;
config: SessionConfig;
config: PlaywrightSessionConfig;
baseURL?: string;

@@ -35,0 +35,0 @@ });

@@ -18,2 +18,3 @@ import { Page } from '@playwright/test';

publicKey?: string;
buildId?: string;
debug?: boolean;

@@ -34,3 +35,2 @@ audio?: boolean;

enableAdb?: boolean;
buildId?: string;
grantPermissions?: boolean;

@@ -37,0 +37,0 @@ hidePasswords?: boolean;

import { PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestType, BrowserContext } from '@playwright/test';
import { SessionConfig } from '../../core/session';
import { PlaywrightClient } from './client';
import './expect';
import { PlaywrightSession } from './session';
import { PlaywrightSession, PlaywrightSessionConfig } from './session';
import { AppetizePage } from './appetize-page';
export interface AppetizeTestOptions extends PlaywrightTestOptions {
config: Partial<SessionConfig>;
config: Partial<PlaywrightSessionConfig>;
}

@@ -10,0 +9,0 @@ interface TestArgs extends PlaywrightTestArgs, AppetizeTestOptions {

@@ -18,2 +18,6 @@ import { Page } from '@playwright/test';

}
export interface PlaywrightSessionConfig extends SessionConfig {
buildId?: string;
publicKey?: string;
}
export declare class PlaywrightSession extends Session {

@@ -20,0 +24,0 @@ page: Page;

{
"name": "@appetize/playwright",
"version": "1.4.0-beta.1",
"version": "1.4.0",
"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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc