@appetize/playwright
Advanced tools
Comparing version 0.1.2 to 0.1.3
@@ -109,3 +109,3 @@ /// <reference types="node" /> | ||
}; | ||
autdio: { | ||
audio: { | ||
buffer: Uint8Array; | ||
@@ -115,3 +115,16 @@ codec: 'aac'; | ||
}; | ||
app: AppetizeApp; | ||
} | ||
export interface AppetizeApp { | ||
publicKey: string; | ||
name?: string; | ||
appDisplayName?: string; | ||
appVersionCode?: string; | ||
bundle?: string; | ||
platform?: string; | ||
versionCode?: string; | ||
architectures?: string; | ||
iconUrl?: string; | ||
created?: string; | ||
} | ||
export interface AdbConnectionInfo { | ||
@@ -118,0 +131,0 @@ command: string; |
@@ -985,3 +985,3 @@ import { expect, test as test$1 } from "@playwright/test"; | ||
} | ||
const version = "0.1.4"; | ||
const version = "0.1.5"; | ||
const VERSION = version; | ||
@@ -1472,2 +1472,5 @@ class AppetizeWindow extends EventEmitter { | ||
break; | ||
case "app": | ||
this.emit(type, value); | ||
break; | ||
} | ||
@@ -1477,19 +1480,20 @@ }); | ||
this.on("queue", ({ type, position }) => { | ||
if (type === "account" && isInQueue !== "account") { | ||
isInQueue = "account"; | ||
log( | ||
`All slots for this account are currently in use. Please wait until a slot becomes available.` | ||
); | ||
} else { | ||
if (isInQueue === "account") { | ||
log(`You are now in the regular queue.`); | ||
} else if (!isInQueue) { | ||
if (!isInQueue) { | ||
isInQueue = true; | ||
if (type === "account") { | ||
log( | ||
`All slots for this account are currently in use. Please wait until a slot becomes available.` | ||
); | ||
} else { | ||
log( | ||
`All devices are currently in use. Please wait until requested device becomes available.` | ||
); | ||
} | ||
isInQueue = "session"; | ||
} | ||
if (position > 0) { | ||
log(`Position in queue: ${position}`); | ||
if (type === "account") { | ||
log(`Position in account-level queue: ${position}`); | ||
} else { | ||
log(`Position in queue: ${position}`); | ||
} | ||
} | ||
@@ -1499,3 +1503,3 @@ }); | ||
if (isInQueue) { | ||
log(`Session is ready to start`); | ||
log(`Session started`); | ||
isInQueue = false; | ||
@@ -1533,13 +1537,12 @@ } | ||
if (publicKey) { | ||
await Promise.all([ | ||
this.window.postMessage({ | ||
const response = await this.window.postMessage( | ||
{ | ||
type: "loadApp", | ||
value: publicKey | ||
}), | ||
waitForEvent(this.window, "app", { | ||
predicate(data) { | ||
return data.publicKey === publicKey; | ||
} | ||
}) | ||
]); | ||
}, | ||
true | ||
); | ||
if ("error" in response) { | ||
throw new Error(response.error); | ||
} | ||
} | ||
@@ -1670,4 +1673,8 @@ this.window.postMessage({ | ||
}); | ||
test.afterAll(async ({ session: session2 }, testInfo) => { | ||
await session2.page.close(); | ||
test.afterAll(async ({}, testInfo) => { | ||
var _a; | ||
await ((_a = session == null ? void 0 : session.page) == null ? void 0 : _a.close()); | ||
page = null; | ||
client = null; | ||
session = null; | ||
}); | ||
@@ -1674,0 +1681,0 @@ } |
@@ -1,5 +0,5 @@ | ||
(function(d,k){typeof exports=="object"&&typeof module!="undefined"?k(exports,require("@playwright/test"),require("events"),require("fs")):typeof define=="function"&&define.amd?define(["exports","@playwright/test","events","fs"],k):(d=typeof globalThis!="undefined"?globalThis:d||self,k(d.playwright={},d.test$1,d.events,d.fs))})(this,function(d,k,$,L){"use strict";function z(s){return s&&typeof s=="object"&&"default"in s?s:{default:s}}var R=z(L);class C{constructor(e){this.path=[],this.easing=t=>t,this.steps=20,this.stepDuration=25,e!=null&&e.easing&&(typeof e.easing=="string"?this.easing=j[e.easing]:this.easing=e.easing),e!=null&&e.steps&&(this.steps=e.steps),e!=null&&e.stepDuration&&(this.stepDuration=e.stepDuration)}from(e,t){return typeof e=="object"?(this.element=e,this.path[0]={type:"move",x:0,y:0}):this.path[0]={type:"move",x:e,y:t},this}to(e,t,n=!0){return n?this.path.push({type:"move",x:e,y:t}):this.path.push({type:"move",x:e,y:t}),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,n)=>this.easing(n*(this.stepDuration/1e3))),element:this.element}}previousCommand(e,t){return e.slice().reverse().find(n=>n.type===t)}interpolatePath(){const e=[];for(let t=0;t<this.path.length-1;t++){const i=this.previousCommand(this.path.slice(0,t+1),"move"),o=this.path[t+1];if(i){if(o.type==="move"){const r=y(o.x)||y(i.x),c=y(o.y)||y(i.y),a=Math.floor(this.steps/(this.path.length-1)),u=(h(o.x)-h(i.x))/a,l=(h(o.y)-h(i.y))/a,p=y(o.x)===y(i.x)||h(o.x)===0||h(i.x)===0,f=y(o.y)===y(i.y)||h(o.y)===0||h(i.y)===0;for(let w=0;w<=a;w++)e.push({x:p?`${h(i.x)+u*w}${r}`:i.x,y:f?`${h(i.y)+l*w}${c}`:i.y})}else if(o.type==="wait"){const r=Math.floor(o.value/this.stepDuration);for(let c=0;c<=r;c++)e.push({x:i.x,y:i.y})}}}return e.length&&(e.unshift(e[0]),e.push(e[e.length-1])),e}}const y=s=>typeof s=="number"||s.endsWith("px")?"":s.replace(/^-?\d+/,""),h=s=>typeof s=="number"?s:parseInt(s),j={linear:s=>s,easeIn:s=>s*s,easeOut:s=>s*(2-s),easeInOut:s=>s<.5?2*s*s:-1+(4-2*s)*s};async function W(s,{retries:e=3,timeout:t=1e3,predicate:n=()=>!0}){for(let i=1;i<=e;i++)try{return await s()}catch(o){if(i===e||!n(o,i))throw o;await new Promise(r=>setTimeout(r,t))}throw null}function U(s,e){switch(s){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{type:"action",value:e};case"deleteEvent":return{type:"deletedAction",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"}}}}async function D(s,e=5e3){const t=Date.now();for(;;)try{return await s()}catch(n){if(await new Promise(i=>setTimeout(i,100)),e!==null&&Date.now()-t>e)throw n}}async function I(s){return new Promise(e=>setTimeout(e,s))}async function m(s,e,t){const n=typeof t=="function"?{}:t,i=typeof t=="function"?t:t==null?void 0:t.predicate,o=typeof(n==null?void 0:n.timeout)!="undefined"?n.timeout:1e4;return new Promise((r,c)=>{const a=u=>{(!i||i(u))&&(s.off(e,a),r(u))};s.on(e,a),o!==null&&setTimeout(()=>{s.off(e,a),c(new Error(`Timed out after ${o}ms waiting for "${e}" event`))},o)})}function H(s){const e=s.length;let t="";for(let n=0;n<e;n+=65535){let i=65535;n+65535>e&&(i=e-n),t+=String.fromCharCode.apply(null,s.subarray(n,n+i))}return t}function V(s,e){const t=H(s),n=btoa(t);return`data:${e};base64,`+n}const F=[")","!","@","#","$","%","^","&","*","("],_={47:"?",44:"<",45:"_",46:">",91:"{",92:"|",93:"}",96:"~",59:":",61:"+",39:'"'},Y={191:"?",188:"<",189:"_",190:">",219:"{",220:"|",221:"}",192:"~",186:":",187:"+",222:'"'};function J(s){let e;for(const n in _)if(s===_[n])return e={key:String.fromCharCode(n),shiftKey:"true"},e;const t=F.indexOf(s);return t>-1?e={key:String.fromCharCode(t+48).toLowerCase(),shiftKey:!0}:s!==s.toLowerCase()?e={key:s.toLowerCase(),shiftKey:!0}:e={key:s,shiftKey:!1},e}function M(s){return s.type==="keypress"&&s.which&&s.key?s.which>=65&&s.which<=90?s.shiftKey?s.key:s.key.toLowerCase():s.shiftKey?s.which>=48&&s.which<=57?F[s.which-48]:Y[s.which]:s.key:null}function B(s){switch(s){case"HOME":return"home";case"VOLUME_UP":return"volumeUp";case"VOLUME_DOWN":return"volumeDown"}return s}class Q extends Error{constructor(e){var i,o,r,c;let t=e.message;const n=(i=e.playback)==null?void 0:i.event;switch(e.errorId){case"unknown":t=`${e.message}`;break;case"notFound":if(n&&"element"in n){let a=!1;const u=typeof n.element=="object"?{...n.element}:n.element;typeof u=="object"&&"allowMultipleMatches"in u&&(a=!!u.allowMultipleMatches,delete u.allowMultipleMatches),t=`No element${a?"s":""} found for selector | ||
${JSON.stringify(u,null," ")}`}break;case"ambiguousMatch":{const a=(o=e.matchedElements)==null?void 0:o.map(({frame:u,address:l,frameInWindow:p,bounds:f,windowType:w,...x})=>x);a&&(t=`More than 1 element matched the selector. Please specify more attributes to narrow down the matches to a single element, or provide a \`matchIndex\` attribute to select one of the following results | ||
(function(d,b){typeof exports=="object"&&typeof module!="undefined"?b(exports,require("@playwright/test"),require("events"),require("fs")):typeof define=="function"&&define.amd?define(["exports","@playwright/test","events","fs"],b):(d=typeof globalThis!="undefined"?globalThis:d||self,b(d.playwright={},d.test$1,d.events,d.fs))})(this,function(d,b,I,L){"use strict";function z(s){return s&&typeof s=="object"&&"default"in s?s:{default:s}}var R=z(L);class C{constructor(e){this.path=[],this.easing=t=>t,this.steps=20,this.stepDuration=25,e!=null&&e.easing&&(typeof e.easing=="string"?this.easing=j[e.easing]:this.easing=e.easing),e!=null&&e.steps&&(this.steps=e.steps),e!=null&&e.stepDuration&&(this.stepDuration=e.stepDuration)}from(e,t){return typeof e=="object"?(this.element=e,this.path[0]={type:"move",x:0,y:0}):this.path[0]={type:"move",x:e,y:t},this}to(e,t,n=!0){return n?this.path.push({type:"move",x:e,y:t}):this.path.push({type:"move",x:e,y:t}),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,n)=>this.easing(n*(this.stepDuration/1e3))),element:this.element}}previousCommand(e,t){return e.slice().reverse().find(n=>n.type===t)}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=y(r.x)||y(i.x),c=y(r.y)||y(i.y),a=Math.floor(this.steps/(this.path.length-1)),u=(h(r.x)-h(i.x))/a,l=(h(r.y)-h(i.y))/a,p=y(r.x)===y(i.x)||h(r.x)===0||h(i.x)===0,f=y(r.y)===y(i.y)||h(r.y)===0||h(i.y)===0;for(let w=0;w<=a;w++)e.push({x:p?`${h(i.x)+u*w}${o}`:i.x,y:f?`${h(i.y)+l*w}${c}`:i.y})}else if(r.type==="wait"){const o=Math.floor(r.value/this.stepDuration);for(let c=0;c<=o;c++)e.push({x:i.x,y:i.y})}}}return e.length&&(e.unshift(e[0]),e.push(e[e.length-1])),e}}const y=s=>typeof s=="number"||s.endsWith("px")?"":s.replace(/^-?\d+/,""),h=s=>typeof s=="number"?s:parseInt(s),j={linear:s=>s,easeIn:s=>s*s,easeOut:s=>s*(2-s),easeInOut:s=>s<.5?2*s*s:-1+(4-2*s)*s};async function W(s,{retries:e=3,timeout:t=1e3,predicate:n=()=>!0}){for(let i=1;i<=e;i++)try{return await s()}catch(r){if(i===e||!n(r,i))throw r;await new Promise(o=>setTimeout(o,t))}throw null}function U(s,e){switch(s){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{type:"action",value:e};case"deleteEvent":return{type:"deletedAction",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"}}}}async function D(s,e=5e3){const t=Date.now();for(;;)try{return await s()}catch(n){if(await new Promise(i=>setTimeout(i,100)),e!==null&&Date.now()-t>e)throw n}}async function M(s){return new Promise(e=>setTimeout(e,s))}async function m(s,e,t){const n=typeof t=="function"?{}:t,i=typeof t=="function"?t:t==null?void 0:t.predicate,r=typeof(n==null?void 0:n.timeout)!="undefined"?n.timeout:1e4;return new Promise((o,c)=>{const a=u=>{(!i||i(u))&&(s.off(e,a),o(u))};s.on(e,a),r!==null&&setTimeout(()=>{s.off(e,a),c(new Error(`Timed out after ${r}ms waiting for "${e}" event`))},r)})}function H(s){const e=s.length;let t="";for(let n=0;n<e;n+=65535){let i=65535;n+65535>e&&(i=e-n),t+=String.fromCharCode.apply(null,s.subarray(n,n+i))}return t}function V(s,e){const t=H(s),n=btoa(t);return`data:${e};base64,`+n}const F=[")","!","@","#","$","%","^","&","*","("],_={47:"?",44:"<",45:"_",46:">",91:"{",92:"|",93:"}",96:"~",59:":",61:"+",39:'"'},J={191:"?",188:"<",189:"_",190:">",219:"{",220:"|",221:"}",192:"~",186:":",187:"+",222:'"'};function Y(s){let e;for(const n in _)if(s===_[n])return e={key:String.fromCharCode(n),shiftKey:"true"},e;const t=F.indexOf(s);return t>-1?e={key:String.fromCharCode(t+48).toLowerCase(),shiftKey:!0}:s!==s.toLowerCase()?e={key:s.toLowerCase(),shiftKey:!0}:e={key:s,shiftKey:!1},e}function P(s){return s.type==="keypress"&&s.which&&s.key?s.which>=65&&s.which<=90?s.shiftKey?s.key:s.key.toLowerCase():s.shiftKey?s.which>=48&&s.which<=57?F[s.which-48]:J[s.which]:s.key:null}function B(s){switch(s){case"HOME":return"home";case"VOLUME_UP":return"volumeUp";case"VOLUME_DOWN":return"volumeDown"}return s}class Q extends Error{constructor(e){var i,r,o,c;let t=e.message;const n=(i=e.playback)==null?void 0:i.event;switch(e.errorId){case"unknown":t=`${e.message}`;break;case"notFound":if(n&&"element"in n){let a=!1;const u=typeof n.element=="object"?{...n.element}:n.element;typeof u=="object"&&"allowMultipleMatches"in u&&(a=!!u.allowMultipleMatches,delete u.allowMultipleMatches),t=`No element${a?"s":""} found for selector | ||
${JSON.stringify(u,null," ")}`}break;case"ambiguousMatch":{const a=(r=e.matchedElements)==null?void 0:r.map(({frame:u,address:l,frameInWindow:p,bounds:f,windowType:w,...$})=>$);a&&(t=`More than 1 element matched the selector. Please specify more attributes to narrow down the matches to a single element, or provide a \`matchIndex\` attribute to select one of the following results | ||
${a.map((u,l)=>`${l}: ${JSON.stringify(u,null," ")}`).join(`, | ||
`)}`);break}default:{const a=e.playback;a!=null&&a.event.id?t=`Action (id: "${a==null?void 0:a.event.id}") failed: ${(r=e.message)!=null?r:e.errorId}`:t=`Action (type: "${a==null?void 0:a.event.type}") failed: ${(c=e.message)!=null?c:e.errorId}`}}super(t),this.name="PlayActionError"}}class P extends Error{constructor(e){super(`App Recorder must be enabled to use ${e}. Please set "record" to true in the config.`),this.name="RecorderRequiredError"}}class X extends $.EventEmitter{constructor({socket:e,config:t}){super(),this.actionHistory=[],this.isEnding=!1,this.debug={printActions:({xdoc:i=!1}={})=>{console.log(this.actionHistory.reduce((o,{action:r})=>i?`let actions = ${JSON.stringify(this.actionHistory.map(c=>c.action),null,2)} | ||
`)}`);break}default:{const a=e.playback;a!=null&&a.event.id?t=`Action (id: "${a==null?void 0:a.event.id}") failed: ${(o=e.message)!=null?o:e.errorId}`:t=`Action (type: "${a==null?void 0:a.event.type}") failed: ${(c=e.message)!=null?c:e.errorId}`}}super(t),this.name="PlayActionError"}}class T extends Error{constructor(e){super(`App Recorder must be enabled to use ${e}. Please set "record" to true in the config.`),this.name="RecorderRequiredError"}}class X extends I.EventEmitter{constructor({socket:e,config:t}){super(),this.actionHistory=[],this.isEnding=!1,this.debug={printActions:({xdoc:i=!1}={})=>{console.log(this.actionHistory.reduce((r,{action:o})=>i?`let actions = ${JSON.stringify(this.actionHistory.map(c=>c.action),null,2)} | ||
@@ -21,4 +21,4 @@ let nextAction = actions.shift() | ||
window.postMessage({ type: 'playEvent', value: { event: nextAction } }, '*') | ||
`:" "+o+` | ||
`+JSON.stringify(r,null,2),""))}},this.config=t,this.socket=e;const n=({type:i,value:o})=>{const r=U(i,o);switch(i){case"adbOverTcp":{this.adbConnectionInfo={...o,command:G(o)};break}case"networkInspectorUrl":this.networkInspectorUrl=o;break}r?(this.emit(r.type,r.value),this.emit("*",r)):(this.emit(i,o),this.emit("*",{type:i,value:o}))};this.socket.on("*",n),this.on("disconnect",()=>{if(this.socket.off("*",n),!this.isEnding)throw new Error("Session disconnected unexpectedly")})}on(e,t){return e==="network"&&this.config.proxy!=="intercept"&&console.warn(`Session must be configured to use a proxy in order to listen to network events. You can do this with | ||
`:" "+r+` | ||
`+JSON.stringify(o,null,2),""))}},this.config=t,this.socket=e;const n=({type:i,value:r})=>{const o=U(i,r);switch(i){case"adbOverTcp":{this.adbConnectionInfo={...r,command:G(r)};break}case"networkInspectorUrl":this.networkInspectorUrl=r;break}o?(this.emit(o.type,o.value),this.emit("*",o)):(this.emit(i,r),this.emit("*",{type:i,value:r}))};this.socket.on("*",n),this.on("disconnect",()=>{if(this.socket.off("*",n),!this.isEnding)throw new Error("Session disconnected unexpectedly")})}on(e,t){return e==="network"&&this.config.proxy!=="intercept"&&console.warn(`Session must be configured to use a proxy in order to listen to network events. You can do this with | ||
@@ -33,12 +33,12 @@ startSession({ proxy: "intercept" })`),e==="log"&&this.config.debug!==!0&&console.warn(`Session must be configured to use debug mode in order to listen to log events. You can do this with | ||
startSession({ enableAdb: true })`);return this.adbConnectionInfo?this.adbConnectionInfo:D(()=>{if(this.adbConnectionInfo)return this.adbConnectionInfo;throw new Error("Timed out waiting for adb connection")})}async rotate(e){const[t]=await Promise.all([this.waitForEvent("orientationChanged"),this.socket.send("userInteraction",{type:"keypress",key:e==="left"?"rotateLeft":"rotateRight",timeStamp:Date.now()})]);return t}async screenshot(e="buffer"){this.socket.send("getScreenshot");const t=await m(this.socket,"screenshot",{timeout:6e4});if(!t.success)throw new Error("Screenshot failed");return{data:e==="buffer"?(o=>typeof window=="undefined"?Buffer.from(o):o)(t.data):V(new Uint8Array(t.data),t.mimeType),mimeType:t.mimeType}}async heartbeat(){return this.socket.send("heartbeat")}async type(e){this.config.platform==="ios"&&await I(1e3);const t=[...e].map(J);if(this.config.record)return this.playAction({type:"keypress",keypress:{type:"keypressArray",shiftKeyArray:t.map(n=>n.shiftKey),keyArray:t.map(n=>n.key),value:e}});await Promise.all([this.socket.send("userInteraction",{type:"keypressArray",shiftKeyArray:t.map(n=>n.shiftKey),keyArray:t.map(n=>n.key),value:e}),this.waitForEvent("interaction",{predicate:n=>n.type==="keypressArray"})])}async keypress(e,t){if(e==="ANDROID_KEYCODE_MENU")return this.socket.send("androidKeycodeMenu");e=B(e);const n=Date.now(),[i]=await Promise.all([this.waitForEvent("interaction",{predicate:o=>o.type==="keypress"&&o.timeStamp===n}),this.socket.send("userInteraction",{type:"keypress",key:e,timeStamp:n,...t})]);return i}async setLanguage(e){this.config.language=e,await this.socket.send("setLanguage",{language:e,timeStamp:Date.now()})}async setLocation(e,t){const n=[e.toString(),t.toString()];return this.config.location=n,this.socket.send("setLocation",{location:n,timeStamp:Date.now()})}async openUrl(e){return this.socket.send("openUrl",{url:e,timeStamp:Date.now()})}async shake(){return this.socket.send("shakeDevice")}async biometry({match:e}){return this.socket.send(e?"biometryMatch":"biometryNoMatch")}async allowInteractions(e){return this.socket.send(e?"enableInteractions":"disableInteractions")}async restartApp(){this.socket.send("restartApp");const{platform:e}=this.config;e==="ios"?await this.waitForEvent("appLaunch",{timeout:6e4}):await I(1e3)}async reinstallApp(){this.socket.send("reinstallApp"),await this.waitForEvent("appLaunch",{timeout:6e4})}async playAction(e,t={}){if(!this.config.record)throw new P("playAction()");return this.playActions([e],t).then(n=>n[0])}async playActions(e,t={}){const{timeout:n=3e4,strictMatch:i}=t,o=[];if(!this.config.record)throw new P("playActions()");for(const r of e){const{id:c,...a}=r;let u=a.type;switch(u){case"tap":u="click";break}const[l]=await Promise.all([new Promise((p,f)=>{const w=()=>{this.off("playbackFoundAndSent",x),this.off("playbackError",v)},x=async b=>{this.actionHistory.push({action:r,result:b}),w(),p(b)},v=b=>{this.actionHistory.push({action:r,error:b}),w(),f(new Q(b))};this.once("playbackFoundAndSent",x),this.once("playbackError",v)}),this.socket.send("playEvent",{event:{...a,type:u},timeout:Math.round(n/1e3),strictMatch:i,id:c})]);o.push(l)}return o}async getUI({timeout:e=3e4}={}){this.socket.send("dumpUi");const t=await m(this.socket,"uiDump",{timeout:e});return"ui"in t?t.ui:t.result}async findElement(e,{timeout:t,...n}={}){const i=await this.playAction({type:"assert",element:e},{timeout:t,...n});if(i.matchedElements)return i.matchedElements[0];if(i.matchedElement)return i.matchedElement}async findElements(e,t){const n=await this.playAction({type:"assert",element:{...e,allowMultipleMatches:!0}},t);return n.matchedElements?n.matchedElements:n.matchedElement?[n.matchedElement]:[]}async tap(e){if("element"in e){if(!this.config.record)throw new P('"element" selector');return this.playAction({type:"click",element:e.element})}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:t=>t.type==="mouseup"})}async swipe(e){if(!this.config.record)throw new P("swipe()");let t;if(e instanceof C)t=e.toAction();else{const{duration:n=300,direction:i}=e;let o=e.distance;const r=new C({steps:25,stepDuration:n/25});if("element"in e){o||(o=i==="up"||i==="down"?"50vh":"50vw"),r.from(e.element);const c=h(o),a=y(o),u=i==="up"||i==="left"?-1:1;switch(i){case"up":case"down":r.to(0,u*c+a);break;case"left":case"right":r.to(u*c+a,0);break}}else{const c=h(e.x),a=y(e.x),u=h(e.y),l=y(e.y);o||(i==="left"||i==="right"?a?o=50+a:o=300:l?o=50+l:o=300);const p=h(o),f=y(o);if((i==="up"||i==="down")&&l!==f)throw new Error(`Distance unit (${f||"px"}) does not match y unit (${l||"px"})`);if((i==="left"||i==="right")&&a!==f)throw new Error(`Distance unit (${f||"px"}) does not match x unit (${a||"px"})`);switch(r.from(e.x,e.y),i){case"up":r.to(e.x,`${u-p}${l}`);break;case"down":r.to(e.x,`${u+p}${l}`);break;case"left":r.to(`${c-p}${a}`,e.y);break;case"right":r.to(`${c+p}${a}`,e.y);break}}t=r.toAction()}return this.playAction(t)}}function G(s){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(!s||!s.forwards[0])return;let t=e;return t=t.replace(/SERVER_PORT/,s.port.toString()),t=t.replace(/USERNAME/,s.user),t=t.replace(/HOSTNAME/,s.hostname),t=t.replace(/FORWARD_DESTINATION/,s.forwards[0].destination),t=t.replace(/FORWARD_PORT/,s.forwards[0].port.toString()),t}function Z({type:s,value:e}){switch(s){case"chromeDevToolsUrl":return{type:"networkInspectorUrl",value:e};case"orientationChanged":return{type:"orientationChanged",value:e}}}const O="0.1.4";class ee extends $.EventEmitter{constructor({page:e}){super(),this.ready=!1,this.page=e,this.page.exposeFunction("__appetize_on",t=>{const n=t==="string"?t:t.type;this.emit(n,t.value),this.emit("*",{type:n,value:t.value})})}async init(){this.ready=!1,await this.page.evaluate(async([e])=>new Promise(t=>{const n=setTimeout(()=>{throw new Error("Unable to find Appetize device on page (timed out after 60 seconds)")},6e4),i=setInterval(()=>{const o=new MessageChannel;o.port1.onmessage=()=>{clearInterval(i),clearTimeout(n),t(!1)},window.postMessage({type:"init",appetizeClient:!0,version:e},"*",[o.port2]),window.__appetize_postMessage=async(r,c=!1)=>{const a=new MessageChannel;if(window.postMessage(r,"*",[a.port2]),c)return new Promise((u,l)=>{const p=setTimeout(()=>{l(new Error("Timed out waiting for postMessage response"))},6e4);a.port1.onmessage=f=>{clearTimeout(p),u(f.data)}})}},100)}),[O]),await this.page.evaluate(()=>{window.addEventListener("message",e=>{e.source===window&&window.__appetize_on(e.data)})},[]),this.ready=!0}async waitUntilReady(){return D(async()=>{if(!this.ready)throw new Error("Timed out waiting for Appetize window to be ready.")},3e4)}async postMessage(e,t=!1){return await this.waitUntilReady(),this.page.evaluate(async([n,i])=>window.__appetize_postMessage(n,i),[e,t])}}class N extends $.EventEmitter{constructor({page:e,type:t,window:n}){super(),this.page=e,this.type=t,this.window=n,this.window.on("*",({type:i,value:o})=>{switch(i){case"socketEvent":o.socket===this.type&&(this.emit(o.type,o.value),this.emit("*",{type:o.type,value:o.value}));break;case"disconnect":this.emit("disconnect"),this.emit("*",{type:"disconnect"});break;case"sessionInfo":case"chromeDevToolsUrl":case"orientationChanged":if(this.type==="appetizer"){const r=Z({type:i,value:o});r&&(this.emit(r.type,r.value),this.emit("*",r))}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 m(this,e,t)}}async function te(s){await s.pause()}const g=function(){const s="[Appetize]";return Function.prototype.bind.call(console.log,console,s)}();class se{constructor({testInfo:e,session:t}){this.currentRecord=0,this.session=t,this.testInfo=e}async record(){const e=this.testInfo.file,t=await R.default.promises.readFile(e,"utf8"),i=t.split(` | ||
`).map((o,r)=>({line:o,num:r+1})).slice(this.testInfo.line).filter(({line:o})=>o.includes("session.record()"))[this.currentRecord].num;if(i!==void 0){g(`\u{1F534} Recording at line ${i}`);let o=[];const r=u=>{ie(u),ne(o,u),g(K(u))},c=u=>{o=o.filter(l=>l.id!==u.id)};this.session.on("action",r),this.session.on("deletedAction",c),await te(this.session.page),await I(2e3),this.session.off("action",r);const a=t.split(` | ||
`).map((u,l)=>{var p,f;if(l===i-1){const w=(f=(p=u.match(/^\s*/))==null?void 0:p[0])!=null?f:0;return`${o.map(v=>K(v)).reduce((v,b,ce)=>`${v} | ||
// ${ce+1}. ${b}`,"// Recorded using session.record()")} | ||
await session.playActions(${JSON.stringify(o,null," ")})`.split(` | ||
`).map(v=>w+v).join(` | ||
startSession({ enableAdb: true })`);return this.adbConnectionInfo?this.adbConnectionInfo:D(()=>{if(this.adbConnectionInfo)return this.adbConnectionInfo;throw new Error("Timed out waiting for adb connection")})}async rotate(e){const[t]=await Promise.all([this.waitForEvent("orientationChanged"),this.socket.send("userInteraction",{type:"keypress",key:e==="left"?"rotateLeft":"rotateRight",timeStamp:Date.now()})]);return t}async screenshot(e="buffer"){this.socket.send("getScreenshot");const t=await m(this.socket,"screenshot",{timeout:6e4});if(!t.success)throw new Error("Screenshot failed");return{data:e==="buffer"?(r=>typeof window=="undefined"?Buffer.from(r):r)(t.data):V(new Uint8Array(t.data),t.mimeType),mimeType:t.mimeType}}async heartbeat(){return this.socket.send("heartbeat")}async type(e){this.config.platform==="ios"&&await M(1e3);const t=[...e].map(Y);if(this.config.record)return this.playAction({type:"keypress",keypress:{type:"keypressArray",shiftKeyArray:t.map(n=>n.shiftKey),keyArray:t.map(n=>n.key),value:e}});await Promise.all([this.socket.send("userInteraction",{type:"keypressArray",shiftKeyArray:t.map(n=>n.shiftKey),keyArray:t.map(n=>n.key),value:e}),this.waitForEvent("interaction",{predicate:n=>n.type==="keypressArray"})])}async keypress(e,t){if(e==="ANDROID_KEYCODE_MENU")return this.socket.send("androidKeycodeMenu");e=B(e);const n=Date.now(),[i]=await Promise.all([this.waitForEvent("interaction",{predicate:r=>r.type==="keypress"&&r.timeStamp===n}),this.socket.send("userInteraction",{type:"keypress",key:e,timeStamp:n,...t})]);return i}async setLanguage(e){this.config.language=e,await this.socket.send("setLanguage",{language:e,timeStamp:Date.now()})}async setLocation(e,t){const n=[e.toString(),t.toString()];return this.config.location=n,this.socket.send("setLocation",{location:n,timeStamp:Date.now()})}async openUrl(e){return this.socket.send("openUrl",{url:e,timeStamp:Date.now()})}async shake(){return this.socket.send("shakeDevice")}async biometry({match:e}){return this.socket.send(e?"biometryMatch":"biometryNoMatch")}async allowInteractions(e){return this.socket.send(e?"enableInteractions":"disableInteractions")}async restartApp(){this.socket.send("restartApp");const{platform:e}=this.config;e==="ios"?await this.waitForEvent("appLaunch",{timeout:6e4}):await M(1e3)}async reinstallApp(){this.socket.send("reinstallApp"),await this.waitForEvent("appLaunch",{timeout:6e4})}async playAction(e,t={}){if(!this.config.record)throw new T("playAction()");return this.playActions([e],t).then(n=>n[0])}async playActions(e,t={}){const{timeout:n=3e4,strictMatch:i}=t,r=[];if(!this.config.record)throw new T("playActions()");for(const o of e){const{id:c,...a}=o;let u=a.type;switch(u){case"tap":u="click";break}const[l]=await Promise.all([new Promise((p,f)=>{const w=()=>{this.off("playbackFoundAndSent",$),this.off("playbackError",S)},$=async A=>{this.actionHistory.push({action:o,result:A}),w(),p(A)},S=A=>{this.actionHistory.push({action:o,error:A}),w(),f(new Q(A))};this.once("playbackFoundAndSent",$),this.once("playbackError",S)}),this.socket.send("playEvent",{event:{...a,type:u},timeout:Math.round(n/1e3),strictMatch:i,id:c})]);r.push(l)}return r}async getUI({timeout:e=3e4}={}){this.socket.send("dumpUi");const t=await m(this.socket,"uiDump",{timeout:e});return"ui"in t?t.ui:t.result}async findElement(e,{timeout:t,...n}={}){const i=await this.playAction({type:"assert",element:e},{timeout:t,...n});if(i.matchedElements)return i.matchedElements[0];if(i.matchedElement)return i.matchedElement}async findElements(e,t){const n=await this.playAction({type:"assert",element:{...e,allowMultipleMatches:!0}},t);return n.matchedElements?n.matchedElements:n.matchedElement?[n.matchedElement]:[]}async tap(e){if("element"in e){if(!this.config.record)throw new T('"element" selector');return this.playAction({type:"click",element:e.element})}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:t=>t.type==="mouseup"})}async swipe(e){if(!this.config.record)throw new T("swipe()");let t;if(e instanceof C)t=e.toAction();else{const{duration:n=300,direction:i}=e;let r=e.distance;const o=new C({steps:25,stepDuration:n/25});if("element"in e){r||(r=i==="up"||i==="down"?"50vh":"50vw"),o.from(e.element);const c=h(r),a=y(r),u=i==="up"||i==="left"?-1:1;switch(i){case"up":case"down":o.to(0,u*c+a);break;case"left":case"right":o.to(u*c+a,0);break}}else{const c=h(e.x),a=y(e.x),u=h(e.y),l=y(e.y);r||(i==="left"||i==="right"?a?r=50+a:r=300:l?r=50+l:r=300);const p=h(r),f=y(r);if((i==="up"||i==="down")&&l!==f)throw new Error(`Distance unit (${f||"px"}) does not match y unit (${l||"px"})`);if((i==="left"||i==="right")&&a!==f)throw new Error(`Distance unit (${f||"px"}) does not match x unit (${a||"px"})`);switch(o.from(e.x,e.y),i){case"up":o.to(e.x,`${u-p}${l}`);break;case"down":o.to(e.x,`${u+p}${l}`);break;case"left":o.to(`${c-p}${a}`,e.y);break;case"right":o.to(`${c+p}${a}`,e.y);break}}t=o.toAction()}return this.playAction(t)}}function G(s){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(!s||!s.forwards[0])return;let t=e;return t=t.replace(/SERVER_PORT/,s.port.toString()),t=t.replace(/USERNAME/,s.user),t=t.replace(/HOSTNAME/,s.hostname),t=t.replace(/FORWARD_DESTINATION/,s.forwards[0].destination),t=t.replace(/FORWARD_PORT/,s.forwards[0].port.toString()),t}function Z({type:s,value:e}){switch(s){case"chromeDevToolsUrl":return{type:"networkInspectorUrl",value:e};case"orientationChanged":return{type:"orientationChanged",value:e}}}const O="0.1.5";class ee extends I.EventEmitter{constructor({page:e}){super(),this.ready=!1,this.page=e,this.page.exposeFunction("__appetize_on",t=>{const n=t==="string"?t:t.type;this.emit(n,t.value),this.emit("*",{type:n,value:t.value})})}async init(){this.ready=!1,await this.page.evaluate(async([e])=>new Promise(t=>{const n=setTimeout(()=>{throw new Error("Unable to find Appetize device on page (timed out after 60 seconds)")},6e4),i=setInterval(()=>{const r=new MessageChannel;r.port1.onmessage=()=>{clearInterval(i),clearTimeout(n),t(!1)},window.postMessage({type:"init",appetizeClient:!0,version:e},"*",[r.port2]),window.__appetize_postMessage=async(o,c=!1)=>{const a=new MessageChannel;if(window.postMessage(o,"*",[a.port2]),c)return new Promise((u,l)=>{const p=setTimeout(()=>{l(new Error("Timed out waiting for postMessage response"))},6e4);a.port1.onmessage=f=>{clearTimeout(p),u(f.data)}})}},100)}),[O]),await this.page.evaluate(()=>{window.addEventListener("message",e=>{e.source===window&&window.__appetize_on(e.data)})},[]),this.ready=!0}async waitUntilReady(){return D(async()=>{if(!this.ready)throw new Error("Timed out waiting for Appetize window to be ready.")},3e4)}async postMessage(e,t=!1){return await this.waitUntilReady(),this.page.evaluate(async([n,i])=>window.__appetize_postMessage(n,i),[e,t])}}class N extends I.EventEmitter{constructor({page:e,type:t,window:n}){super(),this.page=e,this.type=t,this.window=n,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=Z({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 m(this,e,t)}}async function te(s){await s.pause()}const g=function(){const s="[Appetize]";return Function.prototype.bind.call(console.log,console,s)}();class se{constructor({testInfo:e,session:t}){this.currentRecord=0,this.session=t,this.testInfo=e}async record(){const e=this.testInfo.file,t=await R.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){g(`\u{1F534} Recording at line ${i}`);let r=[];const o=u=>{ie(u),ne(r,u),g(K(u))},c=u=>{r=r.filter(l=>l.id!==u.id)};this.session.on("action",o),this.session.on("deletedAction",c),await te(this.session.page),await M(2e3),this.session.off("action",o);const a=t.split(` | ||
`).map((u,l)=>{var p,f;if(l===i-1){const w=(f=(p=u.match(/^\s*/))==null?void 0:p[0])!=null?f:0;return`${r.map(S=>K(S)).reduce((S,A,ce)=>`${S} | ||
// ${ce+1}. ${A}`,"// Recorded using session.record()")} | ||
await session.playActions(${JSON.stringify(r,null," ")})`.split(` | ||
`).map(S=>w+S).join(` | ||
`)}return u});await R.default.promises.writeFile(e,a.join(` | ||
`)),g("\u{1F7E2} Finished"),this.currentRecord+=1}}}function ne(s,e){const t=s[s.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"?s[s.length-1]={...t,keypress:{type:"keypressArray",shiftKeyArray:[t.keypress.shiftKey,e.keypress.shiftKey],keyArray:[t.keypress.key,e.keypress.key],value:M(t.keypress)+M(e.keypress)}}:s[s.length-1]={...t,keypress:{type:"keypressArray",shiftKeyArray:[...t.keypress.shiftKeyArray,e.keypress.shiftKey],keyArray:[...t.keypress.keyArray,e.keypress.key],value:t.keypress.value+M(e.keypress)}}:s.push(e);break;default:s.push(e)}else s.push(e)}function K(s){let e="";switch(s.type){case"swipe":case"click":{const t=s.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}"`:s.xPos&&s.yPos&&(e=`position ${s.xPos}, ${s.yPos}`),e?`${s.type} on ${e}`:s.type}case"keypress":return s.keypress.type==="keypress"?`type "${M(s.keypress)}"`:`type "${s.keypress.value}"`;default:return s.type}}function ie(s){switch(s.type){case"click":case"swipe":delete s.ui;break}return s}class oe extends X{constructor({page:e,config:t,window:n,testInfo:i}){const o=new N({page:e,window:n,type:"appetizer"});super({socket:o,config:t}),this.window=n,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){const[t]=await Promise.all([m(this.window,"orientationChanged"),await this.window.postMessage(e==="left"?"rotateLeft":"rotateRight")]);return this.window.page.waitForTimeout(1e3),t}async screenshot(e="buffer"){const[t]=await Promise.all([m(this.socket,"screenshot",{timeout:6e4}),this.socket.send("getScreenshot")]),n=new Uint8Array(Object.values(t.data).map(Number));return{data:e==="buffer"?Buffer.from(n):t.data,mimeType:t.mimeType}}async record(){if(!this.config.record)throw new Error("Recording is not enabled, please enable it by setting `record: true` in session config");if(!this.testInfo)throw new Error("session.record() requires using `session` from the test() arguments");return new se({session:this,testInfo:this.testInfo}).record()}async waitForEvent(e,t){return m(this.socket,e,t)}async waitForTimeout(e){return I(e)}async waitForElement(e,t){const n=await this.findElements(e,t);if(typeof(t==null?void 0:t.matches)=="number"?n.length===t.matches:n.length>0)return n;throw new Error(`Element not found: | ||
${JSON.stringify(e)}`)}}class re extends $.EventEmitter{constructor({socket:e}){super(),this.socket=e,this.socket.on("*",({type:t,value:n})=>{const i=U(t,n);if(i)this.emit(i.type,i.value),this.emit("*",i);else switch(t){case"newSession":break;default:this.emit(t,n),this.emit("*",{type:t,value:n})}}),this.socket.on("disconnect",()=>{throw new Error("Client disconnected unexpectedly")})}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,n)=>{const i=()=>{n(new Error("Session failed to start - client disconnected"))},o=c=>{n(new Error(`Session failed to start - ${typeof c.message=="object"?JSON.stringify(c.message):c.message}`))},r=c=>{c.message.match(/Too many requests/)&&n(new Error("Session failed to start - too many requests"))};try{this.on("error",r),e.on("disconnect",i),e.on("error",o),await e.waitForEvent("ready",{timeout:null})}finally{this.off("error",r),e.off("disconnect",i),e.off("error",o)}t(e)})}}const q=new WeakMap;class ae extends re{constructor({page:e}){var o;const t=(o=q.get(e))!=null?o:new ee({page:e});q.set(e,t),t.init();const n=new N({type:"webserver",page:e,window:t});super({socket:n}),this.page=e,this.window=t,this.window.on("*",({type:r,value:c})=>{switch(r){case"config":this.currentConfig=c;break}});let i=!1;this.on("queue",({type:r,position:c})=>{r==="account"&&i!=="account"?(i="account",g("All slots for this account are currently in use. Please wait until a slot becomes available.")):(i==="account"?g("You are now in the regular queue."):i||g("All devices are currently in use. Please wait until requested device becomes available."),i="session"),c>0&&g(`Position in queue: ${c}`)}),this.on("session",()=>{i&&(g("Session is ready to start"),i=!1)})}async startSession({testInfo:e,...t}={}){var r;await this.window.waitUntilReady();const n=(r=this.page.context().browser())==null?void 0:r.browserType().name(),i=await this.config({codec:n==="chromium"?"jpeg":"h264",record:!0,...t,apiVersion:O}),o=new oe({config:i,page:this.page,window:this.window,testInfo:e});return this.window.postMessage({type:"requestSession"}),await this.waitForSessionStart(o),o}async config({publicKey:e,...t}){return e&&await Promise.all([this.window.postMessage({type:"loadApp",value:e}),m(this.window,"app",{predicate(i){return i.publicKey===e}})]),this.window.postMessage({type:"setConfig",value:t}),await m(this.window,"config")}}k.expect.extend({toHaveElement:async(s,e,t={})=>{try{const n=await s.findElements(e,t);return{pass:typeof t.matches=="number"?n.length===t.matches:n.length>0,message:()=>`Element not found: | ||
${JSON.stringify(e)}`}}catch(n){return{pass:!1,message:()=>n.message}}}});let E,S,T;const A=Object.assign(k.test.extend({_autoSnapshotSuffix:[async({},s,e)=>{e.snapshotSuffix="",await s()},{auto:!0}],page:async({},s)=>{if(!S)throw new Error("Appetize not initialized. Make sure you have run test.setup()");await s(S.page)},session:async({},s)=>{if(!T)throw new Error("Session was not started. Make sure you have run test.setup()");await s(T)},client:async({},s)=>{if(!S)throw new Error("Appetize not initialized. Make sure you have run test.setup()");await s(S)}}),{setup(s){A.afterEach(async({session:e},t)=>{}),A.beforeAll(async({browser:e,baseURL:t},n)=>{var i,o;if(n.config.fullyParallel)throw new Error("fullyParallel is not allowed when running Appetize tests. Please set `fullyParallel: false` in your Playwright config");if(A.setTimeout(6e4*5),E||(E=await e.newPage(),E.on("close",()=>{E=null,S=null,T=null})),"url"in s)await E.goto(s.url);else{const r=new URLSearchParams;s.device&&r.set("device",s.device),s.deviceColor&&r.set("deviceColor",s.deviceColor),s.screenOnly&&r.set("screenOnly",s.screenOnly.toString()),r.set("scale",(o=(i=s.scale)==null?void 0:i.toString())!=null?o:"auto"),await E.goto(`${t!=null?t:"https://appetize.io"}/embed/${s.publicKey}?${r.toString()}`)}S=new ae({page:E}),T=await W(()=>S.startSession({...s,testInfo:n}),{retries:5,timeout:3e4,predicate:(r,c)=>r instanceof Error&&r.message.match(/too many requests/)?(console.warn(`Too many session requests. Retrying in 30 seconds... (attempt #${c})`),!0):!1})}),A.afterAll(async({session:e},t)=>{await e.page.close()})}});Object.defineProperty(d,"expect",{enumerable:!0,get:function(){return k.expect}}),d.SwipeGesture=C,d.getSwipeUnit=y,d.getSwipeValue=h,d.test=A,Object.defineProperties(d,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); | ||
`)),g("\u{1F7E2} Finished"),this.currentRecord+=1}}}function ne(s,e){const t=s[s.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"?s[s.length-1]={...t,keypress:{type:"keypressArray",shiftKeyArray:[t.keypress.shiftKey,e.keypress.shiftKey],keyArray:[t.keypress.key,e.keypress.key],value:P(t.keypress)+P(e.keypress)}}:s[s.length-1]={...t,keypress:{type:"keypressArray",shiftKeyArray:[...t.keypress.shiftKeyArray,e.keypress.shiftKey],keyArray:[...t.keypress.keyArray,e.keypress.key],value:t.keypress.value+P(e.keypress)}}:s.push(e);break;default:s.push(e)}else s.push(e)}function K(s){let e="";switch(s.type){case"swipe":case"click":{const t=s.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}"`:s.xPos&&s.yPos&&(e=`position ${s.xPos}, ${s.yPos}`),e?`${s.type} on ${e}`:s.type}case"keypress":return s.keypress.type==="keypress"?`type "${P(s.keypress)}"`:`type "${s.keypress.value}"`;default:return s.type}}function ie(s){switch(s.type){case"click":case"swipe":delete s.ui;break}return s}class re extends X{constructor({page:e,config:t,window:n,testInfo:i}){const r=new N({page:e,window:n,type:"appetizer"});super({socket:r,config:t}),this.window=n,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){const[t]=await Promise.all([m(this.window,"orientationChanged"),await this.window.postMessage(e==="left"?"rotateLeft":"rotateRight")]);return this.window.page.waitForTimeout(1e3),t}async screenshot(e="buffer"){const[t]=await Promise.all([m(this.socket,"screenshot",{timeout:6e4}),this.socket.send("getScreenshot")]),n=new Uint8Array(Object.values(t.data).map(Number));return{data:e==="buffer"?Buffer.from(n):t.data,mimeType:t.mimeType}}async record(){if(!this.config.record)throw new Error("Recording is not enabled, please enable it by setting `record: true` in session config");if(!this.testInfo)throw new Error("session.record() requires using `session` from the test() arguments");return new se({session:this,testInfo:this.testInfo}).record()}async waitForEvent(e,t){return m(this.socket,e,t)}async waitForTimeout(e){return M(e)}async waitForElement(e,t){const n=await this.findElements(e,t);if(typeof(t==null?void 0:t.matches)=="number"?n.length===t.matches:n.length>0)return n;throw new Error(`Element not found: | ||
${JSON.stringify(e)}`)}}class oe extends I.EventEmitter{constructor({socket:e}){super(),this.socket=e,this.socket.on("*",({type:t,value:n})=>{const i=U(t,n);if(i)this.emit(i.type,i.value),this.emit("*",i);else switch(t){case"newSession":break;default:this.emit(t,n),this.emit("*",{type:t,value:n})}}),this.socket.on("disconnect",()=>{throw new Error("Client disconnected unexpectedly")})}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,n)=>{const i=()=>{n(new Error("Session failed to start - client disconnected"))},r=c=>{n(new Error(`Session failed to start - ${typeof c.message=="object"?JSON.stringify(c.message):c.message}`))},o=c=>{c.message.match(/Too many requests/)&&n(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 q=new WeakMap;class ae extends oe{constructor({page:e}){var r;const t=(r=q.get(e))!=null?r:new ee({page:e});q.set(e,t),t.init();const n=new N({type:"webserver",page:e,window:t});super({socket:n}),this.page=e,this.window=t,this.window.on("*",({type:o,value:c})=>{switch(o){case"config":this.currentConfig=c;break;case"app":this.emit(o,c);break}});let i=!1;this.on("queue",({type:o,position:c})=>{i||(i=!0,g(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.")),c>0&&g(o==="account"?`Position in account-level queue: ${c}`:`Position in queue: ${c}`)}),this.on("session",()=>{i&&(g("Session started"),i=!1)})}async startSession({testInfo:e,...t}={}){var o;await this.window.waitUntilReady();const n=(o=this.page.context().browser())==null?void 0:o.browserType().name(),i=await this.config({codec:n==="chromium"?"jpeg":"h264",record:!0,...t,apiVersion:O}),r=new re({config:i,page:this.page,window:this.window,testInfo:e});return this.window.postMessage({type:"requestSession"}),await this.waitForSessionStart(r),r}async config({publicKey:e,...t}){if(e){const i=await this.window.postMessage({type:"loadApp",value:e},!0);if("error"in i)throw new Error(i.error)}return this.window.postMessage({type:"setConfig",value:t}),await m(this.window,"config")}}b.expect.extend({toHaveElement:async(s,e,t={})=>{try{const n=await s.findElements(e,t);return{pass:typeof t.matches=="number"?n.length===t.matches:n.length>0,message:()=>`Element not found: | ||
${JSON.stringify(e)}`}}catch(n){return{pass:!1,message:()=>n.message}}}});let v,k,E;const x=Object.assign(b.test.extend({_autoSnapshotSuffix:[async({},s,e)=>{e.snapshotSuffix="",await s()},{auto:!0}],page:async({},s)=>{if(!k)throw new Error("Appetize not initialized. Make sure you have run test.setup()");await s(k.page)},session:async({},s)=>{if(!E)throw new Error("Session was not started. Make sure you have run test.setup()");await s(E)},client:async({},s)=>{if(!k)throw new Error("Appetize not initialized. Make sure you have run test.setup()");await s(k)}}),{setup(s){x.afterEach(async({session:e},t)=>{}),x.beforeAll(async({browser:e,baseURL:t},n)=>{var i,r;if(n.config.fullyParallel)throw new Error("fullyParallel is not allowed when running Appetize tests. Please set `fullyParallel: false` in your Playwright config");if(x.setTimeout(6e4*5),v||(v=await e.newPage(),v.on("close",()=>{v=null,k=null,E=null})),"url"in s)await v.goto(s.url);else{const o=new URLSearchParams;s.device&&o.set("device",s.device),s.deviceColor&&o.set("deviceColor",s.deviceColor),s.screenOnly&&o.set("screenOnly",s.screenOnly.toString()),o.set("scale",(r=(i=s.scale)==null?void 0:i.toString())!=null?r:"auto"),await v.goto(`${t!=null?t:"https://appetize.io"}/embed/${s.publicKey}?${o.toString()}`)}k=new ae({page:v}),E=await W(()=>k.startSession({...s,testInfo:n}),{retries:5,timeout:3e4,predicate:(o,c)=>o instanceof Error&&o.message.match(/too many requests/)?(console.warn(`Too many session requests. Retrying in 30 seconds... (attempt #${c})`),!0):!1})}),x.afterAll(async({},e)=>{var t;await((t=E==null?void 0:E.page)==null?void 0:t.close()),v=null,k=null,E=null})}});Object.defineProperty(d,"expect",{enumerable:!0,get:function(){return b.expect}}),d.SwipeGesture=C,d.getSwipeUnit=y,d.getSwipeValue=h,d.test=x,Object.defineProperties(d,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); | ||
//# sourceMappingURL=index.umd.js.map |
{ | ||
"name": "@appetize/playwright", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"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
339070
2424