Files
appium/lib/devices/common.js

261 lines
7.7 KiB
JavaScript

"use strict";
var errors = require('../server/errors.js')
, request = require('request')
, _ = require('underscore')
, exec = require('child_process').exec
, status = require("../server/status.js")
, logger = require('../server/logger.js').get('appium');
var UnknownError = errors.UnknownError
, ProtocolError = errors.ProtocolError;
exports.respond = function(response, cb) {
if (typeof response === 'undefined') {
cb(null, '');
} else {
if (typeof(response) !== "object") {
cb(new UnknownError(), response);
} else if (!('status' in response)) {
cb(new ProtocolError('Status missing in response from device'), response);
} else {
var status = parseInt(response.status, 10);
if (isNaN(status)) {
cb(new ProtocolError('Invalid status in response from device'), response);
} else {
response.status = status;
cb(null, response);
}
}
}
};
exports.proxy = function(command, cb) {
// was thinking we should use a queue for commands instead of writing to a file
logger.info('Pushing command to appium work queue: ' + JSON.stringify(command));
this.push([command, cb]);
if (typeof command === "object") {
command = JSON.stringify(command);
}
};
exports.waitForCondition = function(waitMs, condFn, cb, intervalMs) {
if (typeof intervalMs === "undefined") {
intervalMs = 500;
}
var begunAt = Date.now();
var endAt = begunAt + waitMs;
var spin = function() {
condFn(function(condMet) {
var args = Array.prototype.slice.call(arguments);
if (condMet) {
cb.apply(this, args.slice(1));
} else if (Date.now() < endAt) {
setTimeout(spin, intervalMs);
} else {
cb.apply(this, args.slice(1));
}
}.bind(this));
}.bind(this);
spin();
};
exports.doRequest = function(url, method, body, contentType, cb) {
if (typeof cb === "undefined" && typeof contentType === "function") {
cb = contentType;
contentType = null;
}
if (typeof contentType === "undefined" || contentType === null) {
contentType = "application/json;charset=UTF-8";
}
if (!(/^https?:\/\//.exec(url))) {
url = 'http://' + url;
}
var opts = {
url: url
, method: method
};
if (_.contains(['put', 'post', 'patch'], method.toLowerCase())) {
if (typeof body === "object") {
opts.json = body;
} else {
opts.body = body || "";
}
}
// explicitly set these headers with correct capitalization to work around
// an issue in node/requests
logger.info("Making http request with opts: " + JSON.stringify(opts));
request(opts, function(err, res, body) {
cb(err, res, body);
});
};
exports.isAppInstalled = function(isInstalledCommand, cb) {
exec(isInstalledCommand, function(error, stdout) {
cb(error, stdout);
});
};
exports.removeApp = function(removeCommand, udid, bundleId, cb) {
exec(removeCommand, function(error) {
if (error !== null) {
cb(error, 'Unable to un-install [' + bundleId + '] from device with id [' + udid + ']. Error [' + error + ']');
} else {
cb(error, 'Successfully un-installed [' + bundleId + '] from device with id [' + udid + ']');
}
});
};
exports.installApp = function(installationCommand, udid, unzippedAppPath, cb) {
exec(installationCommand, function(error) {
if (error !== null) {
cb(error, 'Unable to install [' + unzippedAppPath + '] to device with id [' + udid + ']. Error [' + error + ']');
} else {
cb(error, 'Successfully unzipped and installed [' + unzippedAppPath + '] to device with id [' + udid + ']');
}
});
};
exports.unpackApp = function(req, packageExtension, cb) {
var reqAppPath = req.body.appPath;
if (reqAppPath.toLowerCase().substring(0, 4) === "http") {
req.appium.downloadAndUnzipApp(reqAppPath, function(err, appPath) {
cb(appPath);
});
} else if (reqAppPath.toLowerCase().substring(reqAppPath.length - 4) === ".zip") {
req.appium.unzipLocalApp(reqAppPath, function(err, appPath) {
cb(appPath);
});
} else if (reqAppPath.toLowerCase().substring(reqAppPath.length - 4) === packageExtension) {
cb(reqAppPath.toString());
} else {
cb(null);
}
};
exports.proxyTo = function(endpoint, method, data, cb) {
if (endpoint[0] !== '/') {
endpoint = '/' + endpoint;
}
var url = 'http://' + this.proxyHost + ':' + this.proxyPort + endpoint;
exports.doRequest(url, method, data ? data : '', cb);
};
exports.parseExecuteResponse = function(response, cb) {
if ((response.value !== null) && (typeof response.value !== "undefined")) {
var wdElement = null;
if (!_.isArray(response.value)) {
if (typeof response.value.ELEMENT !== "undefined") {
wdElement = response.value.ELEMENT;
wdElement = this.parseElementResponse(response.value);
if (wdElement === null) {
cb(null, {
status: status.codes.UnknownError.code
, value: "Error converting element ID atom for using in WD: " + response.value.ELEMENT
});
}
response.value = wdElement;
}
} else {
var args = response.value;
for (var i=0; i < args.length; i++) {
wdElement = args[i];
if ((args[i] !== null) && (typeof args[i].ELEMENT !== "undefined")) {
wdElement = this.parseElementResponse(args[i]);
if (wdElement === null) {
cb(null, {
status: status.codes.UnknownError.code
, value: "Error converting element ID atom for using in WD: " + args[i].ELEMENT
});
return;
}
args[i] = wdElement;
}
}
response.value = args;
}
}
return response;
};
exports.parseElementResponse = function(element) {
var objId = element.ELEMENT
, clientId = (5000 + this.webElementIds.length).toString();
this.webElementIds.push(objId);
return {ELEMENT: clientId};
};
exports.getAtomsElement = function(wdId) {
var atomsId;
try {
atomsId = this.webElementIds[parseInt(wdId, 10) - 5000];
} catch(e) {
return null;
}
if (typeof atomsId === "undefined") {
return null;
}
return {'ELEMENT': atomsId};
};
exports.useAtomsElement = function(elementId, failCb, cb) {
if (parseInt(elementId, 10) < 5000) {
logger.info("Element with id " + elementId + " passed in for use with " +
"atoms, but it's out of our internal scope. Adding 5000");
elementId = (parseInt(elementId, 10) + 5000).toString();
}
var atomsElement = this.getAtomsElement(elementId);
if (atomsElement === null) {
failCb(null, {
status: status.codes.UnknownError.code
, value: "Error converting element ID for using in WD atoms: " + elementId
});
} else {
cb(atomsElement);
}
};
exports.convertElementForAtoms = function(args, cb) {
for (var i=0; i < args.length; i++) {
if (args[i] !== null && typeof args[i].ELEMENT !== "undefined") {
var atomsElement = this.getAtomsElement(args[i].ELEMENT);
if (atomsElement === null) {
cb(true, {
status: status.codes.UnknownError.code
, value: "Error converting element ID for using in WD atoms: " + args[i].ELEMENT
});
return;
}
args[i] = atomsElement;
}
}
cb(null, args);
};
exports.getLog = function(logType, cb) {
// go ahead and respond with 'logcat' type no matter what they send in
if (logType !== 'logcat') {
logger.warn("Trying to get log type of " + logType + ", giving logcat " +
"instead");
}
var logs;
try {
logs = this.adb.getLogcatLogs();
} catch (e) {
return cb(e);
}
cb(null, {
status: status.codes.Success.code
, value: logs
});
};
exports.getLogTypes = function(cb) {
return cb(null, {
status: status.codes.Success.code
, value: ['logcat']
});
};