appium-uiauto
Advanced tools
Comparing version 1.2.0-beta3 to 1.2.0-beta4
@@ -0,10 +1,22 @@ | ||
// This is the uiauto facade for appium, the Command Proxy relays uiauto message | ||
// to and from Appium. | ||
// The messages route is the following: | ||
// Appium <--> Command Proxy <--> Instruments | ||
// The medium between Instruments and Command Proxy is the command-proxy-client script. | ||
// The format of the Command Proxy --> Instruments messages is {cmd:"<CMD>"} | ||
// The format of the Instruments --> Command Proxy messages is: | ||
// <one char message type>,<stringified json data> | ||
// The json data in the message above has the following format: | ||
// {status:<status>, value:<result>} | ||
'use strict'; | ||
var logger = require('./logger.js'), | ||
fs = require('fs'), | ||
through = require('through'), | ||
_ = require('underscore'), | ||
net = require('net'); | ||
var MORE_COMMAND = "#more"; | ||
var MESSAGE_TYPES = ['error','no data','regular','chunk','last chunk']; | ||
var UNKNOWN_ERROR = { | ||
@@ -15,3 +27,6 @@ status: 13, | ||
function isChunk(data) { return data.type && data.type.indexOf('chunk') >= 0; } | ||
var Proxy = function (opts) { | ||
opts = opts || {}; | ||
var curCommand = null; | ||
@@ -25,9 +40,8 @@ var onReceiveCommand = null; | ||
var currentSocket = null; | ||
var eventRouter = {}; | ||
var firstSocketConnectionCb = null; | ||
var resultBuffer = ""; | ||
var onSocketConnect = function (conn) { | ||
if (!hasConnected) { | ||
hasConnected = true; | ||
logger.debug("Instruments is ready to receive commands"); | ||
logger.info("Instruments is ready to receive commands"); | ||
firstSocketConnectionCb(); | ||
@@ -52,22 +66,21 @@ } | ||
bufferedData = ""; | ||
var parsedData; | ||
try { | ||
data = JSON.parse(data); | ||
parsedData = { | ||
type: MESSAGE_TYPES[parseInt(data[0], 10)], | ||
}; | ||
if (parsedData.type !== 'no data') { | ||
// format is <one char message type>,<DATA> | ||
parsedData.result = data.substring(2); | ||
} | ||
} catch (e) { | ||
logger.error("Couldn't parse JSON data from socket, maybe buffer issue?"); | ||
logger.error("Couldn't parse data from socket, maybe buffer issue?"); | ||
logger.error(data); | ||
data = { | ||
event: 'cmd', | ||
result: UNKNOWN_ERROR | ||
parsedData = { | ||
type: 'error', | ||
error: UNKNOWN_ERROR | ||
}; | ||
} | ||
if (!_.has(data, 'event')) { | ||
logger.error("Socket data came in without event, it was:"); | ||
logger.error(JSON.stringify(data)); | ||
} else if (!_.has(eventRouter, data.event)) { | ||
logger.error("Socket is asking for event '" + data.event + | ||
"' which doesn't exist"); | ||
} else { | ||
logger.debug("Socket data being routed for '" + data.event + "' event"); | ||
eventRouter[data.event](data, conn); | ||
} | ||
logger.debug("Socket data being routed for '" + data.event + "' event"); | ||
getResultAndSendNext(parsedData, conn); | ||
}); | ||
@@ -84,7 +97,7 @@ }; | ||
eventRouter.cmd = function (data, c) { | ||
var getResultAndSendNext = function (data, c) { | ||
var hasResult = typeof data.result !== "undefined"; | ||
if (hasResult && !curCommand) { | ||
logger.info("Got a result when we weren't expecting one! Ignoring it"); | ||
logger.info("Result was: " + JSON.stringify(data.result)); | ||
logger.info("Result was: " + data.result); | ||
} else if (!hasResult && curCommand) { | ||
@@ -99,8 +112,24 @@ logger.info("Instruments didn't send a result even though we were expecting one"); | ||
logger.debug("Got result from instruments: " + | ||
JSON.stringify(data.result).slice(0, 300)); | ||
data.result.slice(0, 300)); | ||
} else { | ||
logger.debug("Got null result from instruments"); | ||
} | ||
curCommand.cb(data.result); | ||
curCommand = null; | ||
if (isChunk(data)) { | ||
resultBuffer += data.result; | ||
logger.debug("Got chunk data, current resultBuffer length: " + resultBuffer.length); | ||
if (data.type === 'last chunk') { | ||
logger.debug("This is the last data final length: " + resultBuffer.length); | ||
// this is the last row, unpack and respond to command | ||
var result = JSON.parse(resultBuffer); | ||
resultBuffer = ""; | ||
curCommand.cb(result); | ||
curCommand = null; | ||
} else { | ||
logger.debug("Not the last chunk, trying to get more"); | ||
commandQueue.unshift({cmd: MORE_COMMAND, cb: curCommand.cb}); | ||
} | ||
} else { | ||
curCommand.cb(JSON.parse(data.result)); | ||
curCommand = null; | ||
} | ||
} | ||
@@ -111,4 +140,4 @@ | ||
onReceiveCommand = null; | ||
logger.debug("Sending command to instruments: " + curCommand.cmd); | ||
c.write(JSON.stringify({nextCommand: curCommand.cmd})); | ||
logger.info("Sending command to instruments: " + curCommand.cmd); | ||
c.write(JSON.stringify({cmd: curCommand.cmd})); | ||
c.end(); | ||
@@ -154,3 +183,4 @@ //debug("Closing our half of the connection"); | ||
this.start = function (_firstSocketConnectionCb, cb) { | ||
firstSocketConnectionCb = _firstSocketConnectionCb; | ||
cb = cb || function () {}; | ||
firstSocketConnectionCb = _firstSocketConnectionCb || function () {}; | ||
//initSocketServer | ||
@@ -176,3 +206,3 @@ socketServer = net.createServer({allowHalfOpen: true}, | ||
if (err) return cb(err); | ||
logger.debug("Instruments socket server started at " + sock); | ||
logger.info("Instruments socket server started at " + sock); | ||
cb(); | ||
@@ -179,0 +209,0 @@ }); |
@@ -0,1 +1,4 @@ | ||
// This generates a bootstrap for the uiauto instruments script containing | ||
// the environment variable we need. | ||
'use strict'; | ||
@@ -19,3 +22,4 @@ | ||
function buildEnv(opts) { | ||
function getEnv(opts) { | ||
opts = opts || {}; | ||
var bootstrapEnv = { | ||
@@ -25,4 +29,4 @@ USER: process.env.USER, | ||
CWD: process.cwd(), | ||
INSTRUMENTS_CLIENT_PATH: path.resolve( | ||
__dirname, '../bin/instruments-client.js'), | ||
COMMAND_PROXY_CLIENT_PATH: path.resolve( | ||
__dirname, '../bin/command-proxy-client.js'), | ||
VERBOSE_INSTRUMENTS: opts.verboseInstruments || | ||
@@ -60,5 +64,5 @@ toBoolean(process.env.VERBOSE_INSTRUMENTS) | ||
var dynamicBootstrapDir; | ||
if (process.env.DYNAMIC_BOOTSTRAP_DIR) { | ||
if (process.env.APPIUM_BOOTSTRAP_DIR) { | ||
// mainly for test | ||
dynamicBootstrapDir = process.env.DYNAMIC_BOOTSTRAP_DIR; | ||
dynamicBootstrapDir = process.env.APPIUM_BOOTSTRAP_DIR; | ||
} else if (process.env.HOME) { | ||
@@ -74,6 +78,13 @@ dynamicBootstrapDir = path.resolve(process.env.HOME, | ||
// building code and hash | ||
var env = buildEnv(opts); | ||
logger.debug('Dynamic env:', JSON.stringify(env)); | ||
var bootstrapJs = path.resolve(__dirname,'../uiauto/bootstrap.js'); | ||
var code = buildCode(env, bootstrapJs); | ||
var code; | ||
if (!opts.code) { | ||
// building default | ||
var env = getEnv(opts); | ||
logger.debug('Dynamic env:', JSON.stringify(env)); | ||
var bootstrapJs = path.resolve(__dirname,'../uiauto/bootstrap.js'); | ||
code = buildCode(env, bootstrapJs); | ||
} else { | ||
code = opts.code; | ||
} | ||
var hash = computeHash(code); | ||
@@ -106,1 +117,3 @@ var dynamicBootstrapPath = path.resolve(dynamicBootstrapDir, | ||
exports.prepareBootstrap = prepareBootstrap; | ||
exports.getEnv = getEnv; | ||
{ | ||
"name": "appium-uiauto", | ||
"version": "1.2.0-beta3", | ||
"version": "1.2.0-beta4", | ||
"description": "appium uiauto ios driver", | ||
"main": "lib/main.js", | ||
"bin": { | ||
"instruments-client.js": "./bin/instruments-client.js" | ||
}, | ||
@@ -34,8 +33,11 @@ "scripts": { | ||
"devDependencies": { | ||
"appium-instruments": "1.1.0-beta2", | ||
"chai": "~1.9.1", | ||
"chai-as-promised": "~4.1.1", | ||
"jscs": "https://github.com/appium/node-jscs/archive/instruments-js.tar.gz", | ||
"jshint": "~2.5.1", | ||
"mocha": "^1.20.1", | ||
"mocha": "~1.20.1", | ||
"rimraf": "~2.2.8", | ||
"sinon": "^1.10.2" | ||
"sinon": "~1.10.2" | ||
} | ||
} |
@@ -33,4 +33,4 @@ 'use strict'; | ||
env.CWD.should.equal(process.cwd()); | ||
env.INSTRUMENTS_CLIENT_PATH.should.exist; | ||
fs.existsSync(env.INSTRUMENTS_CLIENT_PATH).should.be.ok; | ||
env.COMMAND_PROXY_CLIENT_PATH.should.exist; | ||
fs.existsSync(env.COMMAND_PROXY_CLIENT_PATH).should.be.ok; | ||
env.VERBOSE_INSTRUMENTS.should.equal(opts.VERBOSE_INSTRUMENTS); | ||
@@ -52,8 +52,8 @@ } | ||
it('should generate dynamic bootstrap', function (done) { | ||
process.env.DYNAMIC_BOOTSTRAP_DIR = '/tmp/appium-uiauto/test/bootstrap'; | ||
rimraf(process.env.DYNAMIC_BOOTSTRAP_DIR) | ||
process.env.APPIUM_BOOTSTRAP_DIR = '/tmp/appium-uiauto/test/unit/bootstrap'; | ||
rimraf(process.env.APPIUM_BOOTSTRAP_DIR) | ||
// first call: should create new bootstrap file | ||
.then(function () { return prepareBootstrap(); }) | ||
.then(function (bootstrapFile) { | ||
bootstrapFile.should.match(/\/tmp\/appium-uiauto\/test\/bootstrap\/bootstrap\-.*\.js/); | ||
bootstrapFile.should.match(/\/tmp\/appium-uiauto\/test\/unit\/bootstrap\/bootstrap\-.*\.js/); | ||
var code = fs.readFileSync(bootstrapFile, 'utf8'); | ||
@@ -67,3 +67,3 @@ checkCode(code, {VERBOSE_INSTRUMENTS: false}); | ||
.then(function (bootstrapFile) { | ||
bootstrapFile.should.match(/\/tmp\/appium-uiauto\/test\/bootstrap\/bootstrap\-.*\.js/); | ||
bootstrapFile.should.match(/\/tmp\/appium-uiauto\/test\/unit\/bootstrap\/bootstrap\-.*\.js/); | ||
var code = fs.readFileSync(bootstrapFile, 'utf8'); | ||
@@ -77,3 +77,3 @@ checkCode(code, {VERBOSE_INSTRUMENTS: false}); | ||
.then(function (bootstrapFile) { | ||
bootstrapFile.should.match(/\/tmp\/appium-uiauto\/test\/bootstrap\/bootstrap\-.*\.js/); | ||
bootstrapFile.should.match(/\/tmp\/appium-uiauto\/test\/unit\/bootstrap\/bootstrap\-.*\.js/); | ||
var code = fs.readFileSync(bootstrapFile, 'utf8'); | ||
@@ -80,0 +80,0 @@ checkCode(code, {VERBOSE_INSTRUMENTS: true}); |
@@ -0,1 +1,10 @@ | ||
// The messages route is the following: | ||
// Appium <--> Command Proxy <--> Instruments | ||
// The medium between Instruments and Command Proxy is the command-proxy-client script. | ||
// The format of the Command Proxy --> Instruments messages is {cmd:"<CMD>"} | ||
// The format of the Instruments --> Command Proxy messages is: | ||
// <one char message type>,<stringified json data> | ||
// The json data in the message above has the following format: | ||
// {status:<status>, value:<result>} | ||
/* globals $, errors, env */ | ||
@@ -7,18 +16,62 @@ | ||
var BOOTSTRAP_CONFIG_PREFIX = "setBootstrapConfig: "; | ||
var BIG_DATA_THRESHOLD = 50000; | ||
var MORE_COMMAND = "#more"; | ||
var MESSAGE_TYPES = ['error','no data','regular','chunk','last chunk']; | ||
commands = {}; | ||
var WAIT_FOR_DATA_TIMEOUT = 3600; | ||
var curAppiumCmdId = -1; | ||
function BigResult(_result) { | ||
this.result = _result; | ||
this.idx = 0; | ||
this.noMore = function () { | ||
return this.idx > this.result.length; | ||
}; | ||
this.messageType = function () { | ||
return this.noMore()? MESSAGE_TYPES.indexOf('last chunk') : | ||
MESSAGE_TYPES.indexOf('chunk'); | ||
}; | ||
this.nextChunk = function () { | ||
var _this = this; | ||
var nextIdx = this.idx + BIG_DATA_THRESHOLD; | ||
var chunk = _this.result.substring(_this.idx, nextIdx); | ||
this.idx = nextIdx; | ||
return chunk; | ||
}; | ||
} | ||
var bigResult = null; | ||
var prepareChunk = function (args) { | ||
var chunk = bigResult.nextChunk(); | ||
args.push(bigResult.messageType() + ',' + chunk); | ||
if (bigResult.noMore()) bigResult = null; | ||
}; | ||
var sendResultAndGetNext = function (result) { | ||
curAppiumCmdId++; | ||
var args = [env.instrumentsClientPath, '-s', '/tmp/instruments_sock'], res; | ||
var args = [env.commandProxyClientPath, '/tmp/instruments_sock']; | ||
if (typeof result !== "undefined") { | ||
args = args.concat(['-r', JSON.stringify(result)]); | ||
if (result.type === 'chunk') { | ||
// we responded to the 'more' command | ||
prepareChunk(args); | ||
} else { | ||
var stringResult = JSON.stringify(result); | ||
if (stringResult.length < BIG_DATA_THRESHOLD){ | ||
// regular small results | ||
args.push(MESSAGE_TYPES.indexOf('regular') + ',' +stringResult); | ||
} else { | ||
// initiating big result transfer | ||
bigResult = new BigResult(stringResult); | ||
prepareChunk(args); | ||
} | ||
} | ||
} else { | ||
args.push(MESSAGE_TYPES.indexOf('no data') + ','); | ||
} | ||
var cmd = env.nodePath + " " + args.join(" "); | ||
var cmdLog = cmd.slice(0, 300); | ||
var cmdLog = cmd.slice(0, 300) + '...'; | ||
var res; | ||
try { | ||
$.log("Running command #" + curAppiumCmdId + ": " + cmdLog); | ||
$.log("Running system command #" + curAppiumCmdId + ": " + cmdLog); | ||
res = $.system().performTaskWithPathArgumentsTimeout(env.nodePath, args, WAIT_FOR_DATA_TIMEOUT); | ||
@@ -30,14 +83,13 @@ } catch (e) { | ||
if (!res) { | ||
$.log("Instruments client (" + cmd + ") exited with null res"); | ||
$.log("Command proxy client (" + cmd + ") exited with null res"); | ||
return null; | ||
} | ||
if (res.exitCode !== 0) { | ||
$.log("Instruments client (" + cmd + ") exited with " + res.exitCode + | ||
", here's stderr:"); | ||
$.log(res.stderr); | ||
$.log("And stdout:"); | ||
$.log("Command proxy client (" + cmd + ") exited with " + res.exitCode + | ||
", here's stdout:"); | ||
$.log(res.stdout); | ||
return null; | ||
} | ||
return res.stdout; | ||
var output = res.stdout.replace(/^(.*\n)*----- OUTPUT -----\r?\n/g,''); | ||
return JSON.parse(output).cmd; | ||
}; | ||
@@ -58,3 +110,2 @@ | ||
try { | ||
if (cmd.indexOf(BOOTSTRAP_CONFIG_PREFIX) === 0) { | ||
@@ -64,6 +115,13 @@ var configStr = cmd.slice(BOOTSTRAP_CONFIG_PREFIX.length); | ||
eval(configStr); | ||
} else if (cmd === MORE_COMMAND) { | ||
result = { | ||
status: errors.Success.code, | ||
type: 'chunk', | ||
}; | ||
} else { | ||
/* jshint evil:true */ | ||
try { | ||
$.debug('evaluating ' + cmd); | ||
result = eval(cmd); | ||
$.debug('evaluation finished'); | ||
} catch (possStaleEl) { | ||
@@ -70,0 +128,0 @@ if (possStaleEl.message === errors.StaleElementReference.code) { |
@@ -92,6 +92,2 @@ /* globals $, errors */ | ||
UIAElement.prototype.getPageSource = function () { | ||
return JSON.stringify(this.getTree()); | ||
}; | ||
UIAElement.prototype.getElementLocation = function () { | ||
@@ -98,0 +94,0 @@ return { |
@@ -42,3 +42,3 @@ /* globals $ */ | ||
target.popTimeout(); | ||
return JSON.stringify(tree); | ||
return tree; | ||
}; | ||
@@ -76,2 +76,6 @@ | ||
UIAElement.prototype.getPageSource = function () { | ||
return JSON.stringify(this.getTree()); | ||
}; | ||
})(); |
@@ -23,3 +23,3 @@ /* globals $ */ | ||
this.nodePath = dynamicEnv.NODE_BIN; | ||
this.instrumentsClientPath = dynamicEnv.INSTRUMENTS_CLIENT_PATH; | ||
this.commandProxyClientPath = dynamicEnv.COMMAND_PROXY_CLIENT_PATH; | ||
}; | ||
@@ -26,0 +26,0 @@ |
@@ -90,3 +90,2 @@ /* globals $, errors */ | ||
var viewRes = this.getElementByType('scrollview'); | ||
$.log(JSON.stringify(viewRes)); | ||
var doScroll = function (elId) { | ||
@@ -93,0 +92,0 @@ var el = this.getElement(elId); |
/* jshint ignore:start */ | ||
#import "./basics-ext.js" | ||
#import "./util-ext.js" | ||
@@ -3,0 +4,0 @@ #import "./alert-ext.js" |
/* globals $, errors */ | ||
(function() { | ||
var delaySec = $.delay; | ||
$.extend($, { | ||
cache: [] | ||
, identifier: 0 | ||
, system: function() { return UIATarget.localTarget().host(); } | ||
, target: function () { return UIATarget.localTarget(); } | ||
, mainWindow: function () { return UIATarget.localTarget().frontMostApp().mainWindow(); } | ||
, mainApp: function () { return UIATarget.localTarget().frontMostApp(); } | ||
, keyboard: function () { return UIATarget.localTarget().frontMostApp().keyboard(); } | ||
, bundleId: function() { return UIATarget.localTarget().frontMostApp().bundleID(); } | ||
// overriding existing delay | ||
, delay: function (ms) { delaySec.call(this, ms/1000); } | ||
, _defaultContext: function(ctx) { | ||
@@ -19,0 +8,0 @@ if (typeof ctx === 'string') { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
166729
3093
8
49
17
4