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

@appetize/playwright

Package Overview
Dependencies
Maintainers
4
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 0.3.1 to 0.3.2

4

dist/core/session/index.d.ts

@@ -47,3 +47,3 @@ /// <reference types="node" />

setLanguage(language: string): Promise<void>;
setLocation(latitude: string | number, longitude: string | number): Promise<void>;
setLocation(latitude: number, longitude: number): Promise<void>;
openUrl(url: string): Promise<void>;

@@ -150,3 +150,3 @@ shake(): Promise<void>;

locale?: string;
location?: string[];
location?: number[];
loopback?: boolean;

@@ -153,0 +153,0 @@ noVideo?: boolean;

@@ -162,3 +162,3 @@ import { EventEmitter } from "events";

super(message);
this.name = this.constructor.name;
this.name = "Error";
this.isOperational = true;

@@ -843,3 +843,8 @@ Error.captureStackTrace(this, this.constructor);

try {
const location = [latitude.toString(), longitude.toString()];
if (typeof latitude !== "number" || typeof longitude !== "number") {
throw new OperationalError(
`setLocation requires latitude and longitude to be numbers`
);
}
const location = [latitude, longitude];
this.config.location = location;

@@ -1259,3 +1264,3 @@ return await this.socket.send("setLocation", {

}
const version = "0.3.1";
const version = "0.3.2";
const VERSION = version;

@@ -1262,0 +1267,0 @@ class HeadfulClient extends Client {

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

(function(p,w){typeof exports=="object"&&typeof module!="undefined"?w(exports,require("events"),require("@playwright/test"),require("fs")):typeof define=="function"&&define.amd?define(["exports","events","@playwright/test","fs"],w):(p=typeof globalThis!="undefined"?globalThis:p||self,w(p.playwright={},p.events,p.test$1,p.fs))})(this,function(p,w,R,q){"use strict";function j(n){return n&&typeof n=="object"&&"default"in n?n:{default:n}}var $=j(q);async function H(n,{retries:e=3,timeout:t=1e3,predicate:s=()=>!0}){for(let i=1;i<=e;i++)try{return await n()}catch(r){if(i===e||!s(r,i))throw r;await new Promise(o=>setTimeout(o,t))}throw null}function U(n,e){switch(n){case"accountQueuedPosition":case"accountQueue":return{type:"queue",value:{type:"account",position:e.position}};case"sessionQueuedPosition":case"queue":return{type:"queue",value:{type:"session",position:e.position}};case"debug":return{type:"log",value:e};case"interceptResponse":return{type:"network",value:{type:"response",...e}};case"interceptRequest":return{type:"network",value:{type:"request",...e}};case"interceptError":return{type:"network",value:{type:"error",...e}};case"userError":return{type:"error",value:e};case"recordedEvent":return e.type==="scrollToElement"?null:{type:"action",value:e};case"userInteractionReceived":return{type:"interaction",value:e};case"countdownWarning":return{type:"inactivityWarning",value:e};case"h264Data":return{type:"video",value:{...e,codec:"h264"}};case"frameData":return{type:"video",value:{...e,codec:"jpeg"}};case"audioData":return{type:"audio",value:{...e,codec:"aac"}};case"deleteEvent":return null;case"newSession":return null}}function D(n){return typeof n=="object"&&n!==null?Object.entries(n).reduce((e,[t,s])=>{const i=D(s);return i!=null&&(e[t]=i),e},{}):n}function J(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 h(n,e){n instanceof f&&J(n,e)}class f extends Error{constructor(e){super(e),this.name=this.constructor.name,this.isOperational=!0,Error.captureStackTrace(this,this.constructor)}}class Y extends f{constructor(e){var i,r,o;const t=(i=e.playback)==null?void 0:i.event;let s=(r=e.message)!=null?r:e.errorId;switch(e.errorId){case"notFound":if(t&&"element"in t){let a=!1;const c=typeof t.element=="object"?{...t.element}:t.element;typeof c=="object"&&"allowMultipleMatches"in c&&(a=!!c.allowMultipleMatches,delete c.allowMultipleMatches),s=`No element${a?"s":""} found for selector
${JSON.stringify(c,null," ")}`}break;case"ambiguousMatch":{const a=(o=e.matchedElements)==null?void 0:o.map(({frame:c,address:l,frameInWindow:u,bounds:d,windowType:g,...A})=>A);a&&(s=`Selector matched more than 1 element. Please specify more attributes to match a single element, or provide a \`matchIndex\` attribute to choose an element below.
(function(f,w){typeof exports=="object"&&typeof module!="undefined"?w(exports,require("events"),require("@playwright/test"),require("fs")):typeof define=="function"&&define.amd?define(["exports","events","@playwright/test","fs"],w):(f=typeof globalThis!="undefined"?globalThis:f||self,w(f.playwright={},f.events,f.test$1,f.fs))})(this,function(f,w,R,V){"use strict";function j(n){return n&&typeof n=="object"&&"default"in n?n:{default:n}}var $=j(V);async function H(n,{retries:e=3,timeout:t=1e3,predicate:s=()=>!0}){for(let i=1;i<=e;i++)try{return await n()}catch(r){if(i===e||!s(r,i))throw r;await new Promise(o=>setTimeout(o,t))}throw null}function U(n,e){switch(n){case"accountQueuedPosition":case"accountQueue":return{type:"queue",value:{type:"account",position:e.position}};case"sessionQueuedPosition":case"queue":return{type:"queue",value:{type:"session",position:e.position}};case"debug":return{type:"log",value:e};case"interceptResponse":return{type:"network",value:{type:"response",...e}};case"interceptRequest":return{type:"network",value:{type:"request",...e}};case"interceptError":return{type:"network",value:{type:"error",...e}};case"userError":return{type:"error",value:e};case"recordedEvent":return e.type==="scrollToElement"?null:{type:"action",value:e};case"userInteractionReceived":return{type:"interaction",value:e};case"countdownWarning":return{type:"inactivityWarning",value:e};case"h264Data":return{type:"video",value:{...e,codec:"h264"}};case"frameData":return{type:"video",value:{...e,codec:"jpeg"}};case"audioData":return{type:"audio",value:{...e,codec:"aac"}};case"deleteEvent":return null;case"newSession":return null}}function D(n){return typeof n=="object"&&n!==null?Object.entries(n).reduce((e,[t,s])=>{const i=D(s);return i!=null&&(e[t]=i),e},{}):n}function J(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 u(n,e){n instanceof p&&J(n,e)}class p extends Error{constructor(e){super(e),this.name="Error",this.isOperational=!0,Error.captureStackTrace(this,this.constructor)}}class Y extends p{constructor(e){var i,r,o;const t=(i=e.playback)==null?void 0:i.event;let s=(r=e.message)!=null?r:e.errorId;switch(e.errorId){case"notFound":if(t&&"element"in t){let a=!1;const c=typeof t.element=="object"?{...t.element}:t.element;typeof c=="object"&&"allowMultipleMatches"in c&&(a=!!c.allowMultipleMatches,delete c.allowMultipleMatches),s=`No element${a?"s":""} found for selector
${JSON.stringify(c,null," ")}`}break;case"ambiguousMatch":{const a=(o=e.matchedElements)==null?void 0:o.map(({frame:c,address:l,frameInWindow:h,bounds:d,windowType:g,...A})=>A);a&&(s=`Selector matched more than 1 element. Please specify more attributes to match a single element, or provide a \`matchIndex\` attribute to choose an element below.
${B(a)}`);break}}super(s),this.details=e}}class S extends f{}class _ extends f{constructor(e){super(`App Recorder must be enabled to use ${e}. Please set "record" to true in the config.`)}}function B(n){return n.map((e,t)=>`${t}: ${JSON.stringify(e,null,2)}`).join(`
${B(a)}`);break}}super(s),this.details=e}}class S extends p{}class _ extends p{constructor(e){super(`App Recorder must be enabled to use ${e}. Please set "record" to true in the config.`)}}function B(n){return n.map((e,t)=>`${t}: ${JSON.stringify(e,null,2)}`).join(`
`)}async function F(n,e=5e3){const t=Date.now();for(;;)try{return await n()}catch(s){if(await new Promise(i=>setTimeout(i,100)),e!==null&&Date.now()-t>e)throw s}}async function T(n){return new Promise(e=>setTimeout(e,n))}async function b(n,e,t){const s=typeof t=="function"?{}:t,i=typeof t=="function"?t:t==null?void 0:t.predicate,r=typeof(s==null?void 0:s.timeout)!="undefined"?s.timeout:1e4;return new Promise((o,a)=>{const c=l=>{(!i||i(l))&&(n.off(e,c),o(l))};n.on(e,c),r!==null&&setTimeout(()=>{n.off(e,c),a(new S(`Timeout ${r}ms exceeded while waiting for event "${e}"`))},r)})}const N=[")","!","@","#","$","%","^","&","*","("],K={47:"?",44:"<",45:"_",46:">",91:"{",92:"|",93:"}",96:"~",59:":",61:"+",39:'"'},Q={191:"?",188:"<",189:"_",190:">",219:"{",220:"|",221:"}",192:"~",186:":",187:"+",222:'"'};function X(n){let e;for(const s in K)if(n===K[s])return e={key:String.fromCharCode(s),shiftKey:"true"},e;const t=N.indexOf(n);return t>-1?e={key:String.fromCharCode(t+48).toLowerCase(),shiftKey:!0}:n!==n.toLowerCase()?e={key:n.toLowerCase(),shiftKey:!0}:e={key:n,shiftKey:!1},e}function C(n){return n.type==="keypress"&&n.which&&n.key?n.which>=65&&n.which<=90?n.shiftKey?n.key:n.key.toLowerCase():n.shiftKey?n.which>=48&&n.which<=57?N[n.which-48]:Q[n.which]:n.key:null}function G(n){switch(n){case"HOME":return"home";case"VOLUME_UP":return"volumeUp";case"VOLUME_DOWN":return"volumeDown"}return n}class W{constructor(e,{duration:t=500,...s}){var i,r;this.path=[],this.easing=o=>o,this.session=e,this.element=s.element,s!=null&&s.easing&&(typeof s.easing=="string"?this.easing=Z[s.easing]:this.easing=s.easing),this.steps=Math.floor(t/16),this.stepDuration=t/this.steps,this.move((i=s==null?void 0:s.x)!=null?i:0,(r=s==null?void 0:s.y)!=null?r:0)}move(e,t){var c;const s=(c=this.previousCommand(this.path,"move"))!=null?c:{x:0,y:0},i=this.parseValue(s.x,"x"),r=this.parseValue(s.y,"y"),o=this.parseValue(e,"x"),a=this.parseValue(t,"y");return this.path.push({type:"move",x:i+o,y:r+a}),this}wait(e){return this.path.push({type:"wait",value:e}),this}toAction(){const e=this.interpolatePath();return{type:"swipe",xPos:e.map(t=>t.x.toString()),yPos:e.map(t=>t.y.toString()),ts:e.map((t,s)=>this.easing(s*(this.stepDuration/1e3))),element:D(this.element)}}interpolatePath(){const e=[];for(let t=0;t<this.path.length-1;t++){const i=this.previousCommand(this.path.slice(0,t+1),"move"),r=this.path[t+1];if(i){if(r.type==="move"){const o=this.parseValue(r.x,"x"),a=this.parseValue(r.y,"y"),c=Math.floor(this.steps/this.path.length-1);if(c<1)e.push({x:o,y:a});else{const l=(o-this.parseValue(i.x,"x"))/c,u=(a-this.parseValue(i.y,"y"))/c;for(let d=0;d<=c;d++){const g=this.parseValue(i.x,"x")+l*d,A=this.parseValue(i.y,"y")+u*d;e.push({x:g,y:A})}}}else if(r.type==="wait"){const o=Math.floor(r.value/this.stepDuration);for(let a=0;a<=o;a++)e.push({x:i.x,y:i.y})}}}return e.length&&(e.unshift(e[0]),e.push(e[e.length-1])),e}previousCommand(e,t){return e.slice().reverse().find(s=>s.type===t)}parseValue(e,t){var o;const s=(o=this.session.deviceInfo.screen.devicePixelRatio)!=null?o:1,i=this.session.deviceInfo.screen.width*s,r=this.session.deviceInfo.screen.height*s;if(typeof e=="number")return e*s;if(e.endsWith("px"))return parseInt(e)*s;if(e.endsWith("%")){const a=parseInt(e)/100,c=this.element?this.getElementBounds(this.element):{width:i,height:r};return a*(t==="x"?c.width:c.height)}if(parseInt(e)===0)return 0;throw new Error(`Invalid value: ${e}. Must be a number or string that ends with 'px' or '%'.`)}getElementBounds(e){return e.bounds?{x:e.bounds.left,y:e.bounds.top,width:e.bounds.right-e.bounds.left,height:e.bounds.bottom-e.bounds.top}:{x:e.frameInWindow.x,y:e.frameInWindow.y,width:e.frameInWindow.width,height:e.frameInWindow.height}}}const Z={linear:n=>n,easeIn:n=>n*n,easeOut:n=>n*(2-n),easeInOut:n=>n<.5?2*n*n:-1+(4-2*n)*n};function ee(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 te(n,e){const t=ee(n),s=btoa(t);return`data:${e};base64,`+s}class se extends w.EventEmitter{constructor({socket:e,config:t,deviceInfo:s}){super(),this.actionHistory=[],this.isEndingManually=!1,this.countdownWarning=!1,this.debug={printActions:({xdoc:r=!1}={})=>{console.log(this.actionHistory.reduce((o,{action:a})=>r?`let actions = ${JSON.stringify(this.actionHistory.map(c=>c.action),null,2)}
`)}async function F(n,e=5e3){const t=Date.now();for(;;)try{return await n()}catch(s){if(await new Promise(i=>setTimeout(i,100)),e!==null&&Date.now()-t>e)throw s}}async function T(n){return new Promise(e=>setTimeout(e,n))}async function b(n,e,t){const s=typeof t=="function"?{}:t,i=typeof t=="function"?t:t==null?void 0:t.predicate,r=typeof(s==null?void 0:s.timeout)!="undefined"?s.timeout:1e4;return new Promise((o,a)=>{const c=l=>{(!i||i(l))&&(n.off(e,c),o(l))};n.on(e,c),r!==null&&setTimeout(()=>{n.off(e,c),a(new S(`Timeout ${r}ms exceeded while waiting for event "${e}"`))},r)})}const N=[")","!","@","#","$","%","^","&","*","("],K={47:"?",44:"<",45:"_",46:">",91:"{",92:"|",93:"}",96:"~",59:":",61:"+",39:'"'},Q={191:"?",188:"<",189:"_",190:">",219:"{",220:"|",221:"}",192:"~",186:":",187:"+",222:'"'};function X(n){let e;for(const s in K)if(n===K[s])return e={key:String.fromCharCode(s),shiftKey:"true"},e;const t=N.indexOf(n);return t>-1?e={key:String.fromCharCode(t+48).toLowerCase(),shiftKey:!0}:n!==n.toLowerCase()?e={key:n.toLowerCase(),shiftKey:!0}:e={key:n,shiftKey:!1},e}function C(n){return n.type==="keypress"&&n.which&&n.key?n.which>=65&&n.which<=90?n.shiftKey?n.key:n.key.toLowerCase():n.shiftKey?n.which>=48&&n.which<=57?N[n.which-48]:Q[n.which]:n.key:null}function G(n){switch(n){case"HOME":return"home";case"VOLUME_UP":return"volumeUp";case"VOLUME_DOWN":return"volumeDown"}return n}class W{constructor(e,{duration:t=500,...s}){var i,r;this.path=[],this.easing=o=>o,this.session=e,this.element=s.element,s!=null&&s.easing&&(typeof s.easing=="string"?this.easing=Z[s.easing]:this.easing=s.easing),this.steps=Math.floor(t/16),this.stepDuration=t/this.steps,this.move((i=s==null?void 0:s.x)!=null?i:0,(r=s==null?void 0:s.y)!=null?r:0)}move(e,t){var c;const s=(c=this.previousCommand(this.path,"move"))!=null?c:{x:0,y:0},i=this.parseValue(s.x,"x"),r=this.parseValue(s.y,"y"),o=this.parseValue(e,"x"),a=this.parseValue(t,"y");return this.path.push({type:"move",x:i+o,y:r+a}),this}wait(e){return this.path.push({type:"wait",value:e}),this}toAction(){const e=this.interpolatePath();return{type:"swipe",xPos:e.map(t=>t.x.toString()),yPos:e.map(t=>t.y.toString()),ts:e.map((t,s)=>this.easing(s*(this.stepDuration/1e3))),element:D(this.element)}}interpolatePath(){const e=[];for(let t=0;t<this.path.length-1;t++){const i=this.previousCommand(this.path.slice(0,t+1),"move"),r=this.path[t+1];if(i){if(r.type==="move"){const o=this.parseValue(r.x,"x"),a=this.parseValue(r.y,"y"),c=Math.floor(this.steps/this.path.length-1);if(c<1)e.push({x:o,y:a});else{const l=(o-this.parseValue(i.x,"x"))/c,h=(a-this.parseValue(i.y,"y"))/c;for(let d=0;d<=c;d++){const g=this.parseValue(i.x,"x")+l*d,A=this.parseValue(i.y,"y")+h*d;e.push({x:g,y:A})}}}else if(r.type==="wait"){const o=Math.floor(r.value/this.stepDuration);for(let a=0;a<=o;a++)e.push({x:i.x,y:i.y})}}}return e.length&&(e.unshift(e[0]),e.push(e[e.length-1])),e}previousCommand(e,t){return e.slice().reverse().find(s=>s.type===t)}parseValue(e,t){var o;const s=(o=this.session.deviceInfo.screen.devicePixelRatio)!=null?o:1,i=this.session.deviceInfo.screen.width*s,r=this.session.deviceInfo.screen.height*s;if(typeof e=="number")return e*s;if(e.endsWith("px"))return parseInt(e)*s;if(e.endsWith("%")){const a=parseInt(e)/100,c=this.element?this.getElementBounds(this.element):{width:i,height:r};return a*(t==="x"?c.width:c.height)}if(parseInt(e)===0)return 0;throw new Error(`Invalid value: ${e}. Must be a number or string that ends with 'px' or '%'.`)}getElementBounds(e){return e.bounds?{x:e.bounds.left,y:e.bounds.top,width:e.bounds.right-e.bounds.left,height:e.bounds.bottom-e.bounds.top}:{x:e.frameInWindow.x,y:e.frameInWindow.y,width:e.frameInWindow.width,height:e.frameInWindow.height}}}const Z={linear:n=>n,easeIn:n=>n*n,easeOut:n=>n*(2-n),easeInOut:n=>n<.5?2*n*n:-1+(4-2*n)*n};function ee(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 te(n,e){const t=ee(n),s=btoa(t);return`data:${e};base64,`+s}class se extends w.EventEmitter{constructor({socket:e,config:t,deviceInfo:s}){super(),this.actionHistory=[],this.isEndingManually=!1,this.countdownWarning=!1,this.debug={printActions:({xdoc:r=!1}={})=>{console.log(this.actionHistory.reduce((o,{action:a})=>r?`let actions = ${JSON.stringify(this.actionHistory.map(c=>c.action),null,2)}

@@ -30,9 +30,9 @@ let nextAction = actions.shift()

startSession({ record: true })`),super.on(e,t)}async waitForEvent(e,t){try{return await b(this,e,t)}catch(s){throw h(s,this.waitForEvent),s}}async end(){this.isEndingManually=!0,await this.socket.disconnect()}async getNetworkInspectorUrl(){try{if(this.config.proxy!=="intercept")throw new f(`Session must be configured to use a proxy in order to get the network inspector URL. You can do this with
startSession({ record: true })`),super.on(e,t)}async waitForEvent(e,t){try{return await b(this,e,t)}catch(s){throw u(s,this.waitForEvent),s}}async end(){this.isEndingManually=!0,await this.socket.disconnect()}async getNetworkInspectorUrl(){try{if(this.config.proxy!=="intercept")throw new p(`Session must be configured to use a proxy in order to get the network inspector URL. You can do this with
startSession({ proxy: "intercept" })`);return this.networkInspectorUrl?this.networkInspectorUrl:F(()=>{if(this.networkInspectorUrl)return this.networkInspectorUrl;throw new S("Timed out after 60000ms waiting for network inspector URL")},6e4)}catch(e){throw h(e,this.getNetworkInspectorUrl),e}}async getAdbInfo(){try{if(this.config.platform&&this.config.platform!=="android")throw new f("Session must be connected to an Android device to use adb");if(!this.config.enableAdb)throw new f(`Session must be configured to use adb in order to get the adb command. You can do this with
startSession({ proxy: "intercept" })`);return this.networkInspectorUrl?this.networkInspectorUrl:F(()=>{if(this.networkInspectorUrl)return this.networkInspectorUrl;throw new S("Timed out after 60000ms waiting for network inspector URL")},6e4)}catch(e){throw u(e,this.getNetworkInspectorUrl),e}}async getAdbInfo(){try{if(this.config.platform&&this.config.platform!=="android")throw new p("Session must be connected to an Android device to use adb");if(!this.config.enableAdb)throw new p(`Session must be configured to use adb in order to get the adb command. You can do this with
startSession({ enableAdb: true })`);return this.adbConnectionInfo?this.adbConnectionInfo:F(()=>{if(this.adbConnectionInfo)return this.adbConnectionInfo;throw new S("Timed out after 60000ms waiting for adb connection")},6e4)}catch(e){throw h(e,this.getAdbInfo),e}}async rotate(e){try{const[t]=await Promise.all([this.waitForEvent("orientationChanged"),this.socket.send("userInteraction",{type:"keypress",key:e==="left"?"rotateLeft":"rotateRight",timeStamp:Date.now()})]);return t}catch(t){throw h(t,this.rotate),t}}async screenshot(e="buffer"){try{this.socket.send("getScreenshot");const t=await b(this.socket,"screenshot",{timeout:6e4});if(!t.success)throw new f("Screenshot failed");return{data:e==="buffer"?(r=>typeof window=="undefined"?Buffer.from(r):r)(t.data):te(new Uint8Array(t.data),t.mimeType),mimeType:t.mimeType}}catch(t){throw h(t,this.screenshot),t}}async heartbeat(){try{return await this.socket.send("heartbeat")}catch(e){throw h(e,this.heartbeat),e}}async type(e){try{this.config.platform==="ios"&&await T(1e3);const t=[...e].map(X);if(this.config.record)return await this.playAction({type:"keypress",keypress:{type:"keypressArray",shiftKeyArray:t.map(s=>s.shiftKey),keyArray:t.map(s=>s.key),value:e}});await Promise.all([this.socket.send("userInteraction",{type:"keypressArray",shiftKeyArray:t.map(s=>s.shiftKey),keyArray:t.map(s=>s.key),value:e}),this.waitForEvent("interaction",{predicate:s=>s.type==="keypressArray"})])}catch(t){throw h(t,this.type),t}}async keypress(e,t){var s,i,r,o;try{if(e==="ANDROID_KEYCODE_MENU")return await this.socket.send("androidKeycodeMenu");e=G(e);const a=Date.now();if(this.config.record)return this.playAction({type:"keypress",keypress:{type:"keypress",key:e,timeStamp:a,altKey:(s=t==null?void 0:t.alt)!=null?s:!1,shiftKey:(i=t==null?void 0:t.shift)!=null?i:!1}});{const[c]=await Promise.all([this.waitForEvent("interaction",{predicate:l=>l.type==="keypress"&&l.timeStamp===a}),this.socket.send("userInteraction",{type:"keypress",key:e,timeStamp:a,altKey:(r=t==null?void 0:t.alt)!=null?r:!1,shiftKey:(o=t==null?void 0:t.shift)!=null?o:!1})]);return c}}catch(a){throw h(a,this.keypress),a}}async setLanguage(e){try{return this.config.language=e,await this.socket.send("setLanguage",{language:e,timeStamp:Date.now()})}catch(t){throw h(t,this.setLanguage),t}}async setLocation(e,t){try{const s=[e.toString(),t.toString()];return this.config.location=s,await this.socket.send("setLocation",{location:s,timeStamp:Date.now()})}catch(s){throw h(s,this.setLocation),s}}async openUrl(e){try{return await this.socket.send("openUrl",{url:e,timeStamp:Date.now()})}catch(t){throw h(t,this.openUrl),t}}async shake(){try{return await this.socket.send("shakeDevice")}catch(e){throw h(e,this.swipe),e}}async biometry({match:e}){try{return await this.socket.send(e?"biometryMatch":"biometryNoMatch")}catch(t){throw h(t,this.biometry),t}}async allowInteractions(e){try{return await this.socket.send(e?"enableInteractions":"disableInteractions")}catch(t){throw h(t,this.allowInteractions),t}}async restartApp(){try{this.socket.send("restartApp");const{platform:e}=this.config;e==="ios"?await this.waitForEvent("appLaunch",{timeout:6e4}):await T(1e3)}catch(e){throw h(e,this.restartApp),e}}async reinstallApp(){try{this.socket.send("reinstallApp"),await this.waitForEvent("appLaunch",{timeout:6e4})}catch(e){throw h(e,this.reinstallApp),e}}async adbShellCommand(e){if(this.config.platform!=="android")throw new Error("adbShellCommand is only available on Android devices");try{return await this.socket.send("adbShellCommand",{command:e,timeStamp:Date.now()})}catch(t){throw h(t,this.adbShellCommand),t}}async playAction(e,t={}){try{if(!this.config.record)throw new _("playAction()");return await this.playActions([e],t).then(s=>s[0])}catch(s){throw h(s,this.playAction),s}}async playActions(e,t={}){try{const{timeout:s=3e4,strictMatch:i}=t,r=[];if(!this.config.record)throw new _("playActions()");for(const o of e){const{id:a,...c}=o;let l=c.type,u="element"in c?c.element:void 0;switch(typeof u=="object"&&(u=D(u)),l){case"tap":l="click";break}const[d]=await Promise.all([new Promise((g,A)=>{const v=()=>{this.off("playbackFoundAndSent",M),this.off("playbackError",P)},M=async x=>{this.actionHistory.push({action:o,result:x}),v(),g(x)},P=x=>{this.actionHistory.push({action:o,error:x}),v(),A(new Y(x))};this.once("playbackFoundAndSent",M),this.once("playbackError",P)}),this.socket.send("playEvent",{event:{...c,element:u,type:l},timeout:Math.round(s/1e3),strictMatch:i,id:a})]);r.push(d)}return r}catch(s){throw h(s,this.playActions),s}}async getUI({timeout:e=3e4}={}){try{this.socket.send("dumpUi");const t=await b(this.socket,"uiDump",{timeout:e});return"ui"in t?t.ui:t.result}catch(t){throw h(t,this.getUI),t}}async findElement(e,{timeout:t,...s}={}){try{const i=await this.playAction({type:"assert",element:e,bundleId:s==null?void 0:s.bundleId},{timeout:t});return i.matchedElements?i.matchedElements[0]:i.matchedElement}catch(i){throw h(i,this.findElement),i}}async findElements(e,t){try{const s=await this.playAction({type:"assert",element:{...e,allowMultipleMatches:!0},bundleId:t==null?void 0:t.bundleId},{timeout:t==null?void 0:t.timeout});return s.matchedElements?s.matchedElements:s.matchedElement?[s.matchedElement]:[]}catch(s){throw h(s,this.findElements),s}}async tap(e,t){try{if("element"in e){if(!this.config.record)throw new _('"element" selector');return await this.playAction({type:"click",element:e.element,bundleId:e.bundleId},{timeout:t==null?void 0:t.timeout})}await this.socket.send("userInteraction",{type:"mousedown",timeStamp:Date.now(),xPos:e.x,yPos:e.y}).then(()=>{this.socket.send("userInteraction",{type:"mouseup",timeStamp:Date.now(),xPos:e.x,yPos:e.y})}),await this.waitForEvent("interaction",{predicate:s=>s.type==="mouseup",timeout:t==null?void 0:t.timeout})}catch(s){throw h(s,this.tap),s}}async swipe(e,t){var s,i;try{if(!this.config.record)throw new _("swipe()");let r;const o=e.element?await this.findElement(e.element):void 0;if(typeof e.gesture=="function"){const a=new W(this,{...e,element:o});e.gesture(a),r=a.toAction()}else{const a=new W(this,{...e,element:o}),c=this.deviceInfo.screen.width*((s=this.deviceInfo.screen.devicePixelRatio)!=null?s:1),l=this.deviceInfo.screen.height*((i=this.deviceInfo.screen.devicePixelRatio)!=null?i:1);switch(e.gesture){case"up":case"down":{const u=l*.5;if(typeof u=="number")a.move(0,u*(e.gesture==="up"?-1:1));else{const d=e.gesture==="up"?"-":"";a.move(0,d+u)}break}case"left":case"right":{const u=c*.5;if(typeof u=="number")a.move(u*(e.gesture==="left"?-1:1),0);else{const d=e.gesture==="left"?"-":"";a.move(d+u,0)}break}}r=a.toAction()}return this.playAction({...r,bundleId:e.bundleId},{timeout:t==null?void 0:t.timeout})}catch(r){throw h(r,this.swipe),r}}}function ne(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}const y=function(){const n="[Appetize]";return Function.prototype.bind.call(console.log,console,n)}();class ie extends w.EventEmitter{constructor({socket:e}){super(),this.socket=e,this.socket.on("*",({type:t,value:s})=>{const i=U(t,s);if(i)this.emit(i.type,i.value),this.emit("*",i);else if(i!==null)switch(t){default:this.emit(t,s),this.emit("*",{type:t,value:s})}})}on(e,t){return super.on(e,t)}async startSession(e){throw new Error("Not implemented")}async config(e){throw new Error("Not implemented")}async waitForSessionStart(e){return new Promise(async(t,s)=>{const i=()=>{s(new Error("Session failed to start - client disconnected"))},r=a=>{s(new Error(`Session failed to start - ${typeof a.message=="object"?JSON.stringify(a.message):a.message}`))},o=a=>{a.message.match(/Too many requests/)&&s(new Error("Session failed to start - too many requests"))};try{this.on("error",o),e.on("disconnect",i),e.on("error",r),await e.waitForEvent("ready",{timeout:null})}finally{this.off("error",o),e.off("disconnect",i),e.off("error",r)}t(e)})}}const O="0.3.1";class re extends ie{constructor({socket:e,window:t}){super({socket:e}),this.window=t,this.window.on("*",async({type:s,value:i})=>{switch(s){case"app":this.app=i,this.emit(s,i);break;case"deviceInfo":this.deviceInfo=i,this.emit(s,i);break;case"config":this._config=this.mapConfig(i);break;case"sessionConnecting":{this.session||(this.session=await this.createSession(this._config));try{await this.waitForSessionStart(this.session),this.emit("session",this.session)}catch{}}}}),this.window.waitUntilReady().then(()=>{this.config({record:!0,apiVersion:O})}),this.getDeviceInfo()}async startSession(e,t){this.deviceInfo||await this.getDeviceInfo();const s=await this.config(e!=null?e:{}),i=await this.createSession(s,t);return await Promise.all([this.window.postMessage({type:"requestSession"},!0),this.waitForSessionStart(i)]),i}async config({publicKey:e,...t}){if(e){const i=await this.window.postMessage({type:"loadApp",value:e},!0);if(i&&"error"in i)throw new Error(i.error)}const s=await this.window.postMessage({type:"setConfig",value:this.validateConfig(t!=null?t:{})},!0).then(this.mapConfig);return this._config=s,s}mapConfig(e){return{...e,device:e.deviceType||e.device}}getDeviceInfo(){return this.window.postMessage({type:"getDeviceInfo"},!0).then(e=>{this.deviceInfo=e})}validateConfig(e){return e}async createSession(e,t){throw new Error("Not implemented")}}function oe({type:n,value:e}){switch(n){case"chromeDevToolsUrl":return{type:"networkInspectorUrl",value:e};case"orientationChanged":return{type:"orientationChanged",value:e}}}class ae extends w.EventEmitter{constructor({page:e}){super(),this.ready=!1,this.page=e,this.page.exposeFunction("__appetize_on",t=>{const s=t==="string"?t:t.type;this.emit(s,t.value),this.emit("*",{type:s,value:t.value})})}async init(){this.ready=!1,await this.page.evaluate(async([e])=>new Promise(t=>{const s=setTimeout(()=>{throw new S("Timed out after 60000ms waiting for connection to Appetize page")},6e4),i=setInterval(()=>{const r=new MessageChannel;r.port1.onmessage=()=>{clearInterval(i),clearTimeout(s),t(!1)},window.postMessage({type:"init",appetizeClient:!0,version:e},"*",[r.port2]),window.__appetize_postMessage=async(o,a=!1)=>{const c=new MessageChannel;if(window.postMessage(o,"*",[c.port2]),a)return new Promise((l,u)=>{const d=setTimeout(()=>{u(new S("Timed out after 60000ms while waiting for postMessage response"))},6e4);c.port1.onmessage=g=>{clearTimeout(d),l(g.data)}})}},100)}),[O]),await this.page.evaluate(()=>{window.addEventListener("message",e=>{var t;if(e.source===window){const s=typeof e.data=="string"?e.data:(t=e.data)==null?void 0:t.type;if(s==="socketEvent")switch(e.data.value.type){case"h264Data":case"frameData":if(!window.__appetize_emit_video)return;break;case"audioData":if(!window.__appetize_emit_audio)return;break;case"recordedEvent":if(!window.__appetize_emit_record)return;break}else switch(s){case"frameData":case"recordedEvent":case"playbackFoundAndSent":case"playbackNotFound":case"deleteEvent":case"debug":case"interceptRequest":case"interceptResponse":case"interceptError":case"uiDump":return}window.__appetize_on(e.data)}})},[]),this.ready=!0}async waitUntilReady(){return F(async()=>{if(!this.ready)throw new S("Timed out after 60000ms while waiting for Appetize window to be ready.")},6e4)}enableVideoEvents(){return this.page.evaluate(()=>{window.__appetize_emit_video=!0})}enableAudioEvents(){return this.page.evaluate(()=>{window.__appetize_emit_audio=!0})}enableRecordEvents(){return this.page.evaluate(()=>{window.__appetize_emit_record=!0})}async postMessage(e,t=!1){return await this.waitUntilReady(),this.page.evaluate(async([s,i])=>window.__appetize_postMessage(s,i),[e,t])}}class z extends w.EventEmitter{constructor({page:e,type:t,window:s}){super(),this.page=e,this.type=t,this.window=s,this.window.on("*",({type:i,value:r})=>{switch(i){case"socketEvent":r.socket===this.type&&(this.emit(r.type,r.value),this.emit("*",{type:r.type,value:r.value}));break;case"disconnect":this.emit("disconnect"),this.emit("*",{type:"disconnect"});break;case"sessionInfo":case"chromeDevToolsUrl":case"orientationChanged":if(this.type==="appetizer"){const o=oe({type:i,value:r});o&&(this.emit(o.type,o.value),this.emit("*",o))}break}})}async send(e,t){return this.window.postMessage({type:"emitSocketEvent",value:{type:e,value:t,socket:this.type}})}async disconnect(){await this.send("disconnect")}waitForEvent(e,t){return b(this,e,t)}}async function ce(n){await n.pause()}class he{constructor({testInfo:e,session:t}){this.currentRecord=0,this.session=t,this.testInfo=e}async record(){const e=this.testInfo.file,t=await $.default.promises.readFile(e,"utf8"),i=t.split(`
`).map((r,o)=>({line:r,num:o+1})).slice(this.testInfo.line).filter(({line:r})=>r.includes("session.record()"))[this.currentRecord].num;if(i!==void 0){y(`\u{1F534} Recording at line ${i}`);const r=[],o=c=>{ue(r,c),y(L(c))};this.session.on("action",o),await ce(this.session.page),await T(2e3),this.session.off("action",o);const a=t.split(`
`).map((c,l)=>{var u,d;if(l===i-1){const g=(d=(u=c.match(/^\s*/))==null?void 0:u[0])!=null?d:0;return`${r.map(v=>L(v)).reduce((v,M,P)=>`${v}
startSession({ enableAdb: true })`);return this.adbConnectionInfo?this.adbConnectionInfo:F(()=>{if(this.adbConnectionInfo)return this.adbConnectionInfo;throw new S("Timed out after 60000ms waiting for adb connection")},6e4)}catch(e){throw u(e,this.getAdbInfo),e}}async rotate(e){try{const[t]=await Promise.all([this.waitForEvent("orientationChanged"),this.socket.send("userInteraction",{type:"keypress",key:e==="left"?"rotateLeft":"rotateRight",timeStamp:Date.now()})]);return t}catch(t){throw u(t,this.rotate),t}}async screenshot(e="buffer"){try{this.socket.send("getScreenshot");const t=await b(this.socket,"screenshot",{timeout:6e4});if(!t.success)throw new p("Screenshot failed");return{data:e==="buffer"?(r=>typeof window=="undefined"?Buffer.from(r):r)(t.data):te(new Uint8Array(t.data),t.mimeType),mimeType:t.mimeType}}catch(t){throw u(t,this.screenshot),t}}async heartbeat(){try{return await this.socket.send("heartbeat")}catch(e){throw u(e,this.heartbeat),e}}async type(e){try{this.config.platform==="ios"&&await T(1e3);const t=[...e].map(X);if(this.config.record)return await this.playAction({type:"keypress",keypress:{type:"keypressArray",shiftKeyArray:t.map(s=>s.shiftKey),keyArray:t.map(s=>s.key),value:e}});await Promise.all([this.socket.send("userInteraction",{type:"keypressArray",shiftKeyArray:t.map(s=>s.shiftKey),keyArray:t.map(s=>s.key),value:e}),this.waitForEvent("interaction",{predicate:s=>s.type==="keypressArray"})])}catch(t){throw u(t,this.type),t}}async keypress(e,t){var s,i,r,o;try{if(e==="ANDROID_KEYCODE_MENU")return await this.socket.send("androidKeycodeMenu");e=G(e);const a=Date.now();if(this.config.record)return this.playAction({type:"keypress",keypress:{type:"keypress",key:e,timeStamp:a,altKey:(s=t==null?void 0:t.alt)!=null?s:!1,shiftKey:(i=t==null?void 0:t.shift)!=null?i:!1}});{const[c]=await Promise.all([this.waitForEvent("interaction",{predicate:l=>l.type==="keypress"&&l.timeStamp===a}),this.socket.send("userInteraction",{type:"keypress",key:e,timeStamp:a,altKey:(r=t==null?void 0:t.alt)!=null?r:!1,shiftKey:(o=t==null?void 0:t.shift)!=null?o:!1})]);return c}}catch(a){throw u(a,this.keypress),a}}async setLanguage(e){try{return this.config.language=e,await this.socket.send("setLanguage",{language:e,timeStamp:Date.now()})}catch(t){throw u(t,this.setLanguage),t}}async setLocation(e,t){try{if(typeof e!="number"||typeof t!="number")throw new p("setLocation requires latitude and longitude to be numbers");const s=[e,t];return this.config.location=s,await this.socket.send("setLocation",{location:s,timeStamp:Date.now()})}catch(s){throw u(s,this.setLocation),s}}async openUrl(e){try{return await this.socket.send("openUrl",{url:e,timeStamp:Date.now()})}catch(t){throw u(t,this.openUrl),t}}async shake(){try{return await this.socket.send("shakeDevice")}catch(e){throw u(e,this.swipe),e}}async biometry({match:e}){try{return await this.socket.send(e?"biometryMatch":"biometryNoMatch")}catch(t){throw u(t,this.biometry),t}}async allowInteractions(e){try{return await this.socket.send(e?"enableInteractions":"disableInteractions")}catch(t){throw u(t,this.allowInteractions),t}}async restartApp(){try{this.socket.send("restartApp");const{platform:e}=this.config;e==="ios"?await this.waitForEvent("appLaunch",{timeout:6e4}):await T(1e3)}catch(e){throw u(e,this.restartApp),e}}async reinstallApp(){try{this.socket.send("reinstallApp"),await this.waitForEvent("appLaunch",{timeout:6e4})}catch(e){throw u(e,this.reinstallApp),e}}async adbShellCommand(e){if(this.config.platform!=="android")throw new Error("adbShellCommand is only available on Android devices");try{return await this.socket.send("adbShellCommand",{command:e,timeStamp:Date.now()})}catch(t){throw u(t,this.adbShellCommand),t}}async playAction(e,t={}){try{if(!this.config.record)throw new _("playAction()");return await this.playActions([e],t).then(s=>s[0])}catch(s){throw u(s,this.playAction),s}}async playActions(e,t={}){try{const{timeout:s=3e4,strictMatch:i}=t,r=[];if(!this.config.record)throw new _("playActions()");for(const o of e){const{id:a,...c}=o;let l=c.type,h="element"in c?c.element:void 0;switch(typeof h=="object"&&(h=D(h)),l){case"tap":l="click";break}const[d]=await Promise.all([new Promise((g,A)=>{const v=()=>{this.off("playbackFoundAndSent",M),this.off("playbackError",P)},M=async x=>{this.actionHistory.push({action:o,result:x}),v(),g(x)},P=x=>{this.actionHistory.push({action:o,error:x}),v(),A(new Y(x))};this.once("playbackFoundAndSent",M),this.once("playbackError",P)}),this.socket.send("playEvent",{event:{...c,element:h,type:l},timeout:Math.round(s/1e3),strictMatch:i,id:a})]);r.push(d)}return r}catch(s){throw u(s,this.playActions),s}}async getUI({timeout:e=3e4}={}){try{this.socket.send("dumpUi");const t=await b(this.socket,"uiDump",{timeout:e});return"ui"in t?t.ui:t.result}catch(t){throw u(t,this.getUI),t}}async findElement(e,{timeout:t,...s}={}){try{const i=await this.playAction({type:"assert",element:e,bundleId:s==null?void 0:s.bundleId},{timeout:t});return i.matchedElements?i.matchedElements[0]:i.matchedElement}catch(i){throw u(i,this.findElement),i}}async findElements(e,t){try{const s=await this.playAction({type:"assert",element:{...e,allowMultipleMatches:!0},bundleId:t==null?void 0:t.bundleId},{timeout:t==null?void 0:t.timeout});return s.matchedElements?s.matchedElements:s.matchedElement?[s.matchedElement]:[]}catch(s){throw u(s,this.findElements),s}}async tap(e,t){try{if("element"in e){if(!this.config.record)throw new _('"element" selector');return await this.playAction({type:"click",element:e.element,bundleId:e.bundleId},{timeout:t==null?void 0:t.timeout})}await this.socket.send("userInteraction",{type:"mousedown",timeStamp:Date.now(),xPos:e.x,yPos:e.y}).then(()=>{this.socket.send("userInteraction",{type:"mouseup",timeStamp:Date.now(),xPos:e.x,yPos:e.y})}),await this.waitForEvent("interaction",{predicate:s=>s.type==="mouseup",timeout:t==null?void 0:t.timeout})}catch(s){throw u(s,this.tap),s}}async swipe(e,t){var s,i;try{if(!this.config.record)throw new _("swipe()");let r;const o=e.element?await this.findElement(e.element):void 0;if(typeof e.gesture=="function"){const a=new W(this,{...e,element:o});e.gesture(a),r=a.toAction()}else{const a=new W(this,{...e,element:o}),c=this.deviceInfo.screen.width*((s=this.deviceInfo.screen.devicePixelRatio)!=null?s:1),l=this.deviceInfo.screen.height*((i=this.deviceInfo.screen.devicePixelRatio)!=null?i:1);switch(e.gesture){case"up":case"down":{const h=l*.5;if(typeof h=="number")a.move(0,h*(e.gesture==="up"?-1:1));else{const d=e.gesture==="up"?"-":"";a.move(0,d+h)}break}case"left":case"right":{const h=c*.5;if(typeof h=="number")a.move(h*(e.gesture==="left"?-1:1),0);else{const d=e.gesture==="left"?"-":"";a.move(d+h,0)}break}}r=a.toAction()}return this.playAction({...r,bundleId:e.bundleId},{timeout:t==null?void 0:t.timeout})}catch(r){throw u(r,this.swipe),r}}}function ne(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}const y=function(){const n="[Appetize]";return Function.prototype.bind.call(console.log,console,n)}();class ie extends w.EventEmitter{constructor({socket:e}){super(),this.socket=e,this.socket.on("*",({type:t,value:s})=>{const i=U(t,s);if(i)this.emit(i.type,i.value),this.emit("*",i);else if(i!==null)switch(t){default:this.emit(t,s),this.emit("*",{type:t,value:s})}})}on(e,t){return super.on(e,t)}async startSession(e){throw new Error("Not implemented")}async config(e){throw new Error("Not implemented")}async waitForSessionStart(e){return new Promise(async(t,s)=>{const i=()=>{s(new Error("Session failed to start - client disconnected"))},r=a=>{s(new Error(`Session failed to start - ${typeof a.message=="object"?JSON.stringify(a.message):a.message}`))},o=a=>{a.message.match(/Too many requests/)&&s(new Error("Session failed to start - too many requests"))};try{this.on("error",o),e.on("disconnect",i),e.on("error",r),await e.waitForEvent("ready",{timeout:null})}finally{this.off("error",o),e.off("disconnect",i),e.off("error",r)}t(e)})}}const O="0.3.2";class re extends ie{constructor({socket:e,window:t}){super({socket:e}),this.window=t,this.window.on("*",async({type:s,value:i})=>{switch(s){case"app":this.app=i,this.emit(s,i);break;case"deviceInfo":this.deviceInfo=i,this.emit(s,i);break;case"config":this._config=this.mapConfig(i);break;case"sessionConnecting":{this.session||(this.session=await this.createSession(this._config));try{await this.waitForSessionStart(this.session),this.emit("session",this.session)}catch{}}}}),this.window.waitUntilReady().then(()=>{this.config({record:!0,apiVersion:O})}),this.getDeviceInfo()}async startSession(e,t){this.deviceInfo||await this.getDeviceInfo();const s=await this.config(e!=null?e:{}),i=await this.createSession(s,t);return await Promise.all([this.window.postMessage({type:"requestSession"},!0),this.waitForSessionStart(i)]),i}async config({publicKey:e,...t}){if(e){const i=await this.window.postMessage({type:"loadApp",value:e},!0);if(i&&"error"in i)throw new Error(i.error)}const s=await this.window.postMessage({type:"setConfig",value:this.validateConfig(t!=null?t:{})},!0).then(this.mapConfig);return this._config=s,s}mapConfig(e){return{...e,device:e.deviceType||e.device}}getDeviceInfo(){return this.window.postMessage({type:"getDeviceInfo"},!0).then(e=>{this.deviceInfo=e})}validateConfig(e){return e}async createSession(e,t){throw new Error("Not implemented")}}function oe({type:n,value:e}){switch(n){case"chromeDevToolsUrl":return{type:"networkInspectorUrl",value:e};case"orientationChanged":return{type:"orientationChanged",value:e}}}class ae extends w.EventEmitter{constructor({page:e}){super(),this.ready=!1,this.page=e,this.page.exposeFunction("__appetize_on",t=>{const s=t==="string"?t:t.type;this.emit(s,t.value),this.emit("*",{type:s,value:t.value})})}async init(){this.ready=!1,await this.page.evaluate(async([e])=>new Promise(t=>{const s=setTimeout(()=>{throw new S("Timed out after 60000ms waiting for connection to Appetize page")},6e4),i=setInterval(()=>{const r=new MessageChannel;r.port1.onmessage=()=>{clearInterval(i),clearTimeout(s),t(!1)},window.postMessage({type:"init",appetizeClient:!0,version:e},"*",[r.port2]),window.__appetize_postMessage=async(o,a=!1)=>{const c=new MessageChannel;if(window.postMessage(o,"*",[c.port2]),a)return new Promise((l,h)=>{const d=setTimeout(()=>{h(new S("Timed out after 60000ms while waiting for postMessage response"))},6e4);c.port1.onmessage=g=>{clearTimeout(d),l(g.data)}})}},100)}),[O]),await this.page.evaluate(()=>{window.addEventListener("message",e=>{var t;if(e.source===window){const s=typeof e.data=="string"?e.data:(t=e.data)==null?void 0:t.type;if(s==="socketEvent")switch(e.data.value.type){case"h264Data":case"frameData":if(!window.__appetize_emit_video)return;break;case"audioData":if(!window.__appetize_emit_audio)return;break;case"recordedEvent":if(!window.__appetize_emit_record)return;break}else switch(s){case"frameData":case"recordedEvent":case"playbackFoundAndSent":case"playbackNotFound":case"deleteEvent":case"debug":case"interceptRequest":case"interceptResponse":case"interceptError":case"uiDump":return}window.__appetize_on(e.data)}})},[]),this.ready=!0}async waitUntilReady(){return F(async()=>{if(!this.ready)throw new S("Timed out after 60000ms while waiting for Appetize window to be ready.")},6e4)}enableVideoEvents(){return this.page.evaluate(()=>{window.__appetize_emit_video=!0})}enableAudioEvents(){return this.page.evaluate(()=>{window.__appetize_emit_audio=!0})}enableRecordEvents(){return this.page.evaluate(()=>{window.__appetize_emit_record=!0})}async postMessage(e,t=!1){return await this.waitUntilReady(),this.page.evaluate(async([s,i])=>window.__appetize_postMessage(s,i),[e,t])}}class z extends w.EventEmitter{constructor({page:e,type:t,window:s}){super(),this.page=e,this.type=t,this.window=s,this.window.on("*",({type:i,value:r})=>{switch(i){case"socketEvent":r.socket===this.type&&(this.emit(r.type,r.value),this.emit("*",{type:r.type,value:r.value}));break;case"disconnect":this.emit("disconnect"),this.emit("*",{type:"disconnect"});break;case"sessionInfo":case"chromeDevToolsUrl":case"orientationChanged":if(this.type==="appetizer"){const o=oe({type:i,value:r});o&&(this.emit(o.type,o.value),this.emit("*",o))}break}})}async send(e,t){return this.window.postMessage({type:"emitSocketEvent",value:{type:e,value:t,socket:this.type}})}async disconnect(){await this.send("disconnect")}waitForEvent(e,t){return b(this,e,t)}}async function ce(n){await n.pause()}class ue{constructor({testInfo:e,session:t}){this.currentRecord=0,this.session=t,this.testInfo=e}async record(){const e=this.testInfo.file,t=await $.default.promises.readFile(e,"utf8"),i=t.split(`
`).map((r,o)=>({line:r,num:o+1})).slice(this.testInfo.line).filter(({line:r})=>r.includes("session.record()"))[this.currentRecord].num;if(i!==void 0){y(`\u{1F534} Recording at line ${i}`);const r=[],o=c=>{he(r,c),y(L(c))};this.session.on("action",o),await ce(this.session.page),await T(2e3),this.session.off("action",o);const a=t.split(`
`).map((c,l)=>{var h,d;if(l===i-1){const g=(d=(h=c.match(/^\s*/))==null?void 0:h[0])!=null?d:0;return`${r.map(v=>L(v)).reduce((v,M,P)=>`${v}
// ${P+1}. ${M}`,"// Recorded using session.record()")}

@@ -42,5 +42,5 @@ await session.playActions(${JSON.stringify(r,null," ")})`.split(`

`)}return c});await $.default.promises.writeFile(e,a.join(`
`)),y("\u{1F7E2} Finished"),this.currentRecord+=1}}}function ue(n,e){const t=n[n.length-1];if(t)switch(e.type){case"keypress":(t==null?void 0:t.type)==="keypress"&&e.type==="keypress"&&e.keypress.type==="keypress"?t.keypress.type==="keypress"?n[n.length-1]={...t,keypress:{type:"keypressArray",shiftKeyArray:[t.keypress.shiftKey,e.keypress.shiftKey],keyArray:[t.keypress.key,e.keypress.key],value:C(t.keypress)+C(e.keypress)}}:n[n.length-1]={...t,keypress:{type:"keypressArray",shiftKeyArray:[...t.keypress.shiftKeyArray,e.keypress.shiftKey],keyArray:[...t.keypress.keyArray,e.keypress.key],value:t.keypress.value+C(e.keypress)}}:n.push(e);break;default:n.push(e)}else n.push(e)}function L(n){let e="";switch(n.type){case"swipe":case"click":{const t=n.element;return typeof t=="string"?e=` on element "${t}"`:t!=null&&t.accessibilityIdentifier?e=`element with accessibilityIdentifier "${t.accessibilityIdentifier}"`:t!=null&&t.class?e=`element with class "${t.class}"`:n.xPos&&n.yPos&&(e=`position ${n.xPos}, ${n.yPos}`),e?`${n.type} on ${e}`:n.type}case"keypress":return n.keypress.type==="keypress"?`type "${C(n.keypress)}"`:`type "${n.keypress.value}"`;default:return n.type}}class le extends se{constructor({page:e,config:t,window:s,testInfo:i,deviceInfo:r}){const o=new z({page:e,window:s,type:"appetizer"});super({socket:o,config:t,deviceInfo:r}),this.window=s,this.page=e,this.config=t,this.testInfo=i,this.page.on("load",()=>{this.emit("disconnect")}),t.record&&this.on("disconnect",()=>{this.teardownUi()})}async getUI(e={}){return await super.getUI(e)}teardownUi(){return this.window.page.evaluate(()=>{const e=document.querySelector("app-ui");e&&e.remove()})}async rotate(e){try{const[t]=await Promise.all([b(this.window,"orientationChanged"),await this.window.postMessage(e==="left"?"rotateLeft":"rotateRight")]);return this.window.page.waitForTimeout(1e3),t}catch(t){throw h(t,this.rotate),t}}async screenshot(e="buffer"){try{const[t]=await Promise.all([b(this.socket,"screenshot",{timeout:6e4}),this.socket.send("getScreenshot")]),s=new Uint8Array(Object.values(t.data).map(Number));return{data:e==="buffer"?Buffer.from(s):t.data,mimeType:t.mimeType}}catch(t){throw h(t,this.screenshot),t}}async record(){try{if(!this.config.record)throw new f("Recording is not enabled, please enable it by setting `record: true` in session config");if(!this.testInfo)throw new f("session.record() requires using `session` from the test() arguments");return new he({session:this,testInfo:this.testInfo}).record()}catch(e){throw h(e,this.record),e}}async waitForEvent(e,t){try{return await b(this,e,t)}catch(s){throw h(s,this.waitForEvent),s}}async waitForTimeout(e){try{return await T(e)}catch(t){throw h(t,this.waitForTimeout),t}}async waitForElement(e,t){const s=await this.findElements(e,t);if(typeof(t==null?void 0:t.matches)=="number"?s.length===t.matches:s.length>0)return s;throw new Error(`Element not found:
${JSON.stringify(e)}`)}on(e,t){return e==="video"&&this.window.enableVideoEvents(),e==="audio"&&this.window.enableAudioEvents(),e==="action"&&this.window.enableRecordEvents(),super.on(e,t)}once(e,t){return e==="video"&&this.window.enableVideoEvents(),e==="audio"&&this.window.enableAudioEvents(),e==="action"&&this.window.enableRecordEvents(),super.once(e,t)}}const V=new WeakMap;class de extends re{constructor({page:e}){var r;const t=(r=V.get(e))!=null?r:new ae({page:e});V.set(e,t),t.init();const s=new z({type:"webserver",page:e,window:t});super({socket:s,window:t}),this.window=t,this.page=e;let i=!1;this.on("queue",({type:o,position:a})=>{i||(i=!0,y(o==="account"?"All slots for this account are currently in use. Please wait until a slot becomes available.":"All devices are currently in use. Please wait until requested device becomes available.")),a>0&&y(o==="account"?`Position in account-level queue: ${a}`:`Position in queue: ${a}`)}),this.on("session",()=>{i&&(y("Session started"),i=!1)})}validateConfig(e){var s;return{codec:((s=this.page.context().browser())==null?void 0:s.browserType().name())==="chromium"?"jpeg":"h264",record:!0,apiVersion:O,...e}}async startSession({testInfo:e,...t}){return super.startSession(t,{testInfo:e})}async createSession(e,t){return this.session=new le({config:e,page:this.page,window:this.window,testInfo:t.testInfo,deviceInfo:this.deviceInfo}),this.session}}R.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)}`}}catch(s){return{pass:!1,message:()=>s.message}}}});let k,E,m;const I=Object.assign(R.test.extend({_autoSnapshotSuffix:[async({},n,e)=>{e.snapshotSuffix="",await n()},{auto:!0}],page:async({},n)=>{if(!E)throw new Error("Appetize not initialized. Make sure you have run test.setup()");await n(E.page)},session:async({},n)=>{if(!m)throw new Error("Session was not started. Make sure you have run test.setup()");await n(m)},client:async({},n)=>{if(!E)throw new Error("Appetize not initialized. Make sure you have run test.setup()");await n(E)}}),{setup(n){I.afterEach(async({session:e},t)=>{}),I.beforeAll(async({browser:e,baseURL:t},s)=>{var i,r;if(s.config.fullyParallel)throw new Error("fullyParallel is not allowed when running Appetize tests. Please set `fullyParallel: false` in your Playwright config");if(I.setTimeout(6e4*5),k||(k=await e.newPage(),k.on("close",()=>{k=null,E=null,m=null})),"url"in n)await k.goto(n.url);else{const o=new URLSearchParams;n.device&&o.set("device",n.device),n.deviceColor&&o.set("deviceColor",n.deviceColor),n.screenOnly&&o.set("screenOnly",n.screenOnly.toString()),o.set("scale",(r=(i=n.scale)==null?void 0:i.toString())!=null?r:"auto"),await k.goto(`${t!=null?t:"https://appetize.io"}/embed/${n.publicKey}?${o.toString()}`)}E=new de({page:k}),m=await H(()=>E.startSession({...n,testInfo:s}),{retries:5,timeout:3e4,predicate:(o,a)=>o instanceof Error&&o.message.match(/too many requests/)?(console.warn(`Too many session requests. Retrying in 30 seconds... (attempt #${a})`),!0):!1})}),I.afterAll(async({},e)=>{m!=null&&m.page&&await m.page.context().close()})}});Object.defineProperty(p,"expect",{enumerable:!0,get:function(){return R.expect}}),p.test=I,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
`)),y("\u{1F7E2} Finished"),this.currentRecord+=1}}}function he(n,e){const t=n[n.length-1];if(t)switch(e.type){case"keypress":(t==null?void 0:t.type)==="keypress"&&e.type==="keypress"&&e.keypress.type==="keypress"?t.keypress.type==="keypress"?n[n.length-1]={...t,keypress:{type:"keypressArray",shiftKeyArray:[t.keypress.shiftKey,e.keypress.shiftKey],keyArray:[t.keypress.key,e.keypress.key],value:C(t.keypress)+C(e.keypress)}}:n[n.length-1]={...t,keypress:{type:"keypressArray",shiftKeyArray:[...t.keypress.shiftKeyArray,e.keypress.shiftKey],keyArray:[...t.keypress.keyArray,e.keypress.key],value:t.keypress.value+C(e.keypress)}}:n.push(e);break;default:n.push(e)}else n.push(e)}function L(n){let e="";switch(n.type){case"swipe":case"click":{const t=n.element;return typeof t=="string"?e=` on element "${t}"`:t!=null&&t.accessibilityIdentifier?e=`element with accessibilityIdentifier "${t.accessibilityIdentifier}"`:t!=null&&t.class?e=`element with class "${t.class}"`:n.xPos&&n.yPos&&(e=`position ${n.xPos}, ${n.yPos}`),e?`${n.type} on ${e}`:n.type}case"keypress":return n.keypress.type==="keypress"?`type "${C(n.keypress)}"`:`type "${n.keypress.value}"`;default:return n.type}}class le extends se{constructor({page:e,config:t,window:s,testInfo:i,deviceInfo:r}){const o=new z({page:e,window:s,type:"appetizer"});super({socket:o,config:t,deviceInfo:r}),this.window=s,this.page=e,this.config=t,this.testInfo=i,this.page.on("load",()=>{this.emit("disconnect")}),t.record&&this.on("disconnect",()=>{this.teardownUi()})}async getUI(e={}){return await super.getUI(e)}teardownUi(){return this.window.page.evaluate(()=>{const e=document.querySelector("app-ui");e&&e.remove()})}async rotate(e){try{const[t]=await Promise.all([b(this.window,"orientationChanged"),await this.window.postMessage(e==="left"?"rotateLeft":"rotateRight")]);return this.window.page.waitForTimeout(1e3),t}catch(t){throw u(t,this.rotate),t}}async screenshot(e="buffer"){try{const[t]=await Promise.all([b(this.socket,"screenshot",{timeout:6e4}),this.socket.send("getScreenshot")]),s=new Uint8Array(Object.values(t.data).map(Number));return{data:e==="buffer"?Buffer.from(s):t.data,mimeType:t.mimeType}}catch(t){throw u(t,this.screenshot),t}}async record(){try{if(!this.config.record)throw new p("Recording is not enabled, please enable it by setting `record: true` in session config");if(!this.testInfo)throw new p("session.record() requires using `session` from the test() arguments");return new ue({session:this,testInfo:this.testInfo}).record()}catch(e){throw u(e,this.record),e}}async waitForEvent(e,t){try{return await b(this,e,t)}catch(s){throw u(s,this.waitForEvent),s}}async waitForTimeout(e){try{return await T(e)}catch(t){throw u(t,this.waitForTimeout),t}}async waitForElement(e,t){const s=await this.findElements(e,t);if(typeof(t==null?void 0:t.matches)=="number"?s.length===t.matches:s.length>0)return s;throw new Error(`Element not found:
${JSON.stringify(e)}`)}on(e,t){return e==="video"&&this.window.enableVideoEvents(),e==="audio"&&this.window.enableAudioEvents(),e==="action"&&this.window.enableRecordEvents(),super.on(e,t)}once(e,t){return e==="video"&&this.window.enableVideoEvents(),e==="audio"&&this.window.enableAudioEvents(),e==="action"&&this.window.enableRecordEvents(),super.once(e,t)}}const q=new WeakMap;class de extends re{constructor({page:e}){var r;const t=(r=q.get(e))!=null?r:new ae({page:e});q.set(e,t),t.init();const s=new z({type:"webserver",page:e,window:t});super({socket:s,window:t}),this.window=t,this.page=e;let i=!1;this.on("queue",({type:o,position:a})=>{i||(i=!0,y(o==="account"?"All slots for this account are currently in use. Please wait until a slot becomes available.":"All devices are currently in use. Please wait until requested device becomes available.")),a>0&&y(o==="account"?`Position in account-level queue: ${a}`:`Position in queue: ${a}`)}),this.on("session",()=>{i&&(y("Session started"),i=!1)})}validateConfig(e){var s;return{codec:((s=this.page.context().browser())==null?void 0:s.browserType().name())==="chromium"?"jpeg":"h264",record:!0,apiVersion:O,...e}}async startSession({testInfo:e,...t}){return super.startSession(t,{testInfo:e})}async createSession(e,t){return this.session=new le({config:e,page:this.page,window:this.window,testInfo:t.testInfo,deviceInfo:this.deviceInfo}),this.session}}R.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)}`}}catch(s){return{pass:!1,message:()=>s.message}}}});let k,E,m;const I=Object.assign(R.test.extend({_autoSnapshotSuffix:[async({},n,e)=>{e.snapshotSuffix="",await n()},{auto:!0}],page:async({},n)=>{if(!E)throw new Error("Appetize not initialized. Make sure you have run test.setup()");await n(E.page)},session:async({},n)=>{if(!m)throw new Error("Session was not started. Make sure you have run test.setup()");await n(m)},client:async({},n)=>{if(!E)throw new Error("Appetize not initialized. Make sure you have run test.setup()");await n(E)}}),{setup(n){I.afterEach(async({session:e},t)=>{}),I.beforeAll(async({browser:e,baseURL:t},s)=>{var i,r;if(s.config.fullyParallel)throw new Error("fullyParallel is not allowed when running Appetize tests. Please set `fullyParallel: false` in your Playwright config");if(I.setTimeout(6e4*5),k||(k=await e.newPage(),k.on("close",()=>{k=null,E=null,m=null})),"url"in n)await k.goto(n.url);else{const o=new URLSearchParams;n.device&&o.set("device",n.device),n.deviceColor&&o.set("deviceColor",n.deviceColor),n.screenOnly&&o.set("screenOnly",n.screenOnly.toString()),o.set("scale",(r=(i=n.scale)==null?void 0:i.toString())!=null?r:"auto"),await k.goto(`${t!=null?t:"https://appetize.io"}/embed/${n.publicKey}?${o.toString()}`)}E=new de({page:k}),m=await H(()=>E.startSession({...n,testInfo:s}),{retries:5,timeout:3e4,predicate:(o,a)=>o instanceof Error&&o.message.match(/too many requests/)?(console.warn(`Too many session requests. Retrying in 30 seconds... (attempt #${a})`),!0):!1})}),I.afterAll(async({},e)=>{m!=null&&m.page&&await m.page.context().close()})}});Object.defineProperty(f,"expect",{enumerable:!0,get:function(){return R.expect}}),f.test=I,Object.defineProperties(f,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
//# sourceMappingURL=index.umd.js.map

@@ -35,3 +35,3 @@ import { Page, TestInfo } from '@playwright/test';

locale?: string | undefined;
location?: string[] | undefined;
location?: number[] | undefined;
loopback?: boolean | undefined;

@@ -38,0 +38,0 @@ noVideo?: boolean | undefined;

{
"name": "@appetize/playwright",
"version": "0.3.1",
"version": "0.3.2",
"description": "Test your mobile apps on Appetize.io with Playwright",

@@ -5,0 +5,0 @@ "files": [

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