UNPKG

rubick

Version:

tools for mtc

1,260 lines (1,224 loc) 59.3 kB
'use strict' window.BASE_URL = 'http://localhost:8888/'; let normalizeNum = function(radio, type) { let num = radio; if (type === 'up') { num = ((Math.ceil(radio * 10) + 1) / 10).toFixed(1); } else { num = ((Math.floor(radio * 10) - 1) / 10).toFixed(1); } num = num < 0 ? 0 : num; num = num > 1 ? 1 : num; return num; }; var jcrop_data = { api: null, updatePreview: function(c) { console.log(c); if (parseInt(c.w) > 0) { let originImageCanvas = $("#origin-screen-canvas")[0]; let radio = store.screenData.radio; let originWidth = store.screenData.originSize.width; let originHeight = store.screenData.originSize.height; store.screenData.captureRadio.left = normalizeNum(c.x / radio / originWidth, 'down'); store.screenData.captureRadio.right = normalizeNum(c.x2 / radio / originWidth, 'up'); store.screenData.captureRadio.top = normalizeNum(c.y / radio / originHeight, 'down'); store.screenData.captureRadio.bottom = normalizeNum(c.y2 / radio / originHeight, 'up'); $("#crop-image-preview").css('width', c.w/radio); $("#crop-image-preview").css('height', c.h / radio); let previewImageCanvas = $("#crop-image-preview")[0]; previewImageCanvas.width = c.w/radio; previewImageCanvas.height = c.h / radio; console.log(previewImageCanvas.width + ',' + previewImageCanvas.height); let context = previewImageCanvas.getContext("2d"); if (originImageCanvas != null && c.x !== 0 && c.y !== 0 && c.w !== 0 && c.h !== 0) { context.drawImage(originImageCanvas, c.x / radio, c.y / radio, c.w / radio, c.h / radio, 0, 0, previewImageCanvas.width, previewImageCanvas.height); } $('#crop-image-preview-modal').modal('show'); console.log('select'); } } }; /** * cache image object for reuse **/ function ImagePool(size) { this.size = size; this.images = []; this.counter = 0 } /** * add iterator function for reuse **/ ImagePool.prototype.next = function () { if (this.images.length < this.size) { let image = new Image(); this.images.push(image); return image } else { if (this.counter >= this.size) { this.counter = 0 } } return this.images[this.counter++ % this.size]; }; /** * create blob from base64 string * http://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript * **/ function b64toBlob(b64Data, contentType, sliceSize) { contentType = contentType || ''; sliceSize = sliceSize || 512; let byteCharacters = atob(b64Data); let byteArrays = []; for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) { var slice = byteCharacters.slice(offset, offset + sliceSize); var byteNumbers = new Array(slice.length); for (var i = 0; i < slice.length; i++) { byteNumbers[i] = slice.charCodeAt(i); } var byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } return new Blob(byteArrays, { type: contentType }); } Vue.component('item', { template: '#node-element', props: { model: Object }, data: function () { return { open: false } }, computed: { isFolder: function () { return this.model.children && this.model.children.length } }, methods: { toggle: function () { if (this.isFolder) { this.open = !this.open } } } }); let app = new Vue({ el: '#app', data: { error: '', inputItem: '', nodeSelected: null, parentNode: null, nodeHovered: null, currentCodeBlock: { title:'', code: '', id: -1, opCode: '', assertCode: '', assertable: false, isAssert: false, action: '点击' }, storeData: store, selectedCase: {}, screenOperate: true, nodeMap: new Map(), nodeTree: {'element':{'xpath':''},'children':[]}, resourceIdMap: new Map(), classNameMap: new Map(), textMap: new Map(), platform: 'Android', serial: 'default', codeList: [], dragNodeList: [], dragMode: false, dragStatus: 'init', compiling: false, installing: false, codeContent: '', currentEditCode: {id:-1,code:'',title:''}, defaultTimeout: 5000, defaultCaseName: '', caseList: [], originImageBlob: null, previewImageName: '', previewImageDesc: '', imagePool: null, loading: false, canvas: { bg: null, fg: null, }, mouseOperation: { resolution: { width: 1080, height: 1920, }, type: 'script', data: { startPos: {}, endPos: {}, selector: {}, } }, canvasStyle: { opacity: 0.5, width: '324px', height: '576px' }, screenStyle: { width: '324px', height: '576px' }, screenWrapStyle: { width: '324px', height: '626px' }, screenSize: { screen: { width: 324, height: 576 }, canvas: { width: 324, height: 576 } }, refreshInterval: null, refreshViewInterval: null, screenRefreshStatus: 'done', viewRefreshStatus: 'done', screenRefreshControl: true, viewRefreshControl: true, showFg: true, currentMode:'普通模式', commonCode: '\nindex++;\nSystemClock.sleep(#timeout#);\nhelper.logAndScreenShot(index, "#description#");\n', singleSelectCode: '\nhelper.find(new UiSelector().#method#("#key#").instance(#index#)).click();', singleAssertCode: '\nhelper.checkObject(new UiSelector().#method#("#key#").instance(#index#));', swipeCode: '\nhelper.swipe(#startX#, #startY#, #endX#, #endY#, 5);', childSelectCode: '\nhelper.find(new UiSelector().resourceId("#parentKey#").instance(#parentIndex#)' + '.childSelector(new UiSelector().#method#("#key#").instance(#index#))).click();', childAssertCode: '\nhelper.checkObject(new UiSelector().resourceId("#parentKey#").instance(#parentIndex#)' + '.childSelector(new UiSelector().#method#("#key#").instance(#index#)));', cvSelectCode: '\nhelper.clickImage("#imageDesc#", "#imageName#@auto.png", #left#, #top#, #right#, #bottom#);', cvAssertCode: '\nhelper.checkImage("#imageDesc#", "#imageName#@auto.png", #left#, #top#, #right#, #bottom#);', pointCode: 'new Point(Math.round(#x#*width),Math.round(#y#*height))', pointListIndex: 0, waitTime: 0 }, computed: { showAssert: function(item) { if (item == null) { return false; } return !item.isAssert && item.assertable; }, showAssertCancel: function(item) { if (item == null) { return false; } return item.isAssert && item.assertable; }, nodes: function () { return this.nodeMap }, elem: function () { return this.nodeSelected || {'element': {}}; }, resourceIdNum: function() { let str = ''; let element = this.elem.element; if (element.resourceId != null && element.resourceId !== '') { str = 'currentInstance:' + element.resourceIdIndex + ', total num is:' + this.resourceIdMap.get(element.resourceId); } return str; }, classNameNum: function() { let str = ''; let element = this.elem.element; if (element.className != null && element.className !== '') { str = 'currentInstance:' + element.classNameIndex + ', total num is:' + this.classNameMap.get(element.className); } return str; }, textNum: function() { let str = ''; let element = this.elem.element; if (element.text != null && element.text !== '') { str = 'currentInstance:' + element.textIndex + ', total num is:' + this.textMap.get(element.text); } return str; }, randomName: function() { return this.uuid(16, 16); }, parentElem: function() { return this.parentNode || {'element': {}}; }, elemXpath: function () { var xpath = '//' + (this.elem.className || '*'); if (this.elem.text) { xpath += "[@text='" + this.elem.text + "']"; } return xpath; }, deviceConnected: function() { return (this.serial && this.serial !== '' && this.serial !== 'default'); } }, watch: { canvasStyle: function (newCanvasStyle) { this.resizeScreen(); } }, created: function () { this.imagePool = new ImagePool(100); }, mounted: function () { var URL = window.URL || window.webkitURL; this.canvas.bg = document.getElementById('bgCanvas'); this.canvas.fg = document.getElementById('fgCanvas'); this.activeMouseControl(true); this.getDevices(); this.startScreenRefresh(); this.startViewRefresh(); let uuid = this.uuid(16, 16); console.log(uuid); // this.activeScreenControl(); }, methods: { switchFg: function() { this.showFg = !this.showFg; }, switchScreenOperate: function() { this.screenOperate = !this.screenOperate; }, showError: function(error) { // alert(error); }, showAjaxError: function(ret) { if (ret && ret.msg) { this.showError(ret.msg); } else { this.showError("can not get response from local server"); } }, uuid: function(len, radix) { let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); let uuid = [], i; radix = radix || chars.length; if (len) { for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix]; } else { let r; uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; uuid[14] = '4'; for (i = 0; i < 36; i++) { if (!uuid[i]) { r = 0 | Math.random()*16; uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; } } } return uuid.join(''); }, compile: function() { this.compiling = true; let len = this.codeList.length; let code = ''; for (var i=0; i<len; i++) { code = code + this.codeList[i].code; } console.log(code); // let code = this.codeContent; var self = this; let data = {code: code, packageName: this.storeData.appData.packageName}; console.log(data); $.ajax({ type: 'POST', dataType: 'json', url: BASE_URL + 'compileCode', data: (data), success: function(res) { console.log(res); self.compiling = false; window.location.href=BASE_URL + 'file/caseFile' }, error: function(res) { self.compiling = false; } }); }, sendInputItem: function() { // if this.currentCodeBlock.code != null // let len = this.codeList.length; // this.codeList[len - 1] = this.currentCodeBlock; this.sendEvent('input', {'text': this.inputItem}); $('#inputModal').modal('hide'); }, moveUpCode: function(id) { console.log(id); if (id <= 1) { return; } else { let tmp = this.codeList[id - 1]; tmp.id = id - 1; this.codeList[id - 1] = this.codeList[id - 2]; this.codeList[id - 1].id = id; this.codeList[id - 2] = tmp; } }, moveDownCode: function(id) { console.log(id); if (id >= this.codeList.length) { return; } else { let tmp = this.codeList[id - 1]; tmp.id = id + 1; this.codeList[id - 1] = this.codeList[id]; this.codeList[id - 1].id = id; this.codeList[id] = tmp; } }, confirmCodeEdit: function() { let len = this.codeList.length; let id = this.currentEditCode.id; if (id >= 0 && id <= len) { this.codeList[id - 1] = this.currentEditCode; $('#edit-code-modal').modal('hide'); } }, editCode: function(id) { let len = this.codeList.length; this.currentEditCode = {id:-1, code:'', title:''}; console.log(len + " " + id); if (id <= len) { this.currentEditCode = this.codeList[id - 1]; $('#edit-code-modal').modal('show'); } }, deleteCode: function(id) { let codeList = []; let len = this.codeList.length; for (var i=0; i<len; i++) { if (i < id - 1) { codeList.push(this.codeList[i]); } else if (i > id - 1) { let tmp = this.codeList[i]; tmp.id = tmp.id - 1; codeList.push(tmp); } } this.codeList = codeList; }, downloadCase: function() { let content = JSON.stringify(this.codeList); this.downloadFile('case.txt', content); }, downloadFile: function(name, contents, mime_type) { mime_type = mime_type || "text/plain"; var blob = new Blob([contents], {type: mime_type}); var dlink = document.createElement('a'); dlink.download = name; dlink.href = window.URL.createObjectURL(blob); dlink.onclick = function(e) { var that = this; setTimeout(function() { window.URL.revokeObjectURL(that.href); }, 1500); }; dlink.click(); dlink.remove(); }, setInputText: function(val, oldVal) { if (this.currentCodeBlock.code !== null && this.currentCodeBlock.code !== '') { let setTextCode = 'setText("' + oldVal + '")'; let clickCode = 'click()'; if (val === null || val === '') { this.currentCodeBlock.code = this.currentCodeBlock.code.replace(setTextCode, clickCode); } else { let newSetTextCode = 'setText("' + val + '")'; this.currentCodeBlock.code = this.currentCodeBlock.code.replace(clickCode, newSetTextCode); this.currentCodeBlock.code = this.currentCodeBlock.code.replace(setTextCode, newSetTextCode); } } }, resizeScreen: function() { let self = this; if (jcrop_data.api != null) { jcrop_data.api.disable(); } let canvasSize = self.storeData.screenData.canvasSize; let canvasRatio = canvasSize.width / canvasSize.height; let originSize = self.storeData.screenData.originSize; let originRadio = originSize.width / originSize.height; Object.assign(this.screenStyle, { width: Math.floor(canvasSize.width) + 'px', height: Math.floor(canvasSize.height) + 'px', }); Object.assign(this.screenWrapStyle, { width: Math.floor(canvasSize.width) + 'px', height: parseInt(Math.floor(canvasSize.height) + 50) + 'px', }); let bgCanvas = $('#bgCanvas'); let fgCanvas = $('#fgCanvas'); if (canvasRatio > originRadio) { bgCanvas.css('width', Math.floor(canvasSize.height * originRadio) + 'px'); bgCanvas.css('height', Math.floor(canvasSize.height) + 'px'); fgCanvas.css('width', Math.floor(canvasSize.height * originRadio) + 'px'); fgCanvas.css('height', Math.floor(canvasSize.height) + 'px'); self.storeData.screenData.radio = canvasSize.height / originSize.height; } else { bgCanvas.css('width', Math.floor(canvasSize.width) + 'px'); bgCanvas.css('height', Math.floor(canvasSize.width / originRadio) + 'px'); fgCanvas.css('width', Math.floor(canvasSize.width) + 'px'); fgCanvas.css('height', Math.floor(canvasSize.width / originRadio) + 'px'); self.storeData.screenData.radio = canvasSize.width / originSize.width; } }, startScreenRefresh: function() { console.log('start refresh'); let self = this; if (self.refreshInterval === null) { self.refreshInterval = setInterval(self.refreshScreen, 500); } }, refreshScreen: function() { let self = this; if (!self.screenRefreshControl || self.screenRefreshStatus !== 'done'){ return; } self.screenRefreshStatus = 'start'; $.getJSON(BASE_URL + 'device/' + encodeURIComponent(this.serial) + '/screenshot') .then(function (ret) { console.log(ret.type); self.originImageBlob = b64toBlob(ret.data, 'image/' + ret.type); self.screenRefreshStatus = 'done'; this.drawBlobImageToScreen(); }.bind(this), function(err) { self.screenRefreshStatus = 'done'; }) }, startViewRefresh: function() { console.log('start view refresh'); let self = this; if (self.refreshViewInterval === null) { self.refreshViewInterval = setInterval(self.refreshView, 1000); } }, refreshView: function() { let self = this; if (!self.viewRefreshControl || self.viewRefreshStatus !== 'done' || self.dragMode) { // console.log('direct return refresh view'); return; } self.viewRefreshStatus = 'start'; $.getJSON(BASE_URL + 'device/' + encodeURIComponent(self.serial) + '/dumpView').then(function(ret) { self.canvasStyle.opacity = 1.0; if (ret.data.nodeObj) self.nodeMap = self.buildMap(ret.data.nodeObj); console.log('get node map' + self.nodeMap.length); self.nodeTree = ret.data.nodeTree; self.drawAllNode(); self.hashNodes(); self.loading = false; self.viewRefreshStatus = 'done'; }, function(err) { self.viewRefreshStatus = 'done'; self.showAjaxError(err); }); }, getDevices: function() { var self = this; $.getJSON(BASE_URL + 'devices') .then(function (ret) { // console.log(ret); self.serial = 'default'; if (ret.errno == 0 && ret.data.length > 0) { var length = ret.data.length; for (var i=0; i<length; i++) { if (ret.data[i].adbStatus !== 'unexists') { self.serial = ret.data[i].serial; break; } } } if (self.serial === 'default') { self.showError('没有有效的设备连接'); } }).fail(function(ret) { self.showAjaxError(ret) }); }, addWaitTime: function() { if (self.waitTime > 0) { } }, showScreen: function() { }, refreshScreenNew: function () { let self = this; this.loading = true; this.canvasStyle.opacity = 0.5; this.dragNodeList = []; return this.screenRefresh() .fail(function (ret) { self.showAjaxError(ret); }) .then(function () { return $.getJSON(BASE_URL + 'device/' + encodeURIComponent(self.serial) + '/dumpView') }) .fail(function (ret) { self.showAjaxError(ret); }) .then(function (ret) { self.canvasStyle.opacity = 1.0; if (ret.data.nodeObj) self.nodeMap = self.buildMap(ret.data.nodeObj); console.log('get node map' + self.nodeMap.length); self.nodeTree = ret.data.nodeTree; self.drawAllNode(); self.hashNodes(); self.loading = false; }) }, homeOperation: function() { this.sendEvent('homeClick', {}); }, backOperation: function() { this.sendEvent('backClick', {}); }, menuOperation: function() { this.sendEvent('menuClick', {}); }, sendEvent: function(event_type, event_data) { console.log('send event'); console.log(event_data); return $.ajax({ type: 'POST', dataType: 'json', url: BASE_URL + 'device/' + encodeURIComponent(this.serial) + '/operate', data: {type: event_type, data: event_data}, success: function(res) { console.log(res); }, }); }, screenRefresh: function () { let self = this; return $.getJSON(BASE_URL + 'device/' + encodeURIComponent(this.serial) + '/screenshot') .then(function (ret) { console.log(ret.type); self.originImageBlob = b64toBlob(ret.data, 'image/' + ret.type); this.drawBlobImageToScreen(); }.bind(this)) }, buildMap: function(obj) { let map = new Map(); Object.keys(obj).forEach(key => { map.set(key, obj[key]); }); return map; }, objectEntry: function* (obj) { for (let key of Object.keys(obj)) { yield [key, obj[key]]; } }, drawBlobImageToScreen: function () { var dtd = $.Deferred(); var self = this; var bgcanvas = this.canvas.bg, fgcanvas = this.canvas.fg, originCanvas = document.getElementById('origin-screen-canvas'), ctx = bgcanvas.getContext('2d'), originCtx = originCanvas.getContext('2d'), self = this, URL = window.URL || window.webkitURL, BLANK_IMG = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==', img = this.imagePool.next(); img.onload = function () { self.storeData.screenData.width = self.mouseOperation.resolution.width = img.width; self.storeData.screenData.height = self.mouseOperation.resolution.height = img.height; fgcanvas.width = bgcanvas.width = originCanvas.width = img.width; fgcanvas.height = bgcanvas.height = originCanvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); originCtx.drawImage(img, 0, 0, img.width, img.height); self.screenSize.canvas.width = img.width; self.screenSize.canvas.height = img.height; self.resizeScreen(); img.onload = img.onerror = null; img.src = BLANK_IMG; img = null; URL.revokeObjectURL(url); url = null; dtd.resolve(); }; img.onerror = function () { img.onload = img.onerror = null; img.src = BLANK_IMG; img = null; self.originImageBlob = null; URL.revokeObjectURL(url); url = null; dtd.reject(); }; let url = ''; if (self.originImageBlob != null) { url = URL.createObjectURL(self.originImageBlob); } img.src = url; return dtd; }, initBgCanvas: function() { this.canvas.bg = document.getElementById('bgCanvas'); this.canvas.fg = document.getElementById('fgCanvas'); if (this.canvas.bg == null && this.canvas.fg != null) { var canvas = document.createElement('canvas'); canvas.id = "bgCanvas"; canvas.width = this.canvas.fg.width; canvas.height = this.canvas.fg.height; canvas.className = 'canvas-bg'; var section = this.canvas.fg.parentElement; section.appendChild(canvas); this.canvas.bg = document.getElementById('bgCanvas'); return true; } else { return false; } }, initJcrop: function() { $('#bgCanvas').Jcrop({ onChange: function() {}, onSelect: jcrop_data.updatePreview, allowSelect: true, allowMove: true, allowResize: true, aspectRatio: 0 }, function() { jcrop_data.api = this; }); }, startDrag: function() { let self = this; this.displayFg(); self.stopRefresh(); self.stopOperate(); setTimeout(function() { self.stopCvAction(); self.currentMode = '拖拽模式'; self.dragMode = true; self.dragStatus = 'init'; self.dragNodeList = []; // self.activeMouseControl(false); }, 1000); }, stopDrag: function() { let self = this; self.startOperate(); self.dragMode = false; this.dragNodeList = []; }, initMode: function() { this.displayFg(); this.startRefresh(); this.stopCvAction(); this.stopDrag(); this.currentMode = '普通模式'; }, displayFg: function() { this.showFg = true; }, hideFg: function() { this.showFg = false; }, startOperate: function() { this.screenOperate = true; }, stopOperate: function() { this.screenOperate = false; }, startRefresh: function() { this.screenRefreshControl = true; this.viewRefreshControl = true; }, stopRefresh: function() { this.screenRefreshControl = false; this.viewRefreshControl = false; }, startCvAction: function() { this.stopOperate(); this.stopDrag(); this.hideFg(); this.stopRefresh(); let self = this; setTimeout(function() { self.currentMode = '图像识别模式'; if (jcrop_data.api !== null) { jcrop_data.api.destroy(); if (self.initBgCanvas()) { self.drawBlobImageToScreen().then(function() { self.initJcrop(); }) } else { self.initJcrop(); } } else { self.initJcrop(); } }, 1000); }, stopCvAction: function() { this.startOperate(); if (jcrop_data.api !== null) { jcrop_data.api.destroy(); if (this.initBgCanvas()) { this.drawBlobImageToScreen(); } } }, confirmCrop: function() { console.log(jcrop_data.api.tellSelect()); console.log(this.screenSize); if (this.previewImageDesc === '') { alert('请选输入图片描述'); } else { this.previewImageName = this.uuid(16, 16); let previewCanvas = document.getElementById('crop-image-preview'); let image = this.imagePool.next(); image.width = previewCanvas.width; image.height = previewCanvas.height; image.src = previewCanvas.toDataURL(); var link = document.createElement('a'); link.href = image.src; let originSize = this.storeData.screenData.originSize; link.download = this.previewImageName + '@' + originSize.width + 'x' + originSize.height; link.click(); let codeData = this.cvCodeGen(this.previewImageName, this.previewImageDesc); this.currentCodeBlock = { id: this.codeList.length + 1, title: '图片:' + this.previewImageName, code : codeData.opCode, opCode: codeData.opCode, assertCode: codeData.assertCode, assertable: true, isAssert: false, action: '点击' }; this.refreshCodeContent(); } }, drawClickPos: function(node) { if (!node || !node.element) { return; } }, drawNode: function (node, color, dashed) { if (!node || !node.element) { return; } var element = node.element; var x = element.bounds[0], y = element.bounds[1], w = element.bounds[2] - x, h = element.bounds[3] - y; color = color || 'black'; var ctx = this.canvas.fg.getContext('2d'); var rectangle = new Path2D(); rectangle.rect(x, y, w, h); if (dashed) { ctx.lineWidth = 1; ctx.setLineDash([8, 10]); } else { ctx.lineWidth = 5; ctx.setLineDash([]); } ctx.strokeStyle = color; ctx.stroke(rectangle); }, hashNodes: function() { let self = this; self.resourceIdMap = new Map(); self.classNameMap = new Map(); self.textMap = new Map(); let nodeList = self.nodes.values(); for (var [key, node] of self.nodes) { let element = node.element; if (element.resourceId != null && element.resourceId !== '') { if (self.resourceIdMap.has(element.resourceId)) { node.element.resourceIdIndex = self.resourceIdMap.get(element.resourceId) + 1; } else { node.element.resourceIdIndex = 0; } self.resourceIdMap.set(element.resourceId, node.element.resourceIdIndex); } if (element.text != null && element.text !== '') { if (self.textMap.has(element.text)) { node.element.textIndex = self.textMap.get(element.text) + 1; } else { node.element.textIndex = 0; } self.textMap.set(element.text, node.element.textIndex); } if (element.className != null && element.className !== '') { if (self.classNameMap.has(element.className)) { node.element.classNameIndex = self.classNameMap.get(element.className) + 1; } else { node.element.classNameIndex = 0; } self.classNameMap.set(element.className, node.element.classNameIndex); } self.nodes.set(key, node); } }, drawLine: function(startPos, endPos, color) { if (!startPos || !endPos) { return; } color = color || 'black'; var ctx = this.canvas.fg.getContext('2d'); ctx.beginPath(); ctx.moveTo(startPos.x, startPos.y); ctx.lineWidth = 5; ctx.lineTo(endPos.x, endPos.y); ctx.strokeStyle = color; ctx.stroke(); ctx.closePath(); }, clearFg: function() { var self = this; var canvas = self.canvas.fg; var ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); }, drawAllNode: function () { var self = this; var canvas = self.canvas.fg; var ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); }, drawHoverNode: function (pos) { var self = this; var canvas = self.canvas.fg; self.nodeHovered = null; var minArea = Infinity; function isInside(node, x, y) { var lx = node.element.bounds[0], ly = node.element.bounds[1], rx = node.element.bounds[2], ry = node.element.bounds[3]; return lx < x && x < rx && ly < y && y < ry; } let nodeList = Array.from(self.nodes.values()); var activeNodes = []; activeNodes = nodeList.filter(function (node) { if (!isInside(node, pos.x, pos.y)) { return false; } var bs = node.element.bounds; var area = (bs[2] - bs[0]) * (bs[3] - bs[1]); if (area < minArea) { minArea = area; self.nodeHovered = node; } else if (node.id > self.nodeHovered.id) { minArea = area; self.nodeHovered = node; } return true; }); self.drawNode(self.nodeHovered, "green"); self.drawClickPos(self.nodeHovered) }, getInstanceMap: function(node) { if (!node || !node.element) { return; } let self = this; let element = node.element; if (element.resourceId != null && element.resourceId !== '' && self.resourceIdMap.has(element.resourceId)) { for (let [index, value] of self.resourceIdMap.get(element.resourceId).entries()) { if (value.element.id == element.id) { element.resourceIdIndex = index; break; } } } if (element.className != null && element.className !== '' && self.classNameMap.has(element.className)) { for (let [index, value] of self.classNameMap.get(element.className).entries()) { if (value.element.id == element.id) { element.classNameIndex = index; break; } } } if (element.text != null && element.text !== '') { for (let [index, value] of self.textMap.get(element.text).entries()) { if (value.element.id == element.id) { element.textIndex = index; break; } } } }, getNodeByResourceId: function(root) { var self = this; if (!root && !root.element) { return null; } if (root.element.resourceId != null && root.element.resourceId !== '') { return root; } else { let parentId = root.parentId + ''; let parentNode = self.nodes.has(parentId) ? self.nodes.get(parentId) : {}; return self.getNodeByResourceId(parentNode); } }, getNodeSelector: function(node) { if (!node || !node.element) { return null; } if (node.element.resourceId != null && node.element.resourceId !== '') { return {'#method#':'resourceId', '#key#':node.element.resourceId, '#index#': node.element.resourceIdIndex}; } else if (node.element.text != null && node.element.text !== '') { return {'#method#':'text', '#key#':node.element.text, '#index#': node.element.textIndex}; } else if (node.element.className != null && node.element.className !== '') { return {'#method#':'className', '#key#':node.element.className, '#index#': node.element.classNameIndex}; } else { return null; } }, getChildNodeIndex: function(parentNode, currentNode, method, key) { let self = this; if (!parentNode || !parentNode.element || !currentNode || !currentNode.element) { return -1; } let parentId = parentNode.element.id; let currentId = currentNode.element.id; let index = -1; for (var i=parentId+1; i<=currentId; i++) { let node = self.nodes.get(i+''); if (node.element[method] === key) { index++; // console.log('current index is:' + index + ', has same element:' + node.element); } } return index; }, generateSwipeCode: function (startPos, endPos) { let self = this; let codeTemplate = self.swipeCode; let code = codeTemplate; let startX = startPos.x / self.mouseOperation.resolution.width; let startY = startPos.y / self.mouseOperation.resolution.height; let endX = endPos.x / self.mouseOperation.resolution.width; let endY = endPos.y / self.mouseOperation.resolution.height; code = code.replace("#startX#", startX.toFixed(2)); code = code.replace("#startY#", startY.toFixed(2)); code = code.replace("#endX#", endX.toFixed(2)); code = code.replace("#endY#", endY.toFixed(2)); code = code + self.commonCode; code = code.replace('#timeout#', '' + self.defaultTimeout); if (self.selectedCase.name) { code = code.replace('#description#', 'Case' + self.selectedCase.index + ':' + self.selectedCase.name); } else { code = code.replace('#description#', ''); } this.currentCodeBlock = { 'id': this.codeList.length + 1, 'title': '从(' + startX.toFixed(2) + ',' + startY.toFixed(2) + ')滑动至(' + endX.toFixed(2) + ',' + endY.toFixed(2) + ')', 'code': code}; return code; }, codeGenerate: function(node) { if (!node || !node.element) { return 'can not generate code'; } console.log('generate code'); let self = this; let codeTemplate = self.singleSelectCode; let assertCodeTemplate = self.singleAssertCode; let currentNodeSelector = null; let parentKey = ''; let parentIndex = 0; let rootNode = self.getNodeByResourceId(node); let nodeDesc = self.getNodeDesc(node); if (rootNode !== null) { if (rootNode.element.id === node.element.id) { currentNodeSelector = self.getNodeSelector(node); } else { codeTemplate = self.childSelectCode; assertCodeTemplate = self.childAssertCode; currentNodeSelector = self.getNodeSelector(node); if (currentNodeSelector !== null) { currentNodeSelector['#index#'] = self.getChildNodeIndex(rootNode, node, currentNodeSelector['#method#'], currentNodeSelector['#key#']); } currentNodeSelector['#parentKey#'] = rootNode.element.resourceId; currentNodeSelector['#parentIndex#'] = rootNode.element.resourceIdIndex; } if (nodeDesc === '') { nodeDesc = self.getNodeDesc(rootNode); } } else { currentNodeSelector = self.getNodeSelector(node); } if (currentNodeSelector === null) { return 'can not generate code'; } else { self.mouseOperation.data.selector = currentNodeSelector; let localBounds = self.mouseOperation.data.bounds; let heightRadio = Math.abs(localBounds[3] - localBounds[1]) / self.mouseOperation.resolution.height; let widthRadio = Math.abs(localBounds[2] - localBounds[0]) / self.mouseOperation.resolution.width; if (heightRadio > 0.5 && widthRadio > 0.5) { self.mouseOperation.type = 'position'; } let code = codeTemplate; let assertCode = assertCodeTemplate; for (let [key, value] of self.objectEntry(currentNodeSelector)) { code = code.replace(key, value); assertCode = assertCode.replace(key, value); } console.log(code); console.log(assertCode); code = code + self.commonCode; code = code.replace('#timeout#', '' + self.defaultTimeout); if (self.selectedCase.name) { code = code.replace('#description#', 'Case' + self.selectedCase.index + ':' + self.selectedCase.name); } else { code = code.replace('#description#', ''); } if (nodeDesc === '') { nodeDesc = '位置:(' + self.mouseOperation.data.endPos.x + ',' + self.mouseOperation.data.endPos.y + ')'; } this.currentCodeBlock = { id: this.codeList.length + 1, title: nodeDesc, code: code, assertCode: assertCode, opCode: code, assertable: true, isAssert: false, action: '点击' }; return code; } }, getNodeDesc: function(node) { if (node.element.text != null && node.element.text !== '') { return node.element.text; } else if (node.element.resourceId != null && node.element.resourceId !== '') { return node.element.resourceId; } else if (node.element.description != null && node.element.description !== '') { return node.element.description; } else if (node.element.className != null && node.element.className !== '') { return node.element.className; } else { return ''; } }, addNewDragNode: function(pos) { // this.drawCircle(pos); let len = this.dragNodeList.length; if (len > 0) { if (pos.x !== this.dragNodeList[len - 1].x || pos.y !== this.dragNodeList[len -1].y) { this.dragNodeList.push(pos); } } else { this.dragNodeList.push(pos); } len = this.dragNodeList.length; if (len >= 2) { this.drawLine(this.drawLine(this.dragNodeList[len-2], this.dragNodeList[len-1], 'red')); } this.currentCodeBlock.title = '拖拽操作'; this.currentCodeBlock.id = this.codeList.length + 1; this.currentCodeBlock.code = this.refreshDragCode(); this.currentCodeBlock.assertCode = ''; this.currentCodeBlock.opCode = this.currentCodeBlock.code; this.currentCodeBlock.assertable = false; this.currentCodeBlock.isAssert = false; this.currentCodeBlock.action = ''; }, drawCircle: function(pos) { if (!pos) { return; } var ctx = this.canvas.fg.getContext('2d'); ctx.beginPath(); ctx.arc(pos.x, pos.y, 10 ,0, 360, false); ctx.fillStyle="red";//填充颜色,默认是黑色 ctx.fill();//画实心圆 ctx.stroke(); ctx.closePath(); }, refreshDragCode: function() { let pointName = 'points' + this.pointListIndex++; let pointDefCode = '\nPoint[] ' + pointName + ' = {'; let pointCode = this.pointCode; let pos = this.dragNodeList[0]; console.log(this.dragNodeList.length); pointCode = pointCode.replace( "#x#", '' + (pos.x / this.mouseOperation.resolution.width).toFixed(2) + 'f'); pointCode = pointCode.replace( "#y#", '' + (pos.y / this.mouseOperation.resolution.height).toFixed(2) + 'f'); pointCode = pointDefCode + pointCode; if (this.dragNodeList.length > 1) { for (let i=1; i<this.dragNodeList.length; i++) { let tmp = this.dragNodeList[i]; let tmpCode = this.pointCode.replace( "#x#", '' + (tmp.x / this.mouseOperation.resolution.width).toFixed(2) + 'f'); tmpCode = tmpCode.replace( "#y#", '' + (tmp.y / this.mouseOperation.resolution.height).toFixed(2) + 'f'); pointCode = pointCode + ',' + tmpCode; } } pointCode = pointCode + '};\ndevice.swipe(' + pointName +', 40);'; // pointCode = pointCode + '}, 40);'; console.log(pointCode); return pointCode + '\nSystemClock.sleep(5000);\n'; }, cvCodeGen: function(imageName, imageDesc) { let code = this.cvSelectCode; let assertCode = this.cvAssertCode; code = code.replace('#imageName#', imageName); assertCode = assertCode.replace('#imageName#', imageName); code = code.replace('#imageDesc#', imageDesc); assertCode = assertCode.replace('#imageDesc#', imageDesc); let captureRadio = this.storeData.screenData.captureRadio; code = code.replace('#left#', '' + captureRadio.left); code = code.replace('#right#', '' + captureRadio.right); code = code.replace('#top#', '' + captureRadio.top); code = code.replace('#bottom#', '' + captureRadio.bottom); assertCode = assertCode.replace('#left#', '' + captureRadio.left); assertCode = assertCode.replace('#right#', '' + captureRadio.right); assertCode = assertCode.replace('#top#', '' + captureRadio.top); assertCode = assertCode.replace('#bottom#', '' + captureRadio.bottom); code = code + this.commonCode; code = code.replace('#timeout#', '' + this.defaultTimeout); if (this.selectedCase.name) { code = code.replace('#description#', 'Case' + this.selectedCase.index + ':' + this.selectedCase.name); } else { code = code.replace('#description#', ''); } return {opCode: code, assertCode: assertCode}; }, installApk: function(installStatus) { if (installStatus !== 'ready') { return; } else { let self = this; self.installing = true; let data = {fileName: self.storeData.appData.appFile}; console.log(data); $.ajax({ type: 'POST', dataType: 'json', url: BASE_URL + 'device/' + encodeURIComponent(this.serial) + '/installApk', data: (data),