uni.automator.js 7.7 KB

1
  1. "use strict";var e=require("debug"),t=require("licia/isWindows"),r=require("licia/getPort"),o=require("qrcode-reader"),s=require("fs"),n=require("child_process"),a=require("licia/sleep"),i=require("licia/toStr"),c=require("licia/waitUntil"),l=require("licia/concat"),u=require("licia/dateFormat"),d=require("ws"),p=require("events"),h=require("licia/uuid"),f=require("licia/stringify"),m=require("os");function w(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var v=w(e),g=w(t),y=w(r),b=w(o),E=w(s),q=w(n),M=w(a),P=w(i),A=w(c),H=w(l),$=w(u),j=w(d),x=w(h),C=w(f),k=w(m);/^win/.test(process.platform);class S extends p.EventEmitter{constructor(e){super(),this.ws=e,this.ws.addEventListener("message",(e=>{this.emit("message",e.data)})),this.ws.addEventListener("close",(()=>{this.emit("close")}))}send(e){this.ws.send(e)}close(){this.ws.close()}}const T=new Map,R=new Map,D="Connection closed";class F extends p.EventEmitter{constructor(e,t,r){super(),this.puppet=t,this.namespace=r,this.callbacks=new Map,this.transport=e,this.isAlive=!0,this.id=Date.now(),this.debug=v.default("automator:protocol:"+this.namespace),this.onMessage=e=>{var t,r;if(this.isAlive=!0,"true"===process.env.UNI_APP_X&&'"pong"'===e)return;this.debug(`${$.default("yyyy-mm-dd HH:MM:ss:l")} ◀ RECV ${e}`);const{id:o,method:s,error:n,result:a,params:i}=JSON.parse(e);if(null===(t=null==a?void 0:a.method)||void 0===t?void 0:t.startsWith("on"))return void((e,t)=>{const r=T.get(e.method);(null==r?void 0:r.has(t))&&r.get(t)(e.data)})(a,o);if(null===(r=null==a?void 0:a.method)||void 0===r?void 0:r.startsWith("Socket.")){return void((e,t,r)=>{const o=R.get(t);(null==o?void 0:o.has(e))&&o.get(e)(r)})(a.method.replace("Socket.",""),a.id,a.data)}if(!o)return this.puppet.emit(s,i);const{callbacks:c}=this;if(o&&c.has(o)){const e=c.get(o);c.delete(o),n?e.reject(Error(n.message||n.detailMessage||n.errMsg)):e.resolve(a)}},this.onClose=()=>{this.callbacks.forEach((e=>{e.reject(Error(D))}))},this.transport.on("message",this.onMessage),this.transport.on("close",this.onClose)}send(e,t={},r=!0){if(r&&this.puppet.adapter.has(e))return this.puppet.adapter.send(this,e,t);const o=x.default(),s=C.default({id:o,method:e,params:t});return"ping"!==e&&this.debug(`${$.default("yyyy-mm-dd HH:MM:ss:l")} SEND ► ${s}`),new Promise(((e,t)=>{try{this.transport.send(s)}catch(e){t(Error(D))}this.callbacks.set(o,{resolve:e,reject:t})}))}dispose(){this.transport.close()}startHeartbeat(){"true"===process.env.UNI_APP_X&&("android"===process.env.UNI_APP_PLATFORM?this.startXAndroidHeartbeat():"ios"===process.env.UNI_APP_PLATFORM&&this.startXIosHeartbeat())}startXAndroidHeartbeat(){const e=new Map,t=function(e){try{return require(e)}catch(t){return require(require.resolve(e,{paths:[process.cwd()]}))}}("adbkit"),r=k.default.platform();let o="",s="";"darwin"===r?(o='dumpsys activity | grep "Run"',s="logcat -b crash | grep -C 10 io.dcloud.uniappx"):"win32"===r&&(o='dumpsys activity | findstr "Run"',s="logcat | findstr UncaughtExceptionHandler"),e.set(this.id,setInterval((async()=>{if(!this.isAlive){const n=t.createClient(),a=await n.listDevices();if(!a.length)throw Error("Device not found");const i=a[0].id,c=await n.getProperties(i);return("1"===c["ro.kernel.qemu"]||"goldfish"===c["ro.hardware"])&&"win32"===r&&(s="logcat | grep UncaughtExceptionHandler"),n.shell(i,o).then((function(e){let t,r="";e.on("data",(function(e){r+=e.toString(),t&&clearTimeout(t),t=setTimeout((()=>{r.includes("io.dcloud.uniapp")||console.log("Stop the test process.")}),50)}))})),n.shell(i,s).then((e=>{let t,r="";e.on("data",(e=>{r+=e.toString(),t&&clearTimeout(t),t=setTimeout((()=>{console.log(`crash log: ${r}`)}),50)}))})),clearInterval(e.get(this.id)),e.delete(this.id),void this.dispose()}this.send("ping"),this.isAlive=!1}),5e3))}startXIosHeartbeat(){const e=new Map;e.set(this.id,setInterval((async()=>{if(!this.isAlive)return console.log("Stop the test process."),clearInterval(e.get(this.id)),e.delete(this.id),void this.dispose();this.send("ping"),this.isAlive=!1}),5e3))}static createDevtoolConnection(e,t){return new Promise(((r,o)=>{const s=new j.default(e);s.addEventListener("open",(()=>{r(new F(new S(s),t,"devtool"))})),s.addEventListener("error",o)}))}static createRuntimeConnection(e,t,r){return new Promise(((o,s)=>{v.default("automator:runtime")(`${$.default("yyyy-mm-dd HH:MM:ss:l")} port=${e}`);const n=new j.default.Server({port:e});A.default((async()=>{if(t.runtimeConnection)return!0}),r,1e3).catch((()=>{n.close(),s("Failed to connect to runtime, please make sure the project is running")})),n.on("connection",(function(e){v.default("automator:runtime")(`${$.default("yyyy-mm-dd HH:MM:ss:l")} connected`);const r=new F(new S(e),t,"runtime");t.setRuntimeConnection(r),r.startHeartbeat(),o(r)})),t.setRuntimeServer(n)}))}}const I=v.default("automator:devtool");async function _(e,t,r){const{port:o,cliPath:s,timeout:n,cwd:a="",account:i="",args:c=[],launch:l=!0}=t;let u=!1,d=!1;if(!1!==l){const t={stdio:"ignore",detached:!0};a&&(t.cwd=a);let r=H.default(c,[]);r=H.default(r,["auto","--project"]),r=H.default(r,[e,"--auto-port",P.default(o)]),i&&(r=H.default(r,["--auto-account",i]));try{I("%s %o %o",s,r,t);const e=q.default.spawn(s,r,t);e.on("error",(e=>{u=!0})),e.on("exit",(()=>{setTimeout((()=>{d=!0}),15e3)})),e.unref()}catch(e){u=!1}}else setTimeout((()=>{d=!0}),15e3);const p=await A.default((async()=>{try{if(u||d)return!0;const e=await async function(e,t){let r;try{r=await F.createDevtoolConnection(e.wsEndpoint,t)}catch(t){throw Error(`Failed connecting to ${e.wsEndpoint}, check if target project window is opened with automation enabled`)}return r}({wsEndpoint:`ws://127.0.0.1:${o}`},r);return e}catch(e){}}),n,1e3);if(u)throw Error(`Failed to launch ${r.devtools.name}, please make sure cliPath is correctly specified`);if(d)throw Error(`Failed to launch ${r.devtools.name} , please make sure http port is open`);return await M.default(5e3),I(`${$.default("yyyy-mm-dd HH:MM:ss:l")} connected`),p}const L={devtools:{name:"Wechat web devTools",remote:!0,automator:!0,paths:[g.default?"C:/Program Files (x86)/Tencent/微信web开发者工具/cli.bat":"/Applications/wechatwebdevtools.app/Contents/MacOS/cli"],required:["project.config.json","app.json","app.js"],defaultPort:9420,validate:async function(e,t){const r=function(e,t){const r=t.devtools.paths.slice(0);e&&r.unshift(e);for(const e of r)if(E.default.existsSync(e))return e;throw Error(`${t.devtools.name} not found, please specify executablePath option`)}(e.executablePath,t);let o=e.port||t.devtools.defaultPort;if(!1!==e.launch)try{o=await async function(e,t){const r=await y.default(e||t);if(e&&r!==e)throw Error(`Port ${e} is in use, please specify another port`);return r}(o)}catch(t){e.launch=!1}else{o===await y.default(o)&&(e.launch=!0)}return Object.assign(Object.assign({},e),{port:o,cliPath:r})},async create(e,t,r){const o=await _(e,t,r);return r.compiled?v.default("automator:devtool")("Waiting for runtime automator"):(v.default("automator:devtool")("initRuntimeAutomator"),o.send("App.callWxMethod",{method:"$$initRuntimeAutomator",args:[]})),o}},adapter:{"Tool.enableRemoteDebug":{reflect:async(e,t)=>{let{qrCode:r}=await e("Tool.enableRemoteDebug",t,!1);return r&&(r=await function(e){const t=new Buffer(e,"base64");return new Promise((async(e,r)=>{const o=await require("jimp").read(t),s=new b.default;s.callback=function(t,o){if(t)return r(t);e(o.result)},s.decode(o.bitmap)}))}(r)),{qrCode:r}}},"App.callFunction":{reflect:async(e,t)=>{return e("App.callFunction",Object.assign(Object.assign({},t),{functionDeclaration:(r=t.functionDeclaration,"}"===r[r.length-1]?r.replace("{","{\nvar uni = wx;\n"):r.replace("=>","=>{\nvar uni = wx;\nreturn ")+"}")}),!1);var r}},"Element.getHTML":{reflect:async(e,t)=>({html:(await e("Element.getWXML",t,!1)).wxml})}}};module.exports=L;