@appetize/playwright
Advanced tools
Comparing version 0.3.1 to 0.3.2
@@ -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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
410443
2977