rubick
Version:
tools for mtc
1,260 lines (1,224 loc) • 59.3 kB
JavaScript
'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),