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

@appetize/playwright

Package Overview
Dependencies
Maintainers
4
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@appetize/playwright - npm Package Compare versions

Comparing version 1.0.1 to 1.0.2-beta.0

4

dist/index.umd.js

@@ -11,3 +11,3 @@ var ie=(d,w,b)=>{if(!w.has(d))throw TypeError("Cannot "+b)};var A=(d,w,b)=>(ie(d,w,"read from private field"),b?b.call(d):w.get(d)),j=(d,w,b)=>{if(w.has(d))throw TypeError("Cannot add the same private member more than once");w instanceof WeakSet?w.add(d):w.set(d,b)},B=(d,w,b,O)=>(ie(d,w,"write to private field"),O?O.call(d,b):w.set(d,b),b);(function(d,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):(d=typeof globalThis!="undefined"?globalThis:d||self,w(d.playwright={},d.events,d.test$1,d.fs))})(this,function(d,w,b,O){var k,$;"use strict";function ne(i){return i&&typeof i=="object"&&"default"in i?i:{default:i}}var I=ne(O);async function re(i,{retries:e=3,timeout:t=1e3,predicate:s=()=>!0}){for(let n=1;n<=e;n++)try{return await i()}catch(r){if(n===e||!s(r,n))throw r;await new Promise(o=>setTimeout(o,t))}throw null}function oe(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,i=>{const e=Math.random()*16|0;return(i==="x"?e:e&3|8).toString(16)})}function S(i){return Array.isArray(i)?i.map(S).filter(e=>e!=null):typeof i=="object"&&i!==null?Object.entries(i).reduce((e,[t,s])=>{const n=S(s);return n!=null&&(e[t]=n),e},{}):i}function J(i,e){if("captureStackTrace"in Error)Error.captureStackTrace(i,e);else{const t=new Error;Object.defineProperty(i,"stack",{configurable:!0,get(){const{stack:s}=t;return Object.defineProperty(this,"stack",{value:s}),s}})}}async function l(i,e){i instanceof f&&J(i,e)}class f extends Error{constructor(e){super(e),this.name="Error",this.isOperational=!0,J(this,this.constructor)}}class ae extends f{constructor(e){super(`No element found for selector

${JSON.stringify(t,null,2)}`));break;case"notFound":if(m.playback!==void 0&&"element"in m.playback.action&&m.playback.action.element!==void 0){y(new ae(m.playback.action.element));break}case"ambiguousMatch":if("matchedElements"in m&&m.matchedElements!==void 0){y(new ce(m.matchedElements));break}case"invalidArgument":if("element"in t&&t.element&&m.message.match("outside the screen bounds")){y(new he(t));break}default:y(new f(m.message));break}};this.once("playbackFoundAndSent",v),this.once("playbackError",F)}),this.socket.send("playAction",h)]);return u}catch(r){throw l(r,this.playAction),r}}async playActions(t,s={}){try{if(!this.config.record)throw new M("playActions()");const n=[];for(const r of t){const o=await this.playAction(r,s);n.push(o);const a=t[t.indexOf(r)+1];a&&a.type==="keypress"&&r.type==="keypress"||await D(1e3)}return n}catch(n){throw l(n,this.playActions),n}}async getUI({timeout:t=3e4}={}){try{return this.socket.send("dumpUi"),await _(this,"uiDump",{timeout:t})}catch(s){throw l(s,this.getUI),s}}async findElement(t,s){var n;try{return(n=(await this.playAction({type:"findElements",element:t,appId:s==null?void 0:s.appId},s)).matchedElements)==null?void 0:n[0]}catch(r){throw l(r,this.findElement),r}}async findElements(t,s){try{return(await this.playAction({type:"findElements",element:t,appId:s==null?void 0:s.appId},s)).matchedElements}catch(n){throw l(n,this.findElements),n}}async tap(t,s){var n;try{if(!this.config.record)throw new M("tap()");return await this.playAction({type:"tap",...t,duration:((n=t.duration)!=null?n:0)/1e3},s)}catch(r){throw l(r,this.tap),r}}async swipe({duration:t,gesture:s,...n},r){try{if(!this.config.record)throw new M("swipe()");let o;const a=new be({duration:t});if(typeof s=="function")s(a);else switch(s){case"up":a.up();break;case"down":a.down();break;case"left":a.left();break;case"right":a.right();break}if("element"in n)o={type:"swipe",element:n.element,localPosition:n.localPosition,moves:a.build()};else if("position"in n)o={type:"swipe",position:n.position,moves:a.build()};else throw new Error("Either element or position must be specified");return this.playAction(o,r)}catch(o){throw l(o,this.swipe),o}}async addActionLog(t){this.actionLogs.push(t)}async getAdbInfo(){return this.logger.warn("getAdbInfo() is deprecated. Please use the `adbConnection` property instead."),Promise.resolve(A(this,k))}async getNetworkInspectorUrl(){return this.logger.warn("getNetworkInspectorUrl() is deprecated. Please use the `networkInspectorUrl` property instead."),Promise.resolve(A(this,$))}async getDeviceInfo(){return this.logger.warn("getDeviceInfo() is deprecated. Please use the `device` property instead."),Promise.resolve(this.device)}}k=new WeakMap,$=new WeakMap;function xe(i){const e="ssh -fN -o StrictHostKeyChecking=no -oHostKeyAlgorithms=+ssh-rsa -p SERVER_PORT USERNAME@HOSTNAME -L6000:FORWARD_DESTINATION:FORWARD_PORT && adb connect localhost:6000";if(!i||!i.forwards[0])return;let t=e;return t=t.replace(/SERVER_PORT/,i.port.toString()),t=t.replace(/USERNAME/,i.user),t=t.replace(/HOSTNAME/,i.hostname),t=t.replace(/FORWARD_DESTINATION/,i.forwards[0].destination),t=t.replace(/FORWARD_PORT/,i.forwards[0].port.toString()),t}b.expect.extend({toHaveElement:async(i,e,t={})=>{try{const s=await i.findElements(e,t);return{pass:typeof t.matches=="number"?s.length===t.matches:s.length>0,message:()=>`Element not found:
${JSON.stringify(e,null,2)}`}}catch(s){return{pass:!1,message:()=>s.message}}}});class Ee extends w.EventEmitter{constructor({socket:e,logger:t=new U}){super(),this.logger=t,this.socket=e,this.socket.on("*",({type:s,value:n})=>{const r=ke(s,n);r!==null&&(r?(this.emit(r.type,r.value),this.emit("*",r)):(this.emit(s,n),this.emit("*",{type:s,value:n})))})}on(e,t){return super.on(e,t)}async startSession(e){throw new Error("Not implemented")}async setConfig(e){throw new Error("Not implemented")}getConfig(){return this._config}async waitForSessionStart(e){return new Promise(async(t,s)=>{const n=()=>{s(new Error("Session disconnected before it was ready"))},r=a=>{s(new Error(`Session failed to start - ${typeof a.message=="object"?JSON.stringify(a.message):a.message}`))},o=a=>{a.message.match(/Too many requests/)&&s(new Error("Session failed to start due to too many requests"))};try{this.on("error",o),e.on("disconnect",n),e.on("error",r),await e.waitUntilReady()}finally{this.off("error",o),e.off("disconnect",n),e.off("error",r)}t(e)})}}function ke(i,e){switch(i){case"concurrentQueue":return{type:"queue",value:{type:"concurrent",name:e.name,position:e.position}};case"queue":return{type:"queue",value:{type:"session",position:e.position}};case"userError":return{type:"error",value:e};case"newSession":return null}}class Ae extends Ee{constructor({socket:e,window:t,logger:s=new U}){super({socket:e,logger:s}),this.ready=!1,this.window=t,this.window.on("*",async({type:n,value:r})=>{switch(n){case"app":this.app=r,this.emit(n,r);break;case"deviceInfo":this.device=r,this.emit(n,r);break;case"config":this._config=this.mapConfig(r);break}}),this.socket.on("*",async({type:n,value:r})=>{switch(n){case"newSession":try{this.session=this.createSession(this._config,{path:r.path,token:r.sessionToken}),await this.waitForSessionStart(this.session),this.emit("session",this.session)}catch(o){this.emit("sessionError",o)}}}),this.init()}async init(){await this.window.waitUntilReady();const[e,t]=await Promise.all([this.window.postMessage({type:"getApp"},!0),this.window.postMessage({type:"getDeviceInfo"},!0),this.setConfig({record:!0})]);this.app=e,this.device=t,this.ready=!0}async waitUntilReady(){if(!this.ready)return H(async()=>{if(!this.ready)throw new Error("Timed out waiting for client to be ready")},3e4)}async startSession(e){await this.waitUntilReady(),await this.setConfig(e!=null?e:{});const[t]=await Promise.all([new Promise((s,n)=>{const r=a=>{this.off("session",r),this.off("sessionError",o),s(a)},o=a=>{this.off("session",r),this.off("sessionError",o),n(a)};this.on("session",r),this.on("sessionError",o)}),this.window.postMessage({type:"requestSession"},!0)]);return t}async config(e){return this.logger.warn("client.config() is deprecated and will be removed in a future major release. Use client.setConfig() instead."),this.setConfig(e)}async setConfig({publicKey:e,...t}){if(e){const n=await this.window.postMessage({type:"loadApp",value:e},!0);if(n&&"error"in n)throw new Error(n.error)}const s=await this.window.postMessage({type:"setConfig",value:this.validateConfig(t!=null?t:{})},!0).then(this.mapConfig);return this._config=s,s}mapConfig(e){return{...e,device:e.deviceType||e.device}}validateConfig(e){return e}createSession(e,t){throw new Error("Not implemented")}}class Se extends U{constructor(){super(...arguments),this.logHistory=[],this.logLevel=process.env.CI==="true"?"warnings-errors":"verbose",this.log=(...e)=>{if(this.logHistory.push({method:"log",data:e}),this.logLevel==="verbose")return console.log(...e)},this.warn=(...e)=>{if(this.logHistory.push({method:"warn",data:e}),this.logLevel==="verbose"||this.logLevel==="warnings-errors")return console.warn(...e)},this.error=(...e)=>{if(this.logHistory.push({method:"error",data:e}),this.logLevel==="verbose"||this.logLevel==="warnings-errors")return console.error(...e)},this.debug=(...e)=>{if(this.logHistory.push({method:"debug",data:e}),this.logLevel==="verbose")return console.debug(...e)},this.clearLogHistory=()=>{this.logHistory=[]}}}const T=new Se;async function _e(i){await i.pause()}function V(i){if(i.character)return i.character;const e=i.key;return z(e)?e:i.shiftKey?e.toUpperCase():e.toLowerCase()}function z(i){return/^[\b\t\r]/.test(i)}class Te{constructor({testInfo:e,session:t}){this.currentRecord=0,this.session=t,this.testInfo=e}async record(){const e=this.testInfo.file,t=await I.default.promises.readFile(e,"utf8"),n=t.split(`
${JSON.stringify(e,null,2)}`}}catch(s){return{pass:!1,message:()=>s.message}}}});class Ee extends w.EventEmitter{constructor({socket:e,logger:t=new U}){super(),this.logger=t,this.socket=e,this.socket.on("*",({type:s,value:n})=>{const r=ke(s,n);r!==null&&(r?(this.emit(r.type,r.value),this.emit("*",r)):(this.emit(s,n),this.emit("*",{type:s,value:n})))})}on(e,t){return super.on(e,t)}async startSession(e){throw new Error("Not implemented")}async setConfig(e){throw new Error("Not implemented")}getConfig(){return this._config}async waitForSessionStart(e){return new Promise(async(t,s)=>{const n=()=>{s(new Error("Session disconnected before it was ready"))},r=a=>{s(new Error(`Session failed to start - ${typeof a.message=="object"?JSON.stringify(a.message):a.message}`))},o=a=>{a.message.match(/Too many requests/)&&s(new Error("Session failed to start due to too many requests"))};try{this.on("error",o),e.on("disconnect",n),e.on("error",r),await e.waitUntilReady()}finally{this.off("error",o),e.off("disconnect",n),e.off("error",r)}t(e)})}}function ke(i,e){switch(i){case"concurrentQueue":return{type:"queue",value:{type:"concurrent",name:e.name,position:e.position}};case"queue":return{type:"queue",value:{type:"session",position:e.position}};case"userError":return{type:"error",value:e};case"newSession":return null}}class Ae extends Ee{constructor({socket:e,window:t,logger:s=new U}){super({socket:e,logger:s}),this.ready=!1,this.window=t,this.window.on("*",async({type:n,value:r})=>{switch(n){case"app":this.app=r,this.emit(n,r);break;case"deviceInfo":this.device=r,this.emit(n,r);break;case"config":this._config=this.mapConfig(r);break}}),this.window.on("iframeload",()=>{this.ready=!1,this.session=void 0,this.init()}),this.socket.on("*",async({type:n,value:r})=>{switch(n){case"newSession":try{this.session=this.createSession(this._config,{path:r.path,token:r.sessionToken}),await this.waitForSessionStart(this.session),this.emit("session",this.session)}catch(o){this.emit("sessionError",o)}}}),this.init()}async init(){await this.window.waitUntilReady();const[e,t]=await Promise.all([this.window.postMessage({type:"getApp"},!0),this.window.postMessage({type:"getDeviceInfo"},!0),this.setConfig({record:!0})]);this.app=e,this.device=t,this.ready=!0}async waitUntilReady(){if(!this.ready)return H(async()=>{if(!this.ready)throw new Error("Timed out waiting for client to be ready")},3e4)}async startSession(e){await this.waitUntilReady(),await this.setConfig(e!=null?e:{});const[t]=await Promise.all([new Promise((s,n)=>{const r=a=>{this.off("session",r),this.off("sessionError",o),s(a)},o=a=>{this.off("session",r),this.off("sessionError",o),n(a)};this.on("session",r),this.on("sessionError",o)}),this.window.postMessage({type:"requestSession"},!0)]);return t}async config(e){return this.logger.warn("client.config() is deprecated and will be removed in a future major release. Use client.setConfig() instead."),this.setConfig(e)}async setConfig({publicKey:e,...t}){if(e){const n=await this.window.postMessage({type:"loadApp",value:e},!0);if(n&&"error"in n)throw new Error(n.error)}const s=await this.window.postMessage({type:"setConfig",value:this.validateConfig(t!=null?t:{})},!0).then(this.mapConfig);return this._config=s,s}mapConfig(e){return{...e,device:e.deviceType||e.device}}validateConfig(e){return e}createSession(e,t){throw new Error("Not implemented")}}class Se extends U{constructor(){super(...arguments),this.logHistory=[],this.logLevel=process.env.CI==="true"?"warnings-errors":"verbose",this.log=(...e)=>{if(this.logHistory.push({method:"log",data:e}),this.logLevel==="verbose")return console.log(...e)},this.warn=(...e)=>{if(this.logHistory.push({method:"warn",data:e}),this.logLevel==="verbose"||this.logLevel==="warnings-errors")return console.warn(...e)},this.error=(...e)=>{if(this.logHistory.push({method:"error",data:e}),this.logLevel==="verbose"||this.logLevel==="warnings-errors")return console.error(...e)},this.debug=(...e)=>{if(this.logHistory.push({method:"debug",data:e}),this.logLevel==="verbose")return console.debug(...e)},this.clearLogHistory=()=>{this.logHistory=[]}}}const T=new Se;async function _e(i){await i.pause()}function V(i){if(i.character)return i.character;const e=i.key;return z(e)?e:i.shiftKey?e.toUpperCase():e.toLowerCase()}function z(i){return/^[\b\t\r]/.test(i)}class Te{constructor({testInfo:e,session:t}){this.currentRecord=0,this.session=t,this.testInfo=e}async record(){const e=this.testInfo.file,t=await I.default.promises.readFile(e,"utf8"),n=t.split(`
`).map((r,o)=>({line:r,num:o+1})).slice(this.testInfo.line).filter(({line:r})=>r.includes("session.record()"))[this.currentRecord].num;if(n!==void 0){console.log(`\u{1F534} Recording at line ${n}`);const r=[],o=c=>{Pe(r,c),console.log(Y(c))};this.session.on("action",o),await _e(this.session.page),await D(2e3),this.session.off("action",o);const a=t.split(`

@@ -19,5 +19,5 @@ `).map((c,h)=>{var u,p;if(h===n-1){const y=(p=(u=c.match(/^\s*/))==null?void 0:u[0])!=null?p:0;return`${r.map(v=>Y(v)).reduce((v,F,m)=>`${v}

`)}return c});await I.default.promises.writeFile(e,a.join(`
`)),console.log("\u{1F7E2} Finished"),this.currentRecord+=1}}}function Pe(i,e){const t=i[i.length-1];if(t)switch(e.type){case"keypress":{(t==null?void 0:t.type)==="keypress"&&!z(e.key)&&!z(t.key)?(i.pop(),i.push({type:"typeText",text:V(t)+V(e)})):(t==null?void 0:t.type)==="typeText"&&!z(e.key)?(i.pop(),i.push({type:"typeText",text:t.text+V(e)})):i.push(e);break}default:i.push(e)}else i.push(e)}function Y(i){var t,s,n,r,o,a;let e="";switch(i.type){case"swipe":case"tap":{const c=i.element;return typeof c=="string"?e=` on element "${c}"`:(t=c==null?void 0:c.attributes)!=null&&t.accessibilityIdentifier?e=`element with accessibilityIdentifier "${(s=c.attributes)==null?void 0:s.accessibilityIdentifier}"`:(n=c==null?void 0:c.attributes)!=null&&n.class?e=`element with class "${(r=c.attributes)==null?void 0:r.class}"`:"position"in i&&((o=i.position)==null?void 0:o.x)&&((a=i.position)==null?void 0:a.y)&&(e=`position ${Math.round(i.position.x*100)}%, ${Math.round(i.position.y*100)}%`),e?`${i.type} on ${e}`:i.type}case"keypress":return`type "${V(i)}"`;case"typeText":return`type "${i.text}"`}}function Q({type:i,value:e}){switch(i){case"deviceInfo":return{type:"deviceInfo",value:e};case"sessionRequested":return{type:"sessionRequested"};case"chromeDevToolsUrl":return{type:"networkInspectorUrl",value:e};case"orientationChanged":return{type:"orientationChanged",value:e}}}const $e="1.0.1";class Fe 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,s)=>{const n=setTimeout(()=>{clearInterval(r),s(new C("Timed out after 60000ms waiting for connection to Appetize page"))},6e4),r=setInterval(()=>{const o=new MessageChannel;o.port1.onmessage=()=>{clearInterval(r),clearTimeout(n),t(!1)},window.postMessage({type:"init",appetizeClient:!0,version:e},"*",[o.port2]),window.__appetize_postMessage=async(a,c=!1)=>{const h=new MessageChannel;if(window.postMessage(a,"*",[h.port2]),c)return new Promise((u,p)=>{const y=setTimeout(()=>{p(new C("Timed out after 60000ms while waiting for postMessage response"))},6e4);h.port1.onmessage=g=>{clearTimeout(y),u(g.data)}})}},100)}),[$e]),await this.page.evaluate(()=>{window.__appetize__video_frames=[],window.__appetize__audio_frames=[],window.addEventListener("message",e=>{var t;if(e.source===window){const s=typeof e.data=="string"?e.data:(t=e.data)==null?void 0:t.type;if(s==="socketEvent")switch(e.data.value.type){case"h264Data":case"frameData":if(window.__appetize__video_frames.push(e.data.value),!window.__appetize_emit_video)return;break;case"audioData":if(window.__appetize__audio_frames.push(e.data.value),!window.__appetize_emit_audio)return;break}else switch(s){case"frameData":case"recordedAction":case"playbackFoundAndSent":case"playbackNotFound":case"debug":case"interceptRequest":case"interceptResponse":case"interceptError":case"uiDump":return}window.__appetize_on(e.data)}})},[]),this.ready=!0}async waitUntilReady(){return H(async()=>{if(!this.ready)throw new C("Timed out after 60000ms while waiting for Appetize window to be ready.")},6e4)}enableVideoEvents(e=!0){return this.page.evaluate(t=>{window.__appetize_emit_video=t},e)}enableAudioEvents(e=!0){return this.page.evaluate(t=>{window.__appetize_emit_audio=t},e)}async postMessage(e,t=!1){return await this.waitUntilReady(),this.page.evaluate(async([s,n])=>window.__appetize_postMessage(s,n),[e,t])}async getVideoFrames(){return this.page.evaluate(()=>window.__appetize__video_frames)}async getAudioFrames(){return this.page.evaluate(()=>window.__appetize__audio_frames)}async resetVideoFrames(){return this.page.evaluate(()=>{window.__appetize__video_frames=[]})}async resetAudioFrames(){return this.page.evaluate(()=>{window.__appetize__audio_frames=[]})}}class X extends w.EventEmitter{constructor({page:e,type:t,window:s}){super(),this.page=e,this.type=t,this.window=s,this.window.on("*",({type:n,value:r})=>{switch(n){case"socketEvent":r.socket===this.type&&(this.emit(r.type,r.value),this.emit("*",{type:r.type,value:r.value}));break;case"disconnect":this.emit("disconnect"),this.emit("*",{type:"disconnect"});break;case"sessionInfo":case"chromeDevToolsUrl":case"orientationChanged":case"deviceInfo":if(this.type==="appetizer"){const o=Q({type:n,value:r});o&&(this.emit(o.type,o.value),this.emit("*",o))}break;case"sessionRequested":if(this.type==="webserver"){const o=Q({type:n,value:r});o&&(this.emit(o.type,o.value),this.emit("*",o))}break}})}async send(e,t){return this.window.postMessage({type:"emitSocketEvent",value:{type:e,value:t,socket:this.type}})}async disconnect(){await this.send("disconnect")}waitForEvent(e,t){return _(this,e,t)}}class Ie extends ve{constructor({page:e,config:t,window:s,testInfo:n,...r}){const o=new X({page:e,window:s,type:"appetizer"});super({...r,socket:o,config:t,logger:T}),this.actionLogs=[],this.window=s,this.page=e,this.config=t,this.testInfo=n,this.page.on("load",()=>{this.emit("disconnect")}),t.record&&this.on("disconnect",()=>{this.teardownUi()})}async addActionLog(e){if(e.error){const t=await this.getUI().catch(this.logger.warn);t&&(e.ui=t)}this.actionLogs.push(e)}teardownUi(){return this.window.page.evaluate(()=>{const e=document.querySelector("app-ui");e&&e.remove()})}async rotate(e){try{const[t]=await Promise.all([_(this.window,"orientationChanged"),await this.window.postMessage(e==="left"?"rotateLeft":"rotateRight")]);return this.window.page.waitForTimeout(1e3),t}catch(t){throw l(t,this.rotate),t}}async screenshot(e="buffer"){try{const[t]=await Promise.all([_(this.socket,"screenshot",{timeout:6e4}),this.socket.send("getScreenshot")]),s=new Uint8Array(Object.values(t.data).map(Number));return{data:e==="buffer"?Buffer.from(s):t.data,mimeType:t.mimeType}}catch(t){throw l(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 Te({session:this,testInfo:this.testInfo}).record()}catch(e){throw l(e,this.record),e}}async waitForEvent(e,t){try{return await _(this,e,t)}catch(s){throw l(s,this.waitForEvent),s}}async waitForTimeout(e){try{return await D(e)}catch(t){throw l(t,this.waitForTimeout),t}}async waitForElement(e,t){try{const s=await this.findElements(e,t);if(s.length){if((t==null?void 0:t.matches)&&s.length!==t.matches)throw new Error(`Expected ${t.matches} elements, found ${s.length}`);return s}else throw new Error(`Element not found:
`)),console.log("\u{1F7E2} Finished"),this.currentRecord+=1}}}function Pe(i,e){const t=i[i.length-1];if(t)switch(e.type){case"keypress":{(t==null?void 0:t.type)==="keypress"&&!z(e.key)&&!z(t.key)?(i.pop(),i.push({type:"typeText",text:V(t)+V(e)})):(t==null?void 0:t.type)==="typeText"&&!z(e.key)?(i.pop(),i.push({type:"typeText",text:t.text+V(e)})):i.push(e);break}default:i.push(e)}else i.push(e)}function Y(i){var t,s,n,r,o,a;let e="";switch(i.type){case"swipe":case"tap":{const c=i.element;return typeof c=="string"?e=` on element "${c}"`:(t=c==null?void 0:c.attributes)!=null&&t.accessibilityIdentifier?e=`element with accessibilityIdentifier "${(s=c.attributes)==null?void 0:s.accessibilityIdentifier}"`:(n=c==null?void 0:c.attributes)!=null&&n.class?e=`element with class "${(r=c.attributes)==null?void 0:r.class}"`:"position"in i&&((o=i.position)==null?void 0:o.x)&&((a=i.position)==null?void 0:a.y)&&(e=`position ${Math.round(i.position.x*100)}%, ${Math.round(i.position.y*100)}%`),e?`${i.type} on ${e}`:i.type}case"keypress":return`type "${V(i)}"`;case"typeText":return`type "${i.text}"`}}function Q({type:i,value:e}){switch(i){case"deviceInfo":return{type:"deviceInfo",value:e};case"sessionRequested":return{type:"sessionRequested"};case"chromeDevToolsUrl":return{type:"networkInspectorUrl",value:e};case"orientationChanged":return{type:"orientationChanged",value:e}}}const $e="1.0.2-beta.0";class Fe 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,s)=>{const n=setTimeout(()=>{clearInterval(r),s(new C("Timed out after 60000ms waiting for connection to Appetize page"))},6e4),r=setInterval(()=>{const o=new MessageChannel;o.port1.onmessage=()=>{clearInterval(r),clearTimeout(n),t(!1)},window.postMessage({type:"init",appetizeClient:!0,version:e},"*",[o.port2]),window.__appetize_postMessage=async(a,c=!1)=>{const h=new MessageChannel;if(window.postMessage(a,"*",[h.port2]),c)return new Promise((u,p)=>{const y=setTimeout(()=>{p(new C("Timed out after 60000ms while waiting for postMessage response"))},6e4);h.port1.onmessage=g=>{clearTimeout(y),u(g.data)}})}},100)}),[$e]),await this.page.evaluate(()=>{window.__appetize__video_frames=[],window.__appetize__audio_frames=[],window.addEventListener("message",e=>{var t;if(e.source===window){const s=typeof e.data=="string"?e.data:(t=e.data)==null?void 0:t.type;if(s==="socketEvent")switch(e.data.value.type){case"h264Data":case"frameData":if(window.__appetize__video_frames.push(e.data.value),!window.__appetize_emit_video)return;break;case"audioData":if(window.__appetize__audio_frames.push(e.data.value),!window.__appetize_emit_audio)return;break}else switch(s){case"frameData":case"recordedAction":case"playbackFoundAndSent":case"playbackNotFound":case"debug":case"interceptRequest":case"interceptResponse":case"interceptError":case"uiDump":return}window.__appetize_on(e.data)}})},[]),this.ready=!0}async waitUntilReady(){return H(async()=>{if(!this.ready)throw new C("Timed out after 60000ms while waiting for Appetize window to be ready.")},6e4)}enableVideoEvents(e=!0){return this.page.evaluate(t=>{window.__appetize_emit_video=t},e)}enableAudioEvents(e=!0){return this.page.evaluate(t=>{window.__appetize_emit_audio=t},e)}async postMessage(e,t=!1){return await this.waitUntilReady(),this.page.evaluate(async([s,n])=>window.__appetize_postMessage(s,n),[e,t])}async getVideoFrames(){return this.page.evaluate(()=>window.__appetize__video_frames)}async getAudioFrames(){return this.page.evaluate(()=>window.__appetize__audio_frames)}async resetVideoFrames(){return this.page.evaluate(()=>{window.__appetize__video_frames=[]})}async resetAudioFrames(){return this.page.evaluate(()=>{window.__appetize__audio_frames=[]})}}class X extends w.EventEmitter{constructor({page:e,type:t,window:s}){super(),this.page=e,this.type=t,this.window=s,this.window.on("*",({type:n,value:r})=>{switch(n){case"socketEvent":r.socket===this.type&&(this.emit(r.type,r.value),this.emit("*",{type:r.type,value:r.value}));break;case"disconnect":this.emit("disconnect"),this.emit("*",{type:"disconnect"});break;case"sessionInfo":case"chromeDevToolsUrl":case"orientationChanged":case"deviceInfo":if(this.type==="appetizer"){const o=Q({type:n,value:r});o&&(this.emit(o.type,o.value),this.emit("*",o))}break;case"sessionRequested":if(this.type==="webserver"){const o=Q({type:n,value:r});o&&(this.emit(o.type,o.value),this.emit("*",o))}break}})}async send(e,t){return this.window.postMessage({type:"emitSocketEvent",value:{type:e,value:t,socket:this.type}})}async disconnect(){await this.send("disconnect")}waitForEvent(e,t){return _(this,e,t)}}class Ie extends ve{constructor({page:e,config:t,window:s,testInfo:n,...r}){const o=new X({page:e,window:s,type:"appetizer"});super({...r,socket:o,config:t,logger:T}),this.actionLogs=[],this.window=s,this.page=e,this.config=t,this.testInfo=n,this.page.on("load",()=>{this.emit("disconnect")}),t.record&&this.on("disconnect",()=>{this.teardownUi()})}async addActionLog(e){if(e.error){const t=await this.getUI().catch(this.logger.warn);t&&(e.ui=t)}this.actionLogs.push(e)}teardownUi(){return this.window.page.evaluate(()=>{const e=document.querySelector("app-ui");e&&e.remove()})}async rotate(e){try{const[t]=await Promise.all([_(this.window,"orientationChanged"),await this.window.postMessage(e==="left"?"rotateLeft":"rotateRight")]);return this.window.page.waitForTimeout(1e3),t}catch(t){throw l(t,this.rotate),t}}async screenshot(e="buffer"){try{const[t]=await Promise.all([_(this.socket,"screenshot",{timeout:6e4}),this.socket.send("getScreenshot")]),s=new Uint8Array(Object.values(t.data).map(Number));return{data:e==="buffer"?Buffer.from(s):t.data,mimeType:t.mimeType}}catch(t){throw l(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 Te({session:this,testInfo:this.testInfo}).record()}catch(e){throw l(e,this.record),e}}async waitForEvent(e,t){try{return await _(this,e,t)}catch(s){throw l(s,this.waitForEvent),s}}async waitForTimeout(e){try{return await D(e)}catch(t){throw l(t,this.waitForTimeout),t}}async waitForElement(e,t){try{const s=await this.findElements(e,t);if(s.length){if((t==null?void 0:t.matches)&&s.length!==t.matches)throw new Error(`Expected ${t.matches} elements, found ${s.length}`);return s}else throw new Error(`Element not found:
${JSON.stringify(e)}`)}catch(s){throw l(s,this.waitForElement),s}}on(e,t){return e==="video"&&(q.onVideo||(this.logger.warn("Listening to the `video` event will significantly slow down your tests. It is recommended to use session.getVideoFrames() instead."),q.onVideo=!0),this.window.enableVideoEvents()),e==="audio"&&(q.onAudio||(this.logger.warn("Listening to the `audio` event will significantly slow down your tests. It is recommended to use session.getAudioFrames() instead."),q.onAudio=!0),this.window.enableAudioEvents()),super.on(e,t)}once(e,t){return e==="video"&&this.window.enableVideoEvents(),e==="audio"&&this.window.enableAudioEvents(),super.once(e,t)}async getVideoFrames(){return await this.window.getVideoFrames()}async getAudioFrames(){return await this.window.getAudioFrames()}}const q={onVideo:!1,onAudio:!1},G=new WeakMap;class Ce extends Ae{constructor({page:e}){var r;const t=(r=G.get(e))!=null?r:new Fe({page:e});G.set(e,t),t.init();const s=new X({type:"webserver",page:e,window:t});super({socket:s,window:t,logger:T}),this.window=t,this.page=e;let n=!1;this.on("queue",o=>{n||(n=!0,o.type==="concurrent"?this.logger.log(`Entered ${o.name}. Please wait until a slot becomes available.`):this.logger.log("All devices are currently in use. Please wait until requested device becomes available.")),o.position>0&&(o.type==="concurrent"?this.logger.log(`Position in ${o.name}: ${o.position}`):this.logger.log(`Position in queue: ${o.position}`))}),this.on("session",()=>{n&&(n=!1)})}validateConfig(e){var s;return{codec:((s=this.page.context().browser())==null?void 0:s.browserType().name())==="chromium"?"jpeg":"h264",...e}}createSession(e,t){return this.session=new Ie({config:e,page:this.page,window:this.window,path:t.path,token:t.token,device:this.device,app:this.app}),this.session}}class De{constructor(e){this.queue=null,this.page=e}async start(e){var r,o;const{config:t,baseURL:s}=e,n=new URLSearchParams;t.device&&n.set("device",t.device),t.deviceColor&&n.set("deviceColor",t.deviceColor),t.screenOnly&&n.set("screenOnly",t.screenOnly.toString()),t.orientation&&n.set("orientation",t.orientation),n.set("scale",(o=(r=t.scale)==null?void 0:r.toString())!=null?o:"auto"),await this.page.goto(`${s!=null?s:"https://appetize.io"}/embed/${t.publicKey}?${n.toString()}`),this.client=new Ce({page:this.page}),this.client.on("queue",a=>{this.queue=a}),await this.client.waitUntilReady(),this.session=await re(()=>this.client.startSession({...t}),{retries:5,timeout:3e4,predicate:(a,c)=>a instanceof Error&&a.message.match(/too many requests/)?(console.warn(`Too many session requests. Retrying in 30 seconds... (attempt #${c})`),!0):!1})}}let P,Z;const K=b.test.extend({_useConfig:[{},{option:!0}],config:[async({_useConfig:i},e,t)=>{await e({...t.project.use.config,...i,autoplay:!1})},{auto:!0}],_autoSnapshotSuffix:[async({},i,e)=>{e.snapshotSuffix="",await i()},{auto:!0}],appetizePage:async({browser:i,config:e},t)=>{if(P&&JSON.stringify(Z)!==JSON.stringify(e)&&(await P.page.close(),await P.page.context().close(),P=null),!P){const s=await i.newContext();if(P=new De(await s.newPage()),Z=e,!e.publicKey)throw new Error('Appetize public key not set. Make sure you have run test.use({ config: { publicKey: "..." } })')}await t(P)},session:async({appetizePage:i,config:e,baseURL:t,_doSetupAndTeardown:s},n,r)=>{if(i.session||await W.step("Start Appetize session",async()=>{await i.start({config:e,baseURL:t})}),!i.session)throw new Error("Appetize session failed to start");i.session.testInfo=r,await n(i.session)},client:async({appetizePage:i},e)=>{await e(i.client)},_doSetupAndTeardown:[async({appetizePage:i},e,t)=>{var s,n;T.clearLogHistory(),i.session&&(i.session.actionLogs=[],await i.session.window.resetVideoFrames(),await i.session.window.resetAudioFrames()),await e(),await se(i,t),t.status==="timedOut"&&((n=(s=i.queue)==null?void 0:s.position)!=null?n:0)>0&&T.warn("Test timed out while in queue for a device. You may increase your test timeout to account for higher queue times.")},{auto:!0}]}),Re=K.use,ee=K.afterEach;Object.assign(K,{setup(i){return{}.__APPETIZE__SETUP_WARNED||T.warn("test.setup() is deprecated and will be removed in a future release. Use test.use({ config: {...} }) instead"),W.use({config:i})},use(i){const{config:e,...t}=i;return Re({...t,_useConfig:e})},afterEach(i){return ee(async({appetizePage:e},t)=>{e&&await se(e,t)}),ee(i)}});const W=K,te=new WeakMap;async function se(i,e){if(te.get(e.fn))return;te.set(e.fn,!0);const t=i.session,s="fail-output";if(e.status==="failed"||e.status==="timedOut"){if(t){const o=t.actionLogs;await I.default.promises.mkdir(e.outputPath(s));const a=async()=>{try{const h=await t.screenshot("buffer");e.attach("screenshot",{body:h.data,contentType:"image/png"});const u=e.outputPath(s,"screenshot.png");await I.default.promises.writeFile(u,Buffer.from(h.data))}catch{}},c=async()=>{try{const h=o.map(y=>{if("screenshot"in y){const{screenshot:g,...v}=y;return v}return y});if(!h.length)return;const u=JSON.stringify(h,null,2);e.attach("actions",{body:u,contentType:"application/json"});const p=e.outputPath(s,"actions.json");await I.default.promises.writeFile(p,u)}catch{}};await Promise.all([a(),c()])}await(async()=>{if(!!T.logHistory.length)try{const o=`${T.logHistory.map(c=>`[${c.method}] ${JSON.stringify(c.data).slice(2,-2)}`).join(`
`)}`;e.attach("sdk-logs",{body:o,contentType:"application/text"});const a=e.outputPath(s,"sdk-logs.txt");await I.default.promises.writeFile(a,o)}catch{}})()}}Object.defineProperty(d,"expect",{enumerable:!0,get:function(){return b.expect}}),d.test=W,Object.defineProperties(d,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
//# sourceMappingURL=index.umd.js.map
{
"name": "@appetize/playwright",
"version": "1.0.1",
"version": "1.0.2-beta.0",
"description": "Test your mobile apps on Appetize.io with Playwright",

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

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc