mirror of
https://github.com/appium/appium.git
synced 2026-04-29 15:01:27 -05:00
allow automation of native chrome elements (fix #3434)
This commit is contained in:
@@ -3,10 +3,18 @@
|
||||
var Android = require('./android.js')
|
||||
, _ = require('underscore')
|
||||
, logger = require('../../server/logger.js').get('appium')
|
||||
, status = require('../../server/status.js')
|
||||
, deviceCommon = require('../common.js')
|
||||
, jwpSuccess = deviceCommon.jwpSuccess
|
||||
, async = require('async')
|
||||
, ADB = require('./adb.js')
|
||||
, UiAutomator = require('./uiautomator.js')
|
||||
, Chromedriver = require('./chromedriver.js');
|
||||
|
||||
var NATIVE_WIN = "NATIVE_APP";
|
||||
var WEBVIEW_WIN = "WEBVIEW";
|
||||
var WEBVIEW_BASE = WEBVIEW_WIN + "_";
|
||||
|
||||
var ChromeAndroid = function () {
|
||||
this.init();
|
||||
};
|
||||
@@ -15,10 +23,25 @@ _.extend(ChromeAndroid.prototype, Android.prototype);
|
||||
ChromeAndroid.prototype._androidInit = Android.prototype.init;
|
||||
ChromeAndroid.prototype.init = function () {
|
||||
this._androidInit();
|
||||
this.avoidProxy = [];
|
||||
this.isProxy = true;
|
||||
this.adb = null;
|
||||
this.onDie = null;
|
||||
this.setChromedriverMode();
|
||||
};
|
||||
|
||||
ChromeAndroid.prototype.setChromedriverMode = function () {
|
||||
logger.info("Set mode: Proxying straight through to Chromedriver");
|
||||
this.isProxy = true;
|
||||
// when proxying to chromedriver, we need to make sure the context endpoints
|
||||
// are trapped by appium for its own purposes
|
||||
this.avoidProxy = [
|
||||
['POST', new RegExp('^/wd/hub/session/[^/]+/context')],
|
||||
['GET', new RegExp('^/wd/hub/session/[^/]+/context')]
|
||||
];
|
||||
};
|
||||
|
||||
ChromeAndroid.prototype.setNativeMode = function () {
|
||||
logger.info("Set mode: Proxying to Appium Bootstrap");
|
||||
this.isProxy = false;
|
||||
};
|
||||
|
||||
ChromeAndroid.prototype.configure = function (args, caps, cb) {
|
||||
@@ -45,23 +68,28 @@ ChromeAndroid.prototype.configure = function (args, caps, cb) {
|
||||
delete this.capabilities.appActivity;
|
||||
this.setAndroidArgs();
|
||||
this.args.app = null;
|
||||
this.args.systemPort = this.args.chromeDriverPort;
|
||||
this.args.proxyPort = this.args.systemPort;
|
||||
this.args.proxyPort = this.args.chromeDriverPort;
|
||||
cb();
|
||||
};
|
||||
|
||||
ChromeAndroid.prototype.start = function (cb, onDie) {
|
||||
this.adb = new ADB(this.args);
|
||||
this.uiautomator = new UiAutomator(this.adb, this.args);
|
||||
this.uiautomator.setExitHandler(this.onUiautomatorExit.bind(this));
|
||||
this.onDie = onDie;
|
||||
|
||||
async.series([
|
||||
this.prepareDevice.bind(this),
|
||||
this.prepareChromedriver.bind(this),
|
||||
this.unlock.bind(this),
|
||||
this.forwardPort.bind(this),
|
||||
this.pushAppium.bind(this),
|
||||
this.uiautomator.start.bind(this.uiautomator),
|
||||
this.getDataDir.bind(this),
|
||||
this.createSession.bind(this)
|
||||
], function (err, results) {
|
||||
if (err) return cb(err);
|
||||
var sessionId = results[3];
|
||||
var sessionId = results[results.length - 1];
|
||||
cb(null, sessionId);
|
||||
});
|
||||
};
|
||||
@@ -105,11 +133,13 @@ ChromeAndroid.prototype.createSession = function (cb) {
|
||||
};
|
||||
|
||||
ChromeAndroid.prototype.stop = function (cb) {
|
||||
this.chromedriver.stop(function (err) {
|
||||
if (err) return cb(err);
|
||||
this.adb.forceStop(this.args.appPackage, function (err) {
|
||||
this.uiautomator.shutdown(function () {
|
||||
this.chromedriver.stop(function (err) {
|
||||
if (err) return cb(err);
|
||||
this.adb.stopLogcat(cb);
|
||||
this.adb.forceStop(this.args.appPackage, function (err) {
|
||||
if (err) return cb(err);
|
||||
this.adb.stopLogcat(cb);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
@@ -124,4 +154,49 @@ ChromeAndroid.prototype.onChromedriverExit = function () {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
// since we're in chrome, our default context is not the native mode, but web
|
||||
ChromeAndroid.prototype.defaultContext = function () {
|
||||
return WEBVIEW_BASE + "1";
|
||||
};
|
||||
|
||||
// write a new getContexts function that hard-codes the two available contexts
|
||||
ChromeAndroid.prototype.getContexts = function (cb) {
|
||||
this.contexts = [NATIVE_WIN, this.defaultContext()];
|
||||
logger.info("Available contexts: " + this.contexts);
|
||||
cb(null, {
|
||||
status: status.codes.Success.code
|
||||
, value: this.contexts
|
||||
});
|
||||
};
|
||||
|
||||
// write a new setContext function that handles starting and stopping of
|
||||
// chrome mode; the default android context controller method won't work here
|
||||
// because here we don't need to worry about starting/stopping chromedriver
|
||||
// itself; it's already on
|
||||
ChromeAndroid.prototype.setContext = function (name, cb) {
|
||||
if (name === null) {
|
||||
name = this.defaultContext();
|
||||
} else if (name === WEBVIEW_WIN) {
|
||||
name = this.defaultContext();
|
||||
}
|
||||
this.getContexts(function () {
|
||||
if (!_.contains(this.contexts, name)) {
|
||||
return cb(null, {
|
||||
status: status.codes.NoSuchContext.code
|
||||
, value: "Context '" + name + "' does not exist"
|
||||
});
|
||||
}
|
||||
if (name === this.curContext) {
|
||||
return jwpSuccess(cb);
|
||||
}
|
||||
if (name.indexOf(WEBVIEW_WIN) !== -1) {
|
||||
this.setChromedriverMode();
|
||||
} else {
|
||||
this.setNativeMode();
|
||||
}
|
||||
this.curContext = name;
|
||||
jwpSuccess(cb);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
module.exports = ChromeAndroid;
|
||||
|
||||
@@ -181,7 +181,7 @@ Chromedriver.prototype.proxyNewSession = function (data, cb) {
|
||||
this.chromeSessionId = null;
|
||||
try {
|
||||
if (body.status === 0 && body.sessionId) {
|
||||
logger.debug("Successfully started chrome session");
|
||||
logger.debug("Successfully started chrome session " + body.sessionId);
|
||||
this.chromeSessionId = body.sessionId;
|
||||
}
|
||||
} catch (ignore) {}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
var desired = require('./desired')
|
||||
, webviewHelper = require("../../../helpers/webview")
|
||||
, loadWebView = webviewHelper.loadWebView
|
||||
, setup = require("../../common/setup-base");
|
||||
|
||||
describe("chrome @android-arm-only", function () {
|
||||
describe('contexts', function () {
|
||||
var driver;
|
||||
setup(this, desired, {'no-reset': true}).then(function (d) { driver = d; });
|
||||
|
||||
before(function (done) {
|
||||
loadWebView(desired, driver).nodeify(done);
|
||||
});
|
||||
|
||||
it('should be able to switch contexts', function (done) {
|
||||
driver
|
||||
.title().should.eventually.include("I am a page title")
|
||||
.contexts().then(function (ctxs) {
|
||||
ctxs.should.contain("NATIVE_APP");
|
||||
return driver.context("NATIVE_APP");
|
||||
})
|
||||
.source().should.eventually.include("android.widget.Button")
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user