pull out remote debugger related ios functionality into its own file

This commit is contained in:
Jonathan Lipps
2013-10-18 12:16:16 -07:00
parent c05ed2906e
commit cec0f84620
2 changed files with 218 additions and 203 deletions
+212
View File
@@ -0,0 +1,212 @@
"use strict";
var logger = require('../../server/logger.js').get('appium')
, _ = require('underscore')
, deviceCommon = require('../common.js')
, rd = require('./remote-debugger.js')
, wkrd = require('./webkit-remote-debugger.js');
var iOSHybrid = {};
iOSHybrid.navToInitialWebview = function(cb) {
if (this.autoWebview) {
this.navToFirstAvailWebview(cb);
} else {
cb();
}
};
iOSHybrid.navToFirstAvailWebview = function(cb) {
logger.info("Navigating to first available webview");
this.getWindowHandles(function(err, res) {
if (res.status !== 0) {
cb("Could not navigate to webview! Code: " + res.status);
} else if (res.value.length === 0) {
cb("Could not navigate to webview; there aren't any!");
} else {
logger.info("Picking webview " + res.value[0]);
this.setWindow(res.value[0], function(err) {
if (err) {
cb(err);
} else {
cb(null);
}
});
}
}.bind(this));
};
iOSHybrid.closeAlertBeforeTest = function(cb) {
this.proxy("au.alertIsPresent()", function(err, res) {
if (!err && res !== null && typeof res.value !== "undefined" && res.value === true) {
logger.info("Alert present before starting test, let's banish it");
this.proxy("au.dismissAlert()", function() {
logger.info("Alert banished!");
cb(true);
});
} else {
cb(false);
}
}.bind(this));
};
iOSHybrid.listWebFrames = function(cb, exitCb) {
var isDone = false;
if (!this.bundleId && !this.isSafariLauncherApp) {
logger.error("Can't enter web frame without a bundle ID");
return cb(new Error("Tried to enter web frame without a bundle ID"));
}
var onDone = function(res) {
this.processingRemoteCmd = false;
isDone = true;
cb(res);
}.bind(this);
this.processingRemoteCmd = true;
if (this.remote !== null && this.bundleId !== null) {
if (this.udid !== null) {
this.remote.pageArrayFromJson(function(pageArray) {
cb(pageArray);
});
} else {
this.remote.selectApp(this.bundleId, onDone);
}
} else {
if (this.udid !== null) {
this.remote = wkrd.init(exitCb);
this.remote.pageArrayFromJson(function(pageArray) {
cb(pageArray);
});
} else {
this.remote = new rd.init(exitCb);
this.remote.connect(function(appDict) {
if(!_.has(appDict, this.bundleId)) {
logger.error("Remote debugger did not list " + this.bundleId + " among " +
"its available apps");
if(_.has(appDict, "com.apple.mobilesafari")) {
logger.info("Using mobile safari instead");
this.remote.selectApp("com.apple.mobilesafari", onDone);
} else {
onDone([]);
}
} else {
this.remote.selectApp(this.bundleId, onDone);
}
}.bind(this), this.onPageChange.bind(this));
var loopCloseRuns = 0;
var loopClose = function() {
loopCloseRuns++;
if (!isDone && loopCloseRuns < 3) {
this.closeAlertBeforeTest(function(didDismiss) {
if (!didDismiss) {
setTimeout(loopClose, 1000);
}
});
}
}.bind(this);
setTimeout(loopClose, 4000);
}
}
};
iOSHybrid.onPageChange = function(pageArray) {
logger.info("Remote debugger notified us of a new page listing");
if (this.selectingNewPage) {
logger.info("We're in the middle of selecting a page, ignoring");
return;
}
var newIds = []
, keyId = null;
_.each(pageArray, function(page) {
newIds.push(page.id.toString());
if (page.isKey) {
keyId = page.id.toString();
}
});
var newPages = [];
var cachedHandles = _.pluck(this.windowHandleCache, 'id');
_.each(newIds, function(id) {
if (!_.contains(cachedHandles, id)) {
newPages.push(id);
}
});
var newPage = null;
if (this.curWindowHandle === null) {
logger.info("We don't appear to have window set yet, ignoring");
} else if (newPages.length) {
logger.info("We have new pages, going to select page " + newPages[0]);
newPage = newPages[0];
} else if (!_.contains(newIds, this.curWindowHandle.toString())) {
logger.info("New page listing from remote debugger doesn't contain " +
"current window, let's assume it's closed");
if (keyId !== null) {
logger.info("Debugger already selected page " + keyId + ", " +
"confirming that choice.");
} else {
logger.error("Don't have our current window anymore, and there " +
"aren't any more to load! Doing nothing...");
}
this.curWindowHandle = keyId;
this.remote.pageIdKey = parseInt(keyId, 10);
} else {
var dirty = function() {
var item = function(arr) {
return _.filter(arr, function(obj) {
return obj.id == this.curWindowHandle;
}, this)[0];
}.bind(this);
var win = item(pageArray);
var ret = false;
_.each(item(this.windowHandleCache), function(el, idx, l) {
if (l[idx] !== win[idx]) {
ret = true;
}
});
return ret;
}.bind(this);
// If a window gets navigated to an anchor it doesn't always fire a page callback event
// Let's check if we wound up in such a situation.
if (dirty()) {
this.remote.pageLoad();
}
logger.info("New page listing is same as old, doing nothing");
}
if (newPage !== null) {
this.selectingNewPage = true;
this.remote.selectPage(parseInt(newPage, 10), function() {
this.selectingNewPage = false;
this.curWindowHandle = newPage;
if (this.onPageChangeCb !== null) {
this.onPageChangeCb();
this.onPageChangeCb = null;
}
}.bind(this));
} else if (this.onPageChangeCb !== null) {
this.onPageChangeCb();
this.onPageChangeCb = null;
}
this.windowHandleCache = _.map(pageArray, this.massagePage);
};
iOSHybrid.getAtomsElement = deviceCommon.getAtomsElement;
iOSHybrid.stopRemote = function() {
if (!this.remote) {
logger.error("We don't appear to be in a web frame");
throw new Error("Tried to leave a web frame but weren't in one");
} else {
this.remote.disconnect();
this.curWindowHandle = null;
this.curWebFrames = [];
this.curWebCoords = null;
this.remote = null;
}
};
module.exports = iOSHybrid;
+6 -203
View File
@@ -12,14 +12,13 @@ var path = require('path')
, xmlplist = require('plist')
, instruments = require('./instruments.js')
, helpers = require('../../helpers.js')
, rd = require('./remote-debugger.js')
, wkrd = require('./webkit-remote-debugger.js')
, errors = require('../../server/errors.js')
, deviceCommon = require('../common.js')
, status = require("../../server/status.js")
, IDevice = require('node-idevice')
, async = require('async')
, iOSController = require('./ios-controller.js')
, iOSHybrid = require('./ios-hybrid.js')
, UnknownError = errors.UnknownError;
var IOS = function(args) {
@@ -246,14 +245,6 @@ IOS.prototype.setInitialOrientation = function(cb) {
}
};
IOS.prototype.navToInitialWebview = function(cb) {
if (this.autoWebview) {
this.navToFirstAvailWebview(cb);
} else {
cb();
}
};
IOS.prototype.onInstrumentsExit = function(code, traceDir, launchCb) {
if (!this.instrumentsDidLaunch) {
logger.error("Instruments did not launch successfully, failing session");
@@ -474,40 +465,6 @@ IOS.prototype.parseLocalizableStrings = function(cb) {
};
IOS.prototype.navToFirstAvailWebview = function(cb) {
logger.info("Navigating to first available webview");
this.getWindowHandles(function(err, res) {
if (res.status !== 0) {
cb("Could not navigate to webview! Code: " + res.status);
} else if (res.value.length === 0) {
cb("Could not navigate to webview; there aren't any!");
} else {
logger.info("Picking webview " + res.value[0]);
this.setWindow(res.value[0], function(err) {
if (err) {
cb(err);
} else {
cb(null);
}
});
}
}.bind(this));
};
IOS.prototype.closeAlertBeforeTest = function(cb) {
this.proxy("au.alertIsPresent()", function(err, res) {
if (!err && res !== null && typeof res.value !== "undefined" && res.value === true) {
logger.info("Alert present before starting test, let's banish it");
this.proxy("au.dismissAlert()", function() {
logger.info("Alert banished!");
cb(true);
});
} else {
cb(false);
}
}.bind(this));
};
IOS.prototype.getSimulatorApplications = function(cb) {
var user = process.env.USER;
var simDir = "/Users/" + user + "/Library/Application\\ " +
@@ -566,164 +523,6 @@ IOS.prototype.cleanupAppState = function(cb) {
}.bind(this));
};
IOS.prototype.listWebFrames = function(cb, exitCb) {
var isDone = false;
if (!this.bundleId && !this.isSafariLauncherApp) {
logger.error("Can't enter web frame without a bundle ID");
return cb(new Error("Tried to enter web frame without a bundle ID"));
}
var onDone = function(res) {
this.processingRemoteCmd = false;
isDone = true;
cb(res);
}.bind(this);
this.processingRemoteCmd = true;
if (this.remote !== null && this.bundleId !== null) {
if (this.udid !== null) {
this.remote.pageArrayFromJson(function(pageArray) {
cb(pageArray);
});
} else {
this.remote.selectApp(this.bundleId, onDone);
}
} else {
if (this.udid !== null) {
this.remote = wkrd.init(exitCb);
this.remote.pageArrayFromJson(function(pageArray) {
cb(pageArray);
});
} else {
this.remote = new rd.init(exitCb);
this.remote.connect(function(appDict) {
if(!_.has(appDict, this.bundleId)) {
logger.error("Remote debugger did not list " + this.bundleId + " among " +
"its available apps");
if(_.has(appDict, "com.apple.mobilesafari")) {
logger.info("Using mobile safari instead");
this.remote.selectApp("com.apple.mobilesafari", onDone);
} else {
onDone([]);
}
} else {
this.remote.selectApp(this.bundleId, onDone);
}
}.bind(this), this.onPageChange.bind(this));
var loopCloseRuns = 0;
var loopClose = function() {
loopCloseRuns++;
if (!isDone && loopCloseRuns < 3) {
this.closeAlertBeforeTest(function(didDismiss) {
if (!didDismiss) {
setTimeout(loopClose, 1000);
}
});
}
}.bind(this);
setTimeout(loopClose, 4000);
}
}
};
IOS.prototype.onPageChange = function(pageArray) {
logger.info("Remote debugger notified us of a new page listing");
if (this.selectingNewPage) {
logger.info("We're in the middle of selecting a page, ignoring");
return;
}
var newIds = []
, keyId = null;
_.each(pageArray, function(page) {
newIds.push(page.id.toString());
if (page.isKey) {
keyId = page.id.toString();
}
});
var newPages = [];
var cachedHandles = _.pluck(this.windowHandleCache, 'id');
_.each(newIds, function(id) {
if (!_.contains(cachedHandles, id)) {
newPages.push(id);
}
});
var newPage = null;
if (this.curWindowHandle === null) {
logger.info("We don't appear to have window set yet, ignoring");
} else if (newPages.length) {
logger.info("We have new pages, going to select page " + newPages[0]);
newPage = newPages[0];
} else if (!_.contains(newIds, this.curWindowHandle.toString())) {
logger.info("New page listing from remote debugger doesn't contain " +
"current window, let's assume it's closed");
if (keyId !== null) {
logger.info("Debugger already selected page " + keyId + ", " +
"confirming that choice.");
} else {
logger.error("Don't have our current window anymore, and there " +
"aren't any more to load! Doing nothing...");
}
this.curWindowHandle = keyId;
this.remote.pageIdKey = parseInt(keyId, 10);
} else {
var dirty = function() {
var item = function(arr) {
return _.filter(arr, function(obj) {
return obj.id == this.curWindowHandle;
}, this)[0];
}.bind(this);
var win = item(pageArray);
var ret = false;
_.each(item(this.windowHandleCache), function(el, idx, l) {
if (l[idx] !== win[idx]) {
ret = true;
}
});
return ret;
}.bind(this);
// If a window gets navigated to an anchor it doesn't always fire a page callback event
// Let's check if we wound up in such a situation.
if (dirty()) {
this.remote.pageLoad();
}
logger.info("New page listing is same as old, doing nothing");
}
if (newPage !== null) {
this.selectingNewPage = true;
this.remote.selectPage(parseInt(newPage, 10), function() {
this.selectingNewPage = false;
this.curWindowHandle = newPage;
if (this.onPageChangeCb !== null) {
this.onPageChangeCb();
this.onPageChangeCb = null;
}
}.bind(this));
} else if (this.onPageChangeCb !== null) {
this.onPageChangeCb();
this.onPageChangeCb = null;
}
this.windowHandleCache = _.map(pageArray, this.massagePage);
};
IOS.prototype.getAtomsElement = deviceCommon.getAtomsElement;
IOS.prototype.stopRemote = function() {
if (!this.remote) {
logger.error("We don't appear to be in a web frame");
throw new Error("Tried to leave a web frame but weren't in one");
} else {
this.remote.disconnect();
this.curWindowHandle = null;
this.curWebFrames = [];
this.curWebCoords = null;
this.remote = null;
}
};
IOS.prototype.postCleanup = function(cb) {
this.curCoords = null;
this.curOrientation = null;
@@ -745,7 +544,7 @@ IOS.prototype.postCleanup = function(cb) {
IOS.prototype.endSimulator = function(cb) {
var cmd = 'killall -9 "iPhone Simulator"';
exec(cmd, { maxBuffer: 524288 }, function(err, stdout, stderr) {
exec(cmd, { maxBuffer: 524288 }, function(err) {
cb(err);
});
};
@@ -875,6 +674,10 @@ IOS.prototype.unpackApp = function(req, cb) {
deviceCommon.unpackApp(req, '.app', cb);
};
_.each(_.keys(iOSHybrid), function(method) {
IOS.prototype[method] = iOSHybrid[method];
});
_.each(_.keys(iOSController), function(method) {
IOS.prototype[method] = iOSController[method];
});