mirror of
https://github.com/appium/appium.git
synced 2026-11-12 13:32:01 +08:00
Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
209e378ccf | ||
|
|
9662914c66 | ||
|
|
44e2ed5262 | ||
|
|
8e9cf69fac | ||
|
|
9ee9664f20 | ||
|
|
ec97159c29 | ||
|
|
e7eb407fdd | ||
|
|
6941558bf7 | ||
|
|
db501a5ff6 | ||
|
|
78dcd85935 | ||
|
|
24e8c965f1 | ||
|
|
373379f2e4 | ||
|
|
fd611f7428 | ||
|
|
6ee51a8bd8 | ||
|
|
76adbe365d | ||
|
|
2366944e69 | ||
|
|
f9646dd185 | ||
|
|
ca9109f1bd | ||
|
|
5a9538fb98 | ||
|
|
67affb6d8d | ||
|
|
208be83202 |
Binary file not shown.
+9
-1
@@ -5,6 +5,7 @@ ios_only=false
|
||||
ios6_only=false
|
||||
ios7_only=false
|
||||
ios71_only=false
|
||||
ios8_only=false
|
||||
android_only=false
|
||||
android_chrome=false
|
||||
selendroid_only=false
|
||||
@@ -43,6 +44,9 @@ for arg in "$@"; do
|
||||
elif [ "$arg" = "--ios71" ]; then
|
||||
ios71_only=true
|
||||
all_tests=false
|
||||
elif [ "$arg" = "--ios8" ]; then
|
||||
ios8_only=true
|
||||
all_tests=false
|
||||
elif [ "$arg" = "--no-xcode-switch" ]; then
|
||||
xcode_switch=false
|
||||
elif [ "$arg" = "--real-device" ]; then
|
||||
@@ -84,7 +88,11 @@ if $ios7_only || $all_tests; then
|
||||
fi
|
||||
|
||||
if $ios71_only || $all_tests; then
|
||||
run_ios_tests "7.1" "ios71" "@skip-ios71|@skip-ios7|@skip-ios-all"
|
||||
run_ios_tests "7.1" "ios71" "@skip-ios71|@skip-ios7|@skip-ios-all|@skip-ios7up"
|
||||
fi
|
||||
|
||||
if $ios8_only || $all_tests; then
|
||||
run_ios_tests "8.0" "ios8" "@skip-ios8|@skip-ios-all|@skip-ios7up"
|
||||
fi
|
||||
|
||||
if $did_switch_xcode; then
|
||||
|
||||
@@ -14,6 +14,21 @@ Appium on OS X supports iOS and Android testing.
|
||||
from source, simply run `sudo grunt authorize` to do the same thing. If you
|
||||
are running [Appium.app](https://github.com/appium/appium-dot-app), you can
|
||||
authorize iOS through the GUI.
|
||||
* If you're on Xcode 6, you need to launch each simulator you intend to use
|
||||
with appium in advance, and change the default to actually show the soft
|
||||
keyboard if you want sendKeys to work. You can do this by clicking on any
|
||||
textfield and hitting command-K until you notice the soft keyboard show up.
|
||||
* If you're on Xcode 6, you have a feature in Xcode called Devices
|
||||
(command-shift-2). You need to make sure that whichever deviceName you choose
|
||||
to use with Appium in your capabilities, there is only one of those per sdk
|
||||
version. In other words, if you send in a deviceName cap of "iPhone 5s" and
|
||||
a platformVersion cap of "8.0", you need to make sure that there is exactly
|
||||
one device with the name "iPhone 5s" and the 8.0 sdk in your devices list.
|
||||
Otherwise, Appium won't know which one to use.
|
||||
* In iOS8, devices each have their own setting which enables or disables
|
||||
UIAutomation. It lives in a "Developer" view in the Settings app. You need to
|
||||
verify that UIAutomaion is enabled in this view before the simulator or
|
||||
device can be automated.
|
||||
|
||||
### Testing against multiple iOS SDKs
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ All flags are optional, but some are required in conjunction with certain others
|
||||
|`--chromedriver-port`|9515|Port upon which ChromeDriver will run|`--chromedriver-port 9515`|
|
||||
|`--chromedriver-executable`|null|ChromeDriver executable full path||
|
||||
|`--use-keystore`|false|(Android-only) When set the keystore will be used to sign apks.||
|
||||
|`--keystore-path`|/Users/saucelabs/.android/debug.keystore|(Android-only) Path to keystore||
|
||||
|`--keystore-path`|/Users/user/.android/debug.keystore|(Android-only) Path to keystore||
|
||||
|`--keystore-password`|android|(Android-only) Password to keystore||
|
||||
|`--key-alias`|androiddebugkey|(Android-only) Key alias||
|
||||
|`--key-password`|android|(Android-only) Key password||
|
||||
@@ -75,6 +75,7 @@ All flags are optional, but some are required in conjunction with certain others
|
||||
|`--command-timeout`|60|The default command timeout for the server to use for all sessions. Will still be overridden by newCommandTimeout cap||
|
||||
|`--keep-keychains`|false|(iOS) Whether to keep keychains (Library/Keychains) when reset app between sessions||
|
||||
|`--strict-caps`|false|Cause sessions to fail if desired caps are sent in that Appium does not recognize as valid for the selected device||
|
||||
|`--isolate-sim-device`|false|Xcode 6 has a bug on some platforms where a certain simulator can only be launched without error if all other simulator devices are first deleted. This option causes Appium to delete all devices other than the one being used by Appium. Note that this is a permanent deletion, and you are responsible for using simctl or xcode to manage the categories of devices used with Appium.||
|
||||
|`--tmp`|null|Absolute path to directory Appium can use to manage temporary files, like built-in iOS apps it needs to move around. On *nix/Mac defaults to /tmp, on Windows defaults to C:\Windows\Temp||
|
||||
|`--trace-dir`|null|Absolute path to directory Appium use to save ios instruments traces, defaults to <tmp dir>/appium-instruments||
|
||||
|`--intent-action`|android.intent.action.MAIN|(Android-only) Intent action which will be used to start activity|`--intent-action android.intent.action.MAIN`|
|
||||
|
||||
+3
-4
@@ -17,9 +17,8 @@ var _ = require("underscore")
|
||||
, appiumVer = require('./package.json').version
|
||||
, fs = require('fs')
|
||||
, helpers = require('./lib/helpers')
|
||||
, xcode = require('./lib/devices/ios/xcode.js')
|
||||
, isWindows = helpers.isWindows()
|
||||
, getXcodeFolder = helpers.getXcodeFolder
|
||||
, getXcodeVersion = helpers.getXcodeVersion
|
||||
, MAX_BUFFER_SIZE = 524288
|
||||
, SELENDROID_MAX_BUFFER_SIZE = 4 * MAX_BUFFER_SIZE;
|
||||
|
||||
@@ -254,7 +253,7 @@ var auth_chmodApps = function (grunt, cb) {
|
||||
} else {
|
||||
user = /\/([^\/]+)$/.exec(process.env.HOME)[1];
|
||||
}
|
||||
getXcodeFolder(function (err, xcodeDir) {
|
||||
xcode.getPath(function (err, xcodeDir) {
|
||||
if (err) return cb(err);
|
||||
var glob = path.resolve(xcodeDir, "Platforms/iPhoneSimulator.platform/" +
|
||||
"Developer/SDKs/iPhoneSimulator*.sdk/Applications");
|
||||
@@ -310,7 +309,7 @@ module.exports.build = function (appRoot, cb, sdk, xcconfig) {
|
||||
});
|
||||
};
|
||||
if (typeof sdk === "undefined") {
|
||||
getXcodeVersion(function (err, version) {
|
||||
xcode.getVersion(function (err, version) {
|
||||
if (err) return cb(err);
|
||||
var sdkVersion = version[0] === "5" ? "7.0" : "6.1";
|
||||
sdk = 'iphonesimulator' + sdkVersion;
|
||||
|
||||
@@ -64,12 +64,16 @@ exports.waitForCondition = function (waitMs, condFn, cb, intervalMs) {
|
||||
var endAt = begunAt + waitMs;
|
||||
var spin = function () {
|
||||
condFn(function (condMet) {
|
||||
var now = Date.now();
|
||||
var waited = now - begunAt;
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
if (condMet) {
|
||||
cb.apply(this, args.slice(1));
|
||||
} else if (Date.now() < endAt) {
|
||||
} else if (now < endAt) {
|
||||
logger.debug("Waited for " + waited + "ms so far");
|
||||
setTimeout(spin, intervalMs);
|
||||
} else {
|
||||
logger.debug("Condition unmet after " + waited + "ms. Timing out.");
|
||||
cb.apply(this, args.slice(1));
|
||||
}
|
||||
}.bind(this));
|
||||
@@ -78,6 +82,7 @@ exports.waitForCondition = function (waitMs, condFn, cb, intervalMs) {
|
||||
};
|
||||
|
||||
exports.implicitWaitForCondition = function (condFn, cb) {
|
||||
logger.debug("Waiting up to " + this.implicitWaitMs + "ms for condition");
|
||||
var _condFn = condFn;
|
||||
condFn = function () {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
|
||||
@@ -19,9 +19,7 @@ var uuid = require('uuid-js')
|
||||
, js2xml = require("js2xmlparser2")
|
||||
, xpath = require("xpath")
|
||||
, XMLDom = require("xmldom")
|
||||
, settings = require('./settings.js')
|
||||
, IOSPerfLog = require('./ios-perf-log')
|
||||
, getSimRootsWithVersion = settings.getSimRootsWithVersion
|
||||
, errors = require('../../server/errors.js')
|
||||
, NotImplementedError = errors.NotImplementedError
|
||||
, NotYetImplementedError = errors.NotYetImplementedError;
|
||||
@@ -477,7 +475,7 @@ iOSController.pushFile = function (base64Data, remotePath, cb) {
|
||||
iOSController._getFullPath = function (remotePath, cb) {
|
||||
var fullPath = "";
|
||||
var v = (this.args.platformVersion || this.iOSSDKVersion);
|
||||
var simRoots = getSimRootsWithVersion(v);
|
||||
var simRoots = this.sim.getDirs();
|
||||
if (simRoots.length < 1) {
|
||||
return cb(new Error("Could not find simulator root for SDK version " +
|
||||
v + "; have you launched this sim before?"));
|
||||
@@ -488,7 +486,8 @@ iOSController._getFullPath = function (remotePath, cb) {
|
||||
|
||||
if (simRoots.length > 1) {
|
||||
var filteredSimRoots = simRoots.filter(function (root) {
|
||||
return fs.existsSync(root + "/Applications");
|
||||
return fs.existsSync(root + "/Applications") || // ios7
|
||||
fs.existsSync(root + "/Containers/Data/Application"); // ios8
|
||||
});
|
||||
|
||||
if (filteredSimRoots.length > 0) {
|
||||
@@ -782,6 +781,10 @@ iOSController.clickWebCoords = function (cb) {
|
||||
var xRatio = realDims.w / wvDims.w;
|
||||
var yRatio = realDims.h / wvDims.h;
|
||||
var serviceBarHeight = 20;
|
||||
if (parseFloat(this.args.platformVersion) >= 8) {
|
||||
// ios8 includes the service bar height in the app
|
||||
serviceBarHeight = 0;
|
||||
}
|
||||
coords = {
|
||||
x: wvPos.x + (xRatio * coords.x)
|
||||
, y: wvPos.y + yOffset + (yRatio * coords.y) - serviceBarHeight
|
||||
@@ -1197,12 +1200,13 @@ iOSController.getScreenshot = function (cb) {
|
||||
var guid = uuid.create();
|
||||
var command = ["au.capture('screenshot", guid, "')"].join('');
|
||||
|
||||
var screenshotFolder = "/tmp/appium-instruments/Run 1/";
|
||||
if (!fs.existsSync(screenshotFolder)) {
|
||||
mkdirp.sync(screenshotFolder);
|
||||
var shotFolder = path.resolve(this.args.tmpDir,
|
||||
"appium-instruments/Run 1/");
|
||||
if (!fs.existsSync(shotFolder)) {
|
||||
mkdirp.sync(shotFolder);
|
||||
}
|
||||
|
||||
var shotPath = [screenshotFolder, 'screenshot', guid, ".png"].join("");
|
||||
var shotPath = path.resolve(shotFolder, 'screenshot' + guid + '.png');
|
||||
// Retrying the whole screenshot process for three times.
|
||||
async.retry(3,
|
||||
function (cb) {
|
||||
@@ -1846,8 +1850,6 @@ iOSController.moveTo = function (element, xoffset, yoffset, cb) {
|
||||
x: res.value.x + xoffset
|
||||
, y: res.value.y + yoffset
|
||||
};
|
||||
//console.log("moving mouse to coords:");
|
||||
//console.log(coords);
|
||||
if (this.isWebContext()) {
|
||||
this.curWebCoords = coords;
|
||||
this.useAtomsElement(element, cb, function (atomsElement) {
|
||||
|
||||
@@ -22,6 +22,36 @@ iOSHybrid.closeAlertBeforeTest = function (cb) {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
iOSHybrid.getDebuggerAppKey = function (appDict, bundleId) {
|
||||
var appKey = null;
|
||||
if (parseFloat(this.args.platformVersion) >= 8) {
|
||||
_.each(appDict, function (data, key) {
|
||||
if (data.bundleId === bundleId) {
|
||||
appKey = key;
|
||||
}
|
||||
});
|
||||
// now we need to determine if we should pick a proxy for this instead
|
||||
if (appKey) {
|
||||
_.each(appDict, function (data, key) {
|
||||
if (data.isProxy && data.hostId === appKey) {
|
||||
logger.debug("Found separate bundleId " + data.bundleId + " " +
|
||||
"acting as proxy for " + bundleId + ". Going to use its " +
|
||||
"app ID key of " + key + " instead");
|
||||
appKey = key;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (_.has(appDict, bundleId)) {
|
||||
appKey = bundleId;
|
||||
}
|
||||
}
|
||||
if (appKey === null) {
|
||||
throw new Error("Couldn't get app key from app dict");
|
||||
}
|
||||
return appKey;
|
||||
};
|
||||
|
||||
iOSHybrid.listWebFrames = function (cb, exitCb) {
|
||||
var isDone = false;
|
||||
if (!this.args.bundleId) {
|
||||
@@ -43,7 +73,10 @@ iOSHybrid.listWebFrames = function (cb, exitCb) {
|
||||
if (this.args.udid !== null) {
|
||||
this.remote.pageArrayFromJson(cb);
|
||||
} else {
|
||||
this.remote.selectApp(this.args.bundleId, onDone);
|
||||
if (this.remoteAppKey === null) {
|
||||
return cb(new Error("remote debug app key must be set"));
|
||||
}
|
||||
this.remote.selectApp(this.remoteAppKey, onDone);
|
||||
}
|
||||
} else {
|
||||
if (this.args.udid !== null) {
|
||||
@@ -52,18 +85,22 @@ iOSHybrid.listWebFrames = function (cb, exitCb) {
|
||||
} else {
|
||||
this.remote = rd.init(exitCb);
|
||||
this.remote.connect(function (appDict) {
|
||||
if (!_.has(appDict, this.args.bundleId)) {
|
||||
logger.error("Remote debugger did not list " + this.args.bundleId +
|
||||
" among its available apps");
|
||||
if (_.has(appDict, "com.apple.mobilesafari")) {
|
||||
var appKey;
|
||||
try {
|
||||
appKey = this.getDebuggerAppKey(appDict, this.args.bundleId);
|
||||
} catch (e) {
|
||||
logger.warn("Remote debugger did not list " + this.args.bundleId +
|
||||
" among its available apps");
|
||||
try {
|
||||
appKey = this.getDebuggerAppKey(appDict, "com.apple.mobilesafari");
|
||||
logger.debug("Using mobile safari instead");
|
||||
this.remote.selectApp("com.apple.mobilesafari", onDone);
|
||||
} else {
|
||||
onDone([]);
|
||||
} catch (e) {
|
||||
return onDone([]);
|
||||
}
|
||||
} else {
|
||||
this.remote.selectApp(this.args.bundleId, onDone);
|
||||
}
|
||||
logger.debug("Using remote debugger app key: " + appKey);
|
||||
this.remoteAppKey = appKey;
|
||||
this.remote.selectApp(appKey, onDone);
|
||||
}.bind(this), this.onPageChange.bind(this));
|
||||
var loopCloseRuns = 0;
|
||||
var loopClose = function () {
|
||||
@@ -174,6 +211,7 @@ iOSHybrid.stopRemote = function (closeWindowBeforeDisconnecting) {
|
||||
this.remote.disconnect();
|
||||
}
|
||||
this.curContext = null;
|
||||
this.remoteAppKey = null;
|
||||
this.curWebFrames = [];
|
||||
this.curWebCoords = null;
|
||||
this.remote = null;
|
||||
|
||||
@@ -11,8 +11,11 @@ var spawn = require('win-spawn')
|
||||
// Date-Utils: Polyfills for the Date object
|
||||
require('date-utils');
|
||||
|
||||
var START_TIMEOUT = 10000;
|
||||
|
||||
var IosLog = function (opts) {
|
||||
this.udid = opts.udid;
|
||||
this.simUdid = opts.simUdid;
|
||||
this.xcodeVersion = opts.xcodeVersion;
|
||||
this.showLogs = opts.showLogs;
|
||||
this.proc = null;
|
||||
@@ -24,6 +27,7 @@ var IosLog = function (opts) {
|
||||
this.logs = [];
|
||||
this.logRow = "";
|
||||
this.logsSinceLastRequest = [];
|
||||
this.startTimer = null;
|
||||
|
||||
if (this.xcodeVersion === null) {
|
||||
logger.warn("Xcode version passed into log capture code as null, assuming Xcode 5");
|
||||
@@ -48,13 +52,25 @@ IosLog.prototype.startCapture = function (cb) {
|
||||
this.proc = spawn("deviceconsole", ["-u", this.udid], {env: spawnEnv});
|
||||
this.finishStartingLogCapture(cb);
|
||||
} else {
|
||||
if (parseInt(this.xcodeVersion.split(".")[0], 10) >= 5) {
|
||||
logger.debug("Starting iOS 7.* simulator log capture");
|
||||
var sim7LogsPath = path.resolve(process.env.HOME, "Library", "Logs", "iOS Simulator");
|
||||
glob(sim7LogsPath + "/7.*/system.log", function (err, files) {
|
||||
var ver = parseInt(this.xcodeVersion.split(".")[0], 10);
|
||||
if (ver >= 5) {
|
||||
var logsPath;
|
||||
if (ver >= 6) {
|
||||
logger.debug("Starting iOS 8.* simulator log capture");
|
||||
if (_.isUndefined(this.simUdid)) {
|
||||
return cb(new Error("iOS8 log capture requires a sim udid"));
|
||||
}
|
||||
logsPath = path.resolve(process.env.HOME, "Library", "Logs",
|
||||
"CoreSimulator", this.simUdid);
|
||||
} else {
|
||||
logger.debug("Starting iOS 7.* simulator log capture");
|
||||
logsPath = path.resolve(process.env.HOME, "Library", "Logs",
|
||||
"iOS Simulator", "7.*");
|
||||
}
|
||||
glob(path.resolve(logsPath, "system.log"), function (err, files) {
|
||||
if (err || files.length < 1) {
|
||||
logger.error("Could not start log capture because no iOS 7 " +
|
||||
"simulator logs could be found at " + sim7LogsPath + "/7.*. " +
|
||||
logger.error("Could not start log capture because no iOS " +
|
||||
"simulator logs could be found at " + logsPath + "/system.log" +
|
||||
"Logging will not be functional for this run");
|
||||
return cb();
|
||||
} else {
|
||||
@@ -82,9 +98,18 @@ IosLog.prototype.startCapture = function (cb) {
|
||||
};
|
||||
|
||||
IosLog.prototype.finishStartingLogCapture = function (cb) {
|
||||
this.startTimer = setTimeout(function () {
|
||||
var msg = "Log capture did not start in a reasonable amount of time";
|
||||
logger.error(msg);
|
||||
if (!this.calledBack) {
|
||||
this.calledBack = true;
|
||||
cb(new Error(msg));
|
||||
}
|
||||
}, START_TIMEOUT);
|
||||
this.proc.stdout.setEncoding('utf8');
|
||||
this.proc.stderr.setEncoding('utf8');
|
||||
this.proc.on('error', function (err) {
|
||||
clearTimeout(this.startTimer);
|
||||
logger.error("iOS log capture failed: " + err.message);
|
||||
if (!this.calledBack) {
|
||||
this.calledBack = true;
|
||||
@@ -104,6 +129,7 @@ IosLog.prototype.stopCapture = function () {
|
||||
};
|
||||
|
||||
IosLog.prototype.onStdout = function (data) {
|
||||
clearTimeout(this.startTimer);
|
||||
if (!this.calledBack) {
|
||||
// don't store the first line of the log because it came before the sim or device was launched
|
||||
this.onOutput(data);
|
||||
@@ -117,6 +143,7 @@ IosLog.prototype.onStdout = function (data) {
|
||||
};
|
||||
|
||||
IosLog.prototype.onStderr = function (data) {
|
||||
clearTimeout(this.startTimer);
|
||||
if (/execvp\(\)/.test(data)) {
|
||||
logger.error("iOS log capture process failed to start");
|
||||
if (!this.calledBack) {
|
||||
|
||||
+426
-391
File diff suppressed because it is too large
Load Diff
@@ -59,6 +59,9 @@ RemoteDebugger.prototype.init = function (debuggerType, onDisconnect) {
|
||||
, error: function (msg) {
|
||||
appLogger.error("[REMOTE] " + msg);
|
||||
}
|
||||
, warn: function (msg) {
|
||||
appLogger.warn("[REMOTE] " + msg);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
@@ -106,8 +109,14 @@ RemoteDebugger.prototype.setConnectionKey = function (cb) {
|
||||
}.bind(this), function (appDict) {
|
||||
var newDict = {};
|
||||
_.each(appDict, function (dict) {
|
||||
newDict[dict.WIRApplicationIdentifierKey] = dict.WIRApplicationNameKey;
|
||||
});
|
||||
var idKey = dict.WIRApplicationIdentifierKey;
|
||||
newDict[idKey] = {
|
||||
name: dict.WIRApplicationNameKey,
|
||||
bundleId: dict.WIRApplicationBundleIdentifierKey,
|
||||
isProxy: dict.WIRIsApplicationProxyKey,
|
||||
hostId: dict.WIRHostApplicationIdentifierKey
|
||||
};
|
||||
}.bind(this));
|
||||
cb(newDict);
|
||||
});
|
||||
};
|
||||
@@ -117,7 +126,9 @@ RemoteDebugger.prototype.selectApp = function (appIdKey, cb) {
|
||||
this.appIdKey = appIdKey;
|
||||
var connectToApp = messages.connectToApp(this.connId, this.appIdKey);
|
||||
this.logger.debug("Selecting app");
|
||||
this.send(connectToApp, function (pageDict) {
|
||||
this.send(connectToApp, function (appIdKey, pageDict) {
|
||||
// appIdKey comes in but we trust that it's the same here, otherwise
|
||||
// we'll stall out and not call cb
|
||||
cb(this.pageArrayFromDict(pageDict));
|
||||
this.specialCbs['_rpc_forwardGetListing:'] = this.onPageChange.bind(this);
|
||||
}.bind(this));
|
||||
@@ -184,7 +195,12 @@ RemoteDebugger.prototype.checkPageIsReady = function (cb) {
|
||||
}.bind(this), true);
|
||||
};
|
||||
|
||||
RemoteDebugger.prototype.onPageChange = function (pageDict) {
|
||||
RemoteDebugger.prototype.onPageChange = function (appIdKey, pageDict) {
|
||||
if (this.appIdKey !== appIdKey) {
|
||||
this.logger.debug("New page listing did not match the app id we " +
|
||||
"are currently using, ignoring");
|
||||
return;
|
||||
}
|
||||
this.pageChangeCb(this.pageArrayFromDict(pageDict));
|
||||
};
|
||||
|
||||
@@ -444,8 +460,15 @@ RemoteDebugger.prototype.setHandlers = function () {
|
||||
}.bind(this),
|
||||
'_rpc_applicationSentListing:': function (plist) {
|
||||
this.handleSpecialMessage('_rpc_forwardGetListing:',
|
||||
plist.__argument.WIRApplicationIdentifierKey,
|
||||
plist.__argument.WIRListingKey);
|
||||
}.bind(this),
|
||||
'_rpc_applicationConnected:': function (plist) {
|
||||
this.logger.info("We were notified that we connected to possibly " +
|
||||
"the wrong application. Ignoring for now and " +
|
||||
"hoping we're going to retry looking for apps");
|
||||
this.logger.debug(JSON.stringify(plist.__argument));
|
||||
}.bind(this),
|
||||
'_rpc_applicationSentData:': function (plist) {
|
||||
var dataKey = JSON.parse(plist.__argument.WIRMessageDataKey.toString('utf8'))
|
||||
, msgId = dataKey.id
|
||||
@@ -457,7 +480,6 @@ RemoteDebugger.prototype.setHandlers = function () {
|
||||
if (dataKey.method === "Profiler.resetProfiles") {
|
||||
this.logger.debug("Device is telling us to reset profiles. Should probably " +
|
||||
"do some kind of callback here");
|
||||
//me.onPageChange();
|
||||
} else if (dataKey.method === "Page.frameNavigated") {
|
||||
if (!this.willNavigateWithoutReload && !this.pageLoading) {
|
||||
this.logger.debug("Frame navigated, unloading page");
|
||||
|
||||
+44
-44
@@ -3,13 +3,10 @@
|
||||
var IOS = require('./ios.js')
|
||||
, logger = require('../../server/logger.js').get('appium')
|
||||
, path = require('path')
|
||||
, helpers = require('../../helpers.js')
|
||||
, cleanSafari = helpers.cleanSafari
|
||||
, checkSafari = helpers.checkSafari
|
||||
, getiOSSDKVersion = helpers.getiOSSDKVersion
|
||||
, _ = require('underscore');
|
||||
|
||||
var NATIVE_REAL_SAFARI_MIN_VER = 7.0;
|
||||
var NATIVE_REAL_SAFARI_MIN_VER = 7.0
|
||||
, SAFARI_BUNDLE = 'com.apple.mobilesafari';
|
||||
|
||||
var Safari = function () {
|
||||
this.init();
|
||||
@@ -29,49 +26,35 @@ Safari.prototype.configure = function (args, caps, cb) {
|
||||
"../../../build/SafariLauncher/SafariLauncher.zip");
|
||||
this.configureLocalApp(cb);
|
||||
} else {
|
||||
this.configureSafari(cb);
|
||||
if (parseFloat(this.args.platformVersion) >= 8) {
|
||||
logger.debug("We're on iOS8+ so not copying mobile safari app");
|
||||
this.args.bundleId = SAFARI_BUNDLE;
|
||||
this.args.app = null;
|
||||
} else {
|
||||
// make sure args.app has something in it so we get to the right spots
|
||||
// in moveBuiltInApp()
|
||||
this.args.app = "safari";
|
||||
}
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
Safari.prototype.configureSafari = function (cb) {
|
||||
var safariVer = null;
|
||||
if (typeof this.args.platformVersion !== "undefined" &&
|
||||
this.args.platformVersion) {
|
||||
safariVer = this.args.platformVersion;
|
||||
}
|
||||
logger.debug("Trying to use mobile safari, version " + safariVer);
|
||||
var checkNext = function (attemptedApp, origApp, safariVer) {
|
||||
logger.debug("Using mobile safari app at " + attemptedApp);
|
||||
this.args.app = attemptedApp;
|
||||
logger.debug("Cleaning mobile safari data files");
|
||||
cleanSafari(safariVer, function (err) {
|
||||
Safari.prototype.moveBuiltInApp = function (cb) {
|
||||
if (this.args.app !== null) {
|
||||
logger.debug("Trying to use mobile safari, version " +
|
||||
this.args.platformVersion);
|
||||
this.sim.prepareSafari(this.args.tmpDir, function (err, attemptedApp, origApp) {
|
||||
if (err) {
|
||||
logger.error(err.message);
|
||||
cb(err);
|
||||
} else {
|
||||
this.args.origAppPath = origApp;
|
||||
cb(null);
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this);
|
||||
var sdkNext = function (safariVer) {
|
||||
checkSafari(safariVer, this.args.tmpDir, function (err, attemptedApp, origApp) {
|
||||
if (err) {
|
||||
logger.error("Could not prepare mobile safari with version '" +
|
||||
safariVer + "': " + err);
|
||||
logger.error("Could not prepare mobile safari: " + err);
|
||||
return cb(err);
|
||||
}
|
||||
checkNext(attemptedApp, origApp, safariVer);
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
if (safariVer === null) {
|
||||
getiOSSDKVersion(function (err, safariVer) {
|
||||
if (err) return cb(err);
|
||||
sdkNext(safariVer);
|
||||
});
|
||||
logger.debug("Using mobile safari app at " + attemptedApp);
|
||||
this.args.app = attemptedApp;
|
||||
this.args.origAppPath = origApp;
|
||||
cb();
|
||||
}.bind(this));
|
||||
} else {
|
||||
sdkNext(safariVer);
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -106,7 +89,7 @@ Safari.prototype.click = function (elementId, cb) {
|
||||
};
|
||||
|
||||
Safari.prototype.setBundleId = function (cb) {
|
||||
this.args.bundleId = "com.apple.mobilesafari";
|
||||
this.args.bundleId = SAFARI_BUNDLE;
|
||||
cb();
|
||||
};
|
||||
|
||||
@@ -114,7 +97,7 @@ Safari.prototype._setInitialOrientation = IOS.prototype.setInitialOrientation;
|
||||
Safari.prototype.setInitialOrientation = function (cb) {
|
||||
if (this.shouldIgnoreInstrumentsExit()) {
|
||||
logger.debug("Not setting initial orientation because we're on " +
|
||||
"SafariLauncher");
|
||||
"SafariLauncher");
|
||||
return cb();
|
||||
}
|
||||
this._setInitialOrientation(cb);
|
||||
@@ -124,7 +107,7 @@ Safari.prototype._configureBootstrap = IOS.prototype.configureBootstrap;
|
||||
Safari.prototype.configureBootstrap = function (cb) {
|
||||
if (this.shouldIgnoreInstrumentsExit()) {
|
||||
logger.debug("Not setting bootstrap config because we're on " +
|
||||
"SafariLauncher");
|
||||
"SafariLauncher");
|
||||
return cb();
|
||||
}
|
||||
this._configureBootstrap(cb);
|
||||
@@ -145,6 +128,23 @@ Safari.prototype.installToRealDevice = function (cb) {
|
||||
}
|
||||
};
|
||||
|
||||
Safari.prototype.clearAppData = function (cb) {
|
||||
if (this.args.fullReset) {
|
||||
// Even though we delete typical apps on a regular reset, we do a good
|
||||
// job of getting safari back to its original state, so actually deleting
|
||||
// it is overkill in most cases, and requires an instantLaunchAndQuit.
|
||||
// So we only delete it if the user requests a full reset
|
||||
try {
|
||||
this.sim.deleteSafari();
|
||||
} catch (e) {
|
||||
return cb(e);
|
||||
}
|
||||
cb();
|
||||
} else {
|
||||
this.sim.cleanSafari(this.keepAppToRetainPrefs, cb);
|
||||
}
|
||||
};
|
||||
|
||||
Safari.prototype._stopRemote = IOS.prototype.stopRemote;
|
||||
Safari.prototype.stopRemote = function () {
|
||||
this._stopRemote(true);
|
||||
|
||||
+38
-129
@@ -4,10 +4,10 @@ var logger = require('../../server/logger.js').get('appium')
|
||||
, _ = require('underscore')
|
||||
, fs = require('fs')
|
||||
, path = require('path')
|
||||
, xmlplist = require('plist')
|
||||
, bplistCreate = require('bplist-creator')
|
||||
, mkdirp = require('mkdirp')
|
||||
, bplistParse = require('bplist-parser');
|
||||
, Simulator = require('./simulator.js')
|
||||
, multiResolve = require('../../helpers.js').multiResolve;
|
||||
|
||||
var settings = {};
|
||||
var plists = {
|
||||
@@ -26,13 +26,17 @@ var prefs = {
|
||||
mobileSafari: {
|
||||
OpenLinksInBackground: [0, 1],
|
||||
WebKitJavaScriptCanOpenWindowsAutomatically: [true, false],
|
||||
JavaScriptCanOpenWindowsAutomatically: [true, false],
|
||||
SearchEngineStringSetting: ['Google', 'Yahoo!', 'Bing'],
|
||||
SafariDoNotTrackEnabled: [true, false],
|
||||
SuppressSearchSuggestions: [true, false],
|
||||
SpotlightSuggestionsEnabled: [true, false],
|
||||
SpeculativeLoading: [true, false],
|
||||
WarnAboutFraudulentWebsites: [true, false],
|
||||
ReadingListCellularFetchingEnabled: [true, false],
|
||||
WebKitJavaScriptEnabled: [true, false]
|
||||
WebKitJavaScriptEnabled: [true, false],
|
||||
JavaScriptEnabled: [true, false],
|
||||
DisableWebsiteSpecificSearch: [true, false]
|
||||
},
|
||||
webFoundation: {
|
||||
NSHTTPAcceptCookies: ['never', 'always', 'current page']
|
||||
@@ -54,99 +58,36 @@ var prefs = {
|
||||
}
|
||||
};
|
||||
|
||||
var multiResolve = function (roots) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
var paths = [];
|
||||
_.each(roots, function (root) {
|
||||
var resolveArgs = [root].concat(args);
|
||||
paths.push(path.resolve.apply(null, resolveArgs));
|
||||
});
|
||||
return paths;
|
||||
};
|
||||
|
||||
var getPlistPaths = function (plist, sdk) {
|
||||
var getPlistPaths = function (plist, sim) {
|
||||
var files;
|
||||
var file = plists[plist];
|
||||
var bases = getPrefsDirs(sdk);
|
||||
if (plist === 'mobileSafari' && parseFloat(sdk) >= 7) {
|
||||
bases = getSafari7Dirs(sdk);
|
||||
var bases = getPrefsDirs(sim);
|
||||
if (plist === 'mobileSafari' && parseFloat(sim.platformVer) >= 7) {
|
||||
bases = multiResolve(sim.getSafariDirs(), "Library", "Preferences");
|
||||
} else if (plist === 'locationClients') {
|
||||
bases = multiResolve(getSimDirs(sdk), "Library", "Caches", "locationd");
|
||||
bases = multiResolve(sim.getDirs(), "Library", "Caches", "locationd");
|
||||
} else if (plist === 'locationCache') {
|
||||
var bases2 = multiResolve(getSimDirs(sdk), "Library", "Caches", "locationd");
|
||||
var bases2 = multiResolve(sim.getDirs(), "Library", "Caches", "locationd");
|
||||
files = multiResolve(bases, file);
|
||||
files = files.concat(multiResolve(bases2, file));
|
||||
return files;
|
||||
} else if (plist === 'userSettings') {
|
||||
files = multiResolve(getSimDirs(sdk), "Library", "ConfigurationProfiles", file);
|
||||
files = files.concat(multiResolve(getSimDirs(sdk), "Library", "ConfigurationProfiles",
|
||||
"PublicInfo", 'EffectiveUserSettings.plist'));
|
||||
files = multiResolve(sim.getDirs(), "Library", "ConfigurationProfiles",
|
||||
file);
|
||||
files = files.concat(multiResolve(sim.getDirs(), "Library",
|
||||
"ConfigurationProfiles", "PublicInfo",
|
||||
"EffectiveUserSettings.plist"));
|
||||
files = files.concat(multiResolve(sim.getDirs(), "Library",
|
||||
"ConfigurationProfiles", "PublicInfo",
|
||||
"PublicEffectiveUserSettings.plist"));
|
||||
return files;
|
||||
}
|
||||
|
||||
return multiResolve(bases, file);
|
||||
};
|
||||
|
||||
settings.getSimRoot = function () {
|
||||
var u = process.env.USER;
|
||||
return path.resolve("/Users", u, "Library", "Application Support",
|
||||
"iPhone Simulator");
|
||||
};
|
||||
|
||||
settings.getSimRootsWithVersion = function (sdk) {
|
||||
sdk = sdk.toString();
|
||||
var base = settings.getSimRoot();
|
||||
var list = [];
|
||||
try {
|
||||
list = fs.readdirSync(base);
|
||||
} catch (e) {
|
||||
}
|
||||
var dirs = [];
|
||||
_.each(list, function (sdkDir) {
|
||||
if (sdkDir.indexOf(sdk) !== -1) {
|
||||
dirs.push(path.resolve(base, sdkDir));
|
||||
}
|
||||
});
|
||||
return dirs;
|
||||
};
|
||||
|
||||
var getSimDirs = settings.getSimRootsWithVersion;
|
||||
|
||||
var getPrefsDirs = function (sdk) {
|
||||
return multiResolve(getSimDirs(sdk), "Library", "Preferences");
|
||||
};
|
||||
|
||||
var getSafari7Dirs = function (sdk) {
|
||||
var appsDirs = multiResolve(getSimDirs(sdk), "Applications");
|
||||
var safariDirs = [];
|
||||
_.each(appsDirs, function (appsDir) {
|
||||
var list;
|
||||
try {
|
||||
list = fs.readdirSync(appsDir);
|
||||
} catch (e) {
|
||||
if (/ENOENT/.test(e.message)) {
|
||||
logger.warn("Applications directory " + appsDir + " doesn't exist. " +
|
||||
"Have you run this simulator before?");
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
var safariDir = null;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (fs.existsSync(path.resolve(appsDir, list[i], "MobileSafari.app")) ||
|
||||
fs.existsSync(path.resolve(appsDir, list[i], "Appium-MobileSafari.app"))) {
|
||||
safariDir = path.resolve(appsDir, list[i], "Library", "Preferences");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (safariDir) {
|
||||
safariDirs.push(safariDir);
|
||||
} else {
|
||||
logger.warn("Could not find MobileSafari in sim applications at " +
|
||||
appsDir);
|
||||
}
|
||||
});
|
||||
return safariDirs;
|
||||
var getPrefsDirs = function (sim) {
|
||||
return multiResolve(sim.getDirs(), "Library", "Preferences");
|
||||
};
|
||||
|
||||
var checkValidSettings = function (forPlist, prefSet) {
|
||||
@@ -206,11 +147,11 @@ settings.writeSettings = function (forPlist, prefSetPerFile, bypassCheck,
|
||||
}
|
||||
};
|
||||
|
||||
settings.updateSettings = function (sdk, forPlist, prefSet) {
|
||||
settings.updateSettings = function (sim, forPlist, prefSet) {
|
||||
logger.debug("Updating settings for " + forPlist);
|
||||
checkValidSettings(forPlist, prefSet);
|
||||
var prefSetPerFile = {};
|
||||
var curSettings = settings.getSettings(sdk, forPlist);
|
||||
var curSettings = settings.getSettings(sim, forPlist);
|
||||
_.each(curSettings, function (settingSet, file) {
|
||||
_.each(prefSet, function (prefValue, prefName) {
|
||||
settingSet[prefName] = prefValue;
|
||||
@@ -220,7 +161,7 @@ settings.updateSettings = function (sdk, forPlist, prefSet) {
|
||||
settings.writeSettings(forPlist, prefSetPerFile, true);
|
||||
};
|
||||
|
||||
settings.updateLocationSettings = function (sdk, bundleId, authorized) {
|
||||
settings.updateLocationSettings = function (sim, bundleId, authorized) {
|
||||
var weirdLocKey = "com.apple.locationd.bundle-/System/Library/" +
|
||||
"PrivateFrameworks/AOSNotification.framework";
|
||||
var newPrefs = {
|
||||
@@ -234,11 +175,11 @@ settings.updateLocationSettings = function (sdk, bundleId, authorized) {
|
||||
};
|
||||
var prefSetPerFile = {};
|
||||
var cachePrefSetPerFile = {};
|
||||
var curCacheSettings = settings.getSettings(sdk, 'locationCache');
|
||||
var curCacheSettings = settings.getSettings(sim, 'locationCache');
|
||||
_.each(curCacheSettings, function (settingSet, file) {
|
||||
cachePrefSetPerFile[file] = _.extend(_.clone(newCachePrefs), settingSet);
|
||||
});
|
||||
var curSettings = settings.getSettings(sdk, 'locationClients');
|
||||
var curSettings = settings.getSettings(sim, 'locationClients');
|
||||
_.each(curSettings, function (settingSet, file) {
|
||||
// add this random data to the clients.plist since it always seems to be there
|
||||
if (!_.has(settingSet, weirdLocKey)) {
|
||||
@@ -266,12 +207,12 @@ settings.updateLocationSettings = function (sdk, bundleId, authorized) {
|
||||
settings.writeSettings('locationCache', cachePrefSetPerFile, true);
|
||||
};
|
||||
|
||||
settings.updateSafariSettings = function (sdk, settingSet) {
|
||||
settings.updateSafariUserSettings(sdk, settingSet);
|
||||
settings.updateSettings(sdk, 'mobileSafari', settingSet);
|
||||
settings.updateSafariSettings = function (sim, settingSet) {
|
||||
settings.updateSafariUserSettings(sim, settingSet);
|
||||
settings.updateSettings(sim, 'mobileSafari', settingSet);
|
||||
};
|
||||
|
||||
settings.updateSafariUserSettings = function (sdk, settingSet) {
|
||||
settings.updateSafariUserSettings = function (sim, settingSet) {
|
||||
// add extra stuff to UserSettings.plist and EffectiveUserSettings.plist
|
||||
var newUserSettings = {};
|
||||
if (_.has(settings, 'WebKitJavaScriptEnabled')) {
|
||||
@@ -286,7 +227,7 @@ settings.updateSafariUserSettings = function (sdk, settingSet) {
|
||||
if (_.size(newUserSettings) > 0) {
|
||||
logger.debug("Updating UserSettings.plist and friends");
|
||||
var userSettingsPerFile = {};
|
||||
var curUserSettings = settings.getSettings(sdk, 'userSettings');
|
||||
var curUserSettings = settings.getSettings(sim, 'userSettings');
|
||||
_.each(curUserSettings, function (settingSet, file) {
|
||||
_.extend(settingSet.restrictedBool, newUserSettings);
|
||||
userSettingsPerFile[file] = settingSet;
|
||||
@@ -295,33 +236,13 @@ settings.updateSafariUserSettings = function (sdk, settingSet) {
|
||||
}
|
||||
};
|
||||
|
||||
var getPlistData = function (file) {
|
||||
var data;
|
||||
if (fs.existsSync(file)) {
|
||||
var fileData = fs.readFileSync(file);
|
||||
try {
|
||||
data = bplistParse.parseBuffer(fileData)[0];
|
||||
} catch (err) {
|
||||
if (err.message.indexOf("Invalid binary plist") !== -1) {
|
||||
logger.debug("Plist was not binary format, retrying with xml");
|
||||
data = xmlplist(file)[0];
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error("Settings file " + file + " did not exist");
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
settings.getSettings = function (sdk, forPlist) {
|
||||
var files = getPlistPaths(forPlist, sdk);
|
||||
settings.getSettings = function (sim, forPlist) {
|
||||
var files = getPlistPaths(forPlist, sim);
|
||||
var bplists = {};
|
||||
_.each(files, function (file) {
|
||||
logger.debug("Getting current settings for " + forPlist + " from " + file);
|
||||
try {
|
||||
bplists[file] = getPlistData(file);
|
||||
bplists[file] = Simulator.getPlistData(file);
|
||||
} catch (err) {
|
||||
bplists[file] = {};
|
||||
logger.warn(err.message);
|
||||
@@ -330,20 +251,8 @@ settings.getSettings = function (sdk, forPlist) {
|
||||
return bplists;
|
||||
};
|
||||
|
||||
settings.simDirsExist = function (sdk) {
|
||||
return getSimDirs(sdk).length > 0;
|
||||
};
|
||||
|
||||
settings.safari7DirsExist = function (sdk) {
|
||||
try {
|
||||
return getSafari7Dirs(sdk).length > 0;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
settings.locServicesDirsExist = function (sdk) {
|
||||
return getPlistPaths('locationClients', sdk).length > 0;
|
||||
settings.locServicesDirsExist = function (sim) {
|
||||
return getPlistPaths('locationClients', sim).length > 0;
|
||||
};
|
||||
|
||||
module.exports = settings;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
"use strict";
|
||||
|
||||
var logger = require('../../server/logger.js').get('appium')
|
||||
, _ = require('underscore')
|
||||
, exec = require('child_process').exec;
|
||||
|
||||
var Simctl = function (opts) {
|
||||
var requiredOpts = [];
|
||||
_.each(requiredOpts, function (opt) {
|
||||
if (!_.has(opts, opt)) {
|
||||
throw new Error(opt + " is required");
|
||||
}
|
||||
this[opt] = opts[opt];
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Simctl.exec = function (cmd, args, cb) {
|
||||
if (typeof args === "function") {
|
||||
cb = args;
|
||||
args = [];
|
||||
}
|
||||
args = _.map(args, function (arg) {
|
||||
if (args.indexOf(" ") !== -1) {
|
||||
return '"' + arg + '"';
|
||||
}
|
||||
return arg;
|
||||
});
|
||||
cmd = "xcrun simctl " + cmd + " " + args.join(' ');
|
||||
logger.debug("Executing: " + cmd);
|
||||
exec(cmd, cb);
|
||||
};
|
||||
|
||||
Simctl.delete = function (udid, cb) {
|
||||
Simctl.exec("delete", [udid], cb);
|
||||
};
|
||||
|
||||
Simctl.getDevices = function (forSdk, cb) {
|
||||
if (typeof forSdk === "function") {
|
||||
cb = forSdk;
|
||||
forSdk = null;
|
||||
}
|
||||
Simctl.exec("list", ["devices"], function (err, stdout) {
|
||||
if (err) return cb(err);
|
||||
var deviceSecRe = /-- iOS (.+) --(\n .+)*/mg;
|
||||
var matches = [];
|
||||
var devices = {};
|
||||
var match = deviceSecRe.exec(stdout);
|
||||
while (match !== null) {
|
||||
matches.push(match);
|
||||
match = deviceSecRe.exec(stdout);
|
||||
}
|
||||
if (matches.length < 1) {
|
||||
return cb(new Error("Could not find device section"));
|
||||
}
|
||||
_.each(matches, function (match) {
|
||||
var sdk = match[1];
|
||||
devices[sdk] = [];
|
||||
_.each(match[0].split("\n").slice(1), function (line) {
|
||||
var lineRe = /^ (.+) \((.+)\) \((.+)\)/;
|
||||
var match = lineRe.exec(line);
|
||||
if (match === null) {
|
||||
throw new Error("Couldn't match line");
|
||||
}
|
||||
var device = {};
|
||||
device.name = match[1];
|
||||
device.udid = match[2];
|
||||
device.state = match[3];
|
||||
devices[sdk].push(device);
|
||||
});
|
||||
});
|
||||
if (forSdk) {
|
||||
if (!_.has(devices, forSdk)) {
|
||||
cb(new Error("Sdk " + forSdk + " was not in list of simctl sdks"));
|
||||
} else {
|
||||
cb(null, devices[forSdk]);
|
||||
}
|
||||
} else {
|
||||
cb(null, devices);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Simctl;
|
||||
@@ -0,0 +1,490 @@
|
||||
"use strict";
|
||||
|
||||
var logger = require('../../server/logger.js').get('appium')
|
||||
, _ = require('underscore')
|
||||
, fs = require('fs')
|
||||
, async = require('async')
|
||||
, exec = require('child_process').exec
|
||||
, path = require('path')
|
||||
, ncp = require('ncp')
|
||||
, xcode = require('./xcode.js')
|
||||
, Simctl = require('./simctl.js')
|
||||
, multiResolve = require('../../helpers.js').multiResolve
|
||||
, rimraf = require('rimraf')
|
||||
, xmlplist = require('plist')
|
||||
, bplistCreate = require('bplist-creator')
|
||||
, bplistParse = require('bplist-parser');
|
||||
|
||||
var Simulator = function (opts) {
|
||||
var requiredOpts = ['sdkVer', 'platformVer', 'udid'];
|
||||
_.each(requiredOpts, function (opt) {
|
||||
if (!_.has(opts, opt)) {
|
||||
throw new Error(opt + " is required");
|
||||
}
|
||||
this[opt] = opts[opt];
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
var wrapInArray = function (res) {
|
||||
if (res) {
|
||||
return [res];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
var rmrf = function (delPath, cb) {
|
||||
exec("rm -rf " + delPath, function (err) {
|
||||
cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
var safeRimRafSync = function (delPath, tries) {
|
||||
if (_.isUndefined(tries)) tries = 0;
|
||||
try {
|
||||
rimraf.sync(delPath);
|
||||
} catch (e) {
|
||||
if (e.message.indexOf("ENOTEMPTY") !== -1 && tries < 20) {
|
||||
logger.debug("Path " + delPath + " was not empty during delete; retrying");
|
||||
safeRimRafSync(delPath, tries + 1);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Simulator.prototype.getRootDir = function () {
|
||||
var u = process.env.USER;
|
||||
if (parseFloat(this.sdkVer) >= 8) {
|
||||
return path.resolve("/Users", u, "Library", "Developer",
|
||||
"CoreSimulator", "Devices");
|
||||
}
|
||||
|
||||
return path.resolve("/Users", u, "Library", "Application Support",
|
||||
"iPhone Simulator");
|
||||
};
|
||||
|
||||
Simulator.prototype.getDirs = function () {
|
||||
var base;
|
||||
if (parseFloat(this.sdkVer) >= 8) {
|
||||
base = path.resolve(this.getRootDir(), this.udid, "data");
|
||||
if (fs.existsSync(base)) {
|
||||
return [base];
|
||||
}
|
||||
return [];
|
||||
} else {
|
||||
var sdk = this.sdkVer.toString();
|
||||
base = this.getRootDir();
|
||||
var list = [];
|
||||
try {
|
||||
list = fs.readdirSync(base);
|
||||
} catch (e) {
|
||||
}
|
||||
var dirs = [];
|
||||
_.each(list, function (sdkDir) {
|
||||
if (sdkDir.indexOf(sdk) !== -1) {
|
||||
dirs.push(path.resolve(base, sdkDir));
|
||||
}
|
||||
});
|
||||
return dirs;
|
||||
}
|
||||
};
|
||||
|
||||
Simulator.getPlistData = function (file) {
|
||||
var data;
|
||||
if (fs.existsSync(file)) {
|
||||
var fileData = fs.readFileSync(file);
|
||||
try {
|
||||
data = bplistParse.parseBuffer(fileData)[0];
|
||||
} catch (err) {
|
||||
if (err.message.indexOf("Invalid binary plist") !== -1) {
|
||||
logger.debug("Plist was not binary format, retrying with xml");
|
||||
data = xmlplist(file)[0];
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error("Settings file " + file + " did not exist");
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
var findAppByCondition = function (dir, condition) {
|
||||
var list;
|
||||
try {
|
||||
list = fs.readdirSync(dir);
|
||||
} catch (e) {
|
||||
if (/ENOENT/.test(e.message)) {
|
||||
logger.warn("Applications directory " + dir + " doesn't exist. " +
|
||||
"Have you run this simulator before?");
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
var appDir = null;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (condition(list[i])) {
|
||||
appDir = path.resolve(dir, list[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return appDir;
|
||||
};
|
||||
|
||||
Simulator.prototype.getSafariDirs = function () {
|
||||
if (parseFloat(this.platformVer) >= 8) {
|
||||
return wrapInArray(this.getSafari8Dir());
|
||||
} else {
|
||||
return this.getSafari7Dirs();
|
||||
}
|
||||
};
|
||||
|
||||
Simulator.prototype.getAppDirs = function (appFile, appBundleId) {
|
||||
if (parseFloat(this.platformVer) >= 8) {
|
||||
var dataDirs = wrapInArray(this.getApp8Dir(appBundleId, "Data"));
|
||||
var bundleDirs = wrapInArray(this.getApp8Dir(appBundleId, "Bundle"));
|
||||
return dataDirs.concat(bundleDirs);
|
||||
} else {
|
||||
return this.getApp7Dirs(appFile);
|
||||
}
|
||||
};
|
||||
|
||||
Simulator.prototype.getSafari7Dirs = function () {
|
||||
return this.getApp7Dirs(["MobileSafari.app", "Appium-MobileSafari-" + this.platformVer + ".app"]);
|
||||
};
|
||||
|
||||
Simulator.prototype.getApp7Dirs = function (appFiles) {
|
||||
var appsDirs = multiResolve(this.getDirs(), "Applications");
|
||||
var foundAppDirs = [];
|
||||
_.each(appsDirs, function (appsDir) {
|
||||
var cond = function (d) {
|
||||
var found = false;
|
||||
_.each(appFiles, function (appFile) {
|
||||
found = found || fs.existsSync(path.resolve(appsDir, d, appFile));
|
||||
});
|
||||
return found;
|
||||
};
|
||||
var appDir = findAppByCondition(appsDir, cond);
|
||||
if (appDir !== null) {
|
||||
foundAppDirs.push(appDir);
|
||||
}
|
||||
});
|
||||
return foundAppDirs;
|
||||
};
|
||||
|
||||
Simulator.prototype.getSafari8Dir = function () {
|
||||
return this.getApp8Dir("com.apple.mobilesafari", "Data");
|
||||
};
|
||||
|
||||
Simulator.prototype.getApp8Dir = function (bundleId, dataOrBundle) {
|
||||
var root = this.getDirs()[0];
|
||||
if (!root) {
|
||||
return null;
|
||||
}
|
||||
var appsDir = path.resolve(root, "Containers", dataOrBundle, "Application");
|
||||
var magicFile = ".com.apple.mobile_container_manager.metadata.plist";
|
||||
var cond = function (d) {
|
||||
var magicPlist = path.resolve(appsDir, d, magicFile);
|
||||
if (!fs.existsSync(magicPlist)) {
|
||||
return false;
|
||||
}
|
||||
var data = Simulator.getPlistData(magicPlist);
|
||||
return data.MCMMetadataIdentifier === bundleId;
|
||||
};
|
||||
return findAppByCondition(appsDir, cond);
|
||||
};
|
||||
|
||||
Simulator.prototype.dirsExist = function () {
|
||||
return this.getDirs().length > 0;
|
||||
};
|
||||
|
||||
Simulator.prototype.safariDirsExist = function () {
|
||||
try {
|
||||
return this.getSafariDirs().length > 0;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Simulator.prototype.cleanSafari = function (keepPrefs, cb) {
|
||||
// this method is async because we use glob paths for deletes and rimraf
|
||||
// can't handle them, so we use our own async 'rmrf' model that calls out
|
||||
// to shell to do it
|
||||
logger.debug("Cleaning mobile safari data files");
|
||||
if (!this.dirsExist()) {
|
||||
logger.info("Couldn't find Safari support directories to clean out old " +
|
||||
"data. Probably there's nothing to clean out");
|
||||
return;
|
||||
}
|
||||
|
||||
var libraryDirs = multiResolve(this.getDirs(), 'Library');
|
||||
var safariLibDirs = multiResolve(this.getSafariDirs(), 'Library');
|
||||
var toDeletes = [
|
||||
'Caches/Snapshots/com.apple.mobilesafari'
|
||||
, 'Caches/com.apple.mobilesafari/Cache.db*'
|
||||
, 'Caches/com.apple.WebAppCache/*.db'
|
||||
, 'Safari/*.plist'
|
||||
, 'WebKit/LocalStorage/*.*'
|
||||
, 'WebKit/GeolocationSites.plist'
|
||||
, 'Cookies/*.binarycookies'
|
||||
];
|
||||
var deleteActions = [];
|
||||
|
||||
var buildLibraryDeletes = function (libDirs, toDeletes) {
|
||||
_.each(libDirs, function (libraryDir) {
|
||||
_.each(toDeletes, function (relRmPath) {
|
||||
var rmPath = path.resolve(libraryDir, relRmPath);
|
||||
deleteActions.push(function (cb) {
|
||||
logger.debug("Deleting " + rmPath);
|
||||
rmrf(rmPath, cb);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var safariToDeletes = _.clone(toDeletes);
|
||||
if (!keepPrefs) {
|
||||
safariToDeletes.push('Preferences/*.plist');
|
||||
}
|
||||
|
||||
buildLibraryDeletes(libraryDirs, toDeletes);
|
||||
buildLibraryDeletes(safariLibDirs, safariToDeletes);
|
||||
|
||||
async.parallel(deleteActions, cb);
|
||||
};
|
||||
|
||||
Simulator.prototype.deleteSafari = function () {
|
||||
logger.debug("Deleting Safari apps");
|
||||
var safariDirs = multiResolve(this.getSafariDirs());
|
||||
if (parseFloat(this.platformVer) >= 8) {
|
||||
var safariBundleDir = this.getApp8Dir("com.apple.mobilesafari", "Bundle");
|
||||
safariDirs = safariDirs.concat(wrapInArray(safariBundleDir));
|
||||
}
|
||||
_.each(safariDirs, function (safariDir) {
|
||||
logger.debug("Deleting " + safariDir);
|
||||
safeRimRafSync(safariDir);
|
||||
});
|
||||
};
|
||||
|
||||
Simulator.prototype.cleanCustomApp = function (appFile, appBundleId) {
|
||||
logger.debug("Cleaning app data files");
|
||||
var appDirs = this.getAppDirs(appFile, appBundleId);
|
||||
if (appDirs.length === 0) {
|
||||
logger.info("Couldn't find app directories to delete. Probably it's not " +
|
||||
"installed");
|
||||
return;
|
||||
}
|
||||
_.each(appDirs, function (appDir) {
|
||||
logger.debug("Deleting " + appDir);
|
||||
safeRimRafSync(appDir);
|
||||
});
|
||||
};
|
||||
|
||||
Simulator.prototype.cleanSim = function (keepKeychains) {
|
||||
logger.debug("Cleaning sim data files");
|
||||
if (!this.dirsExist()) {
|
||||
logger.info("Couldn't find support directories to clean out old " +
|
||||
"data. Probably there's nothing to clean out");
|
||||
return;
|
||||
}
|
||||
var toDeletes = [
|
||||
'Library/TCC',
|
||||
'Library/Caches/locationd',
|
||||
'Library/BackBoard/applicationState.plist',
|
||||
'Media'
|
||||
];
|
||||
if (!keepKeychains) {
|
||||
toDeletes.push('Library/Keychains');
|
||||
}
|
||||
_.each(this.getDirs(), function (simDir) {
|
||||
_.each(toDeletes, function (relRmPath) {
|
||||
var rmPath = path.resolve(simDir, relRmPath);
|
||||
logger.debug("Deleting " + rmPath);
|
||||
safeRimRafSync(rmPath);
|
||||
});
|
||||
});
|
||||
|
||||
logger.debug("Cleaning sim preferences");
|
||||
var prefsPlist = Simulator.getSimAppPrefsFile();
|
||||
var data = Simulator.getPlistData(prefsPlist);
|
||||
var keysToClear = [
|
||||
'CurrentDeviceUDID',
|
||||
'SimulateDevice'
|
||||
];
|
||||
var changed = false;
|
||||
_.each(keysToClear, function (key) {
|
||||
if (_.has(data, key)) {
|
||||
logger.debug("Clearing key: " + key);
|
||||
delete data[key];
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
logger.debug("Writing new preferences plist data");
|
||||
fs.writeFileSync(prefsPlist, bplistCreate(data));
|
||||
}
|
||||
};
|
||||
|
||||
Simulator.prototype.moveBuiltInApp = function (appPath, appName, newAppDir, cb) {
|
||||
ncp(appPath, newAppDir, function (err) {
|
||||
if (err) return cb(err);
|
||||
logger.debug("Copied " + appName + " to " + newAppDir);
|
||||
rimraf(appPath, function (err) {
|
||||
if (err) {
|
||||
if (err.message.indexOf("EACCES") !== -1) {
|
||||
return cb(new Error("We don't have write access to " + appPath +
|
||||
", please re-run authorize as " + process.env.USER));
|
||||
}
|
||||
return cb(err);
|
||||
}
|
||||
logger.debug("Temporarily deleted original app at " + appPath);
|
||||
cb(null, newAppDir, appPath);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Simulator.prototype.getBuiltInApp = function (appName, cb) {
|
||||
this.getBuiltInAppDir(function (err, appDir) {
|
||||
if (err) return cb(err);
|
||||
var appPath = path.resolve(appDir, appName + ".app");
|
||||
fs.stat(appPath, function (err, s) {
|
||||
if (err && err.message.indexOf("ENOENT") !== -1) {
|
||||
logger.debug("App is not at " + appPath);
|
||||
return cb(err);
|
||||
}
|
||||
cb(null, s, appPath);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Simulator.prototype.prepareBuiltInApp = function (appName, tmpDir, cb) {
|
||||
logger.debug("Looking for built in app " + appName);
|
||||
var newAppDir = path.resolve(tmpDir, 'Appium-' + appName + '-' + this.platformVer + '.app');
|
||||
var checkApp = function (s, appPath, cb) {
|
||||
if (!s.isDirectory()) {
|
||||
cb(new Error("App package was not a directory"), appPath);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
this.getBuiltInApp(appName, function (err, s, appPath) {
|
||||
if (err) {
|
||||
fs.stat(newAppDir, function (err, s) {
|
||||
if (err) {
|
||||
logger.warn("App is also not at " + newAppDir);
|
||||
return cb(new Error("Couldn't find built in app in its home " +
|
||||
"or temp dir!"));
|
||||
}
|
||||
if (checkApp(s, appPath, cb)) {
|
||||
logger.debug("Couldn't find original app, but found the temp " +
|
||||
"Appium one so using that");
|
||||
cb(null, newAppDir, appPath);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (checkApp(s, appPath, cb)) {
|
||||
if (parseInt(this.platformVer, 10) < 7) {
|
||||
logger.debug("Got app, trying to copy " + appPath + " to tmp dir");
|
||||
ncp(appPath, newAppDir, function (err) {
|
||||
if (err) return cb(err);
|
||||
logger.debug("Copied " + appName);
|
||||
cb(null, newAppDir, null);
|
||||
});
|
||||
} else {
|
||||
logger.debug("Got app, trying to move " + appPath + " to tmp dir");
|
||||
this.moveBuiltInApp(appPath, appName, newAppDir, cb);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Simulator.prototype.getBuiltInAppDir = function (cb) {
|
||||
xcode.getPath(function (err, xcodeDir) {
|
||||
if (err) return cb(err);
|
||||
var appDir = path.resolve(xcodeDir, "Platforms/iPhoneSimulator.platform/" +
|
||||
"Developer/SDKs/iPhoneSimulator" +
|
||||
this.platformVer + ".sdk/Applications/");
|
||||
fs.stat(appDir, function (err, s) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
} else if (!s.isDirectory()) {
|
||||
cb(new Error("Could not load built in applications directory"));
|
||||
} else {
|
||||
cb(null, appDir);
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Simulator.prototype.prepareSafari = function (tmpDir, cb) {
|
||||
this.prepareBuiltInApp("MobileSafari", tmpDir, cb);
|
||||
};
|
||||
|
||||
Simulator.prototype.preparePreferencesApp = function (tmpDir, cb) {
|
||||
this.prepareBuiltInApp("Preferences", tmpDir, cb);
|
||||
};
|
||||
|
||||
Simulator.prototype.deleteSim = function () {
|
||||
var root = this.getRootDir();
|
||||
logger.debug("Deleting simulator folder: " + root);
|
||||
safeRimRafSync(root);
|
||||
};
|
||||
|
||||
Simulator.prototype.setLocale = function (language, locale, calendar) {
|
||||
var globalPrefs = multiResolve(this.getDirs(), "Library", "Preferences",
|
||||
".GlobalPreferences.plist");
|
||||
_.each(globalPrefs, function (plist) {
|
||||
var data = Simulator.getPlistData(plist);
|
||||
var curLocaleAndCal = data.AppleLocale || null;
|
||||
var supportedLangs = data.AppleLanguages || [];
|
||||
var newLangs = [];
|
||||
if (language) {
|
||||
logger.debug("New language: " + language);
|
||||
newLangs.push(language);
|
||||
newLangs = newLangs.concat(_.without(supportedLangs, language));
|
||||
data.AppleLanguages = newLangs;
|
||||
}
|
||||
if (locale || calendar) {
|
||||
var calSplit = "@calendar=";
|
||||
if (curLocaleAndCal === null) {
|
||||
curLocaleAndCal = language || 'en';
|
||||
}
|
||||
var curLoc = curLocaleAndCal.split(calSplit)[0];
|
||||
var newLocaleAndCal = locale ? locale : curLoc;
|
||||
if (calendar) {
|
||||
newLocaleAndCal += calSplit + calendar;
|
||||
}
|
||||
logger.debug("New locale: " + newLocaleAndCal);
|
||||
data.AppleLocale = newLocaleAndCal;
|
||||
}
|
||||
|
||||
logger.debug("Writing new locale plist data");
|
||||
fs.writeFileSync(plist, bplistCreate(data));
|
||||
});
|
||||
};
|
||||
|
||||
Simulator.getSimAppPrefsFile = function () {
|
||||
var u = process.env.USER;
|
||||
return path.resolve("/Users", u, "Library", "Preferences",
|
||||
"com.apple.iphonesimulator.plist");
|
||||
};
|
||||
|
||||
Simulator.prototype.deleteOtherSims = function (cb) {
|
||||
logger.debug("Isolating the requested simulator by deleting all others");
|
||||
Simctl.getDevices(function (err, devices) {
|
||||
if (err) return cb(err);
|
||||
var udids = [];
|
||||
var deleteCalls = [];
|
||||
_.each(devices, function (sdkDevices) {
|
||||
udids = udids.concat(_.pluck(sdkDevices, 'udid'));
|
||||
});
|
||||
_.each(_.without(udids, this.udid), function (udid) {
|
||||
deleteCalls.push(_.partial(Simctl.delete, udid));
|
||||
});
|
||||
async.series(deleteCalls, cb);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
module.exports = Simulator;
|
||||
@@ -0,0 +1,86 @@
|
||||
"use strict";
|
||||
|
||||
var logger = require('../../server/logger.js').get('appium')
|
||||
, fs = require('fs')
|
||||
, path = require('path')
|
||||
, exec = require('child_process').exec;
|
||||
|
||||
var xcode = {};
|
||||
|
||||
xcode.getPath = function (cb) {
|
||||
exec('xcode-select --print-path', { maxBuffer: 524288, timeout: 3000 }, function (err, stdout, stderr) {
|
||||
if (!err) {
|
||||
var xcodeFolderPath = stdout.replace("\n", "");
|
||||
if (fs.existsSync(xcodeFolderPath)) {
|
||||
cb(null, xcodeFolderPath);
|
||||
} else {
|
||||
logger.error(xcodeFolderPath + "does not exist.");
|
||||
cb(new Error("xcode-select could not find xcode"), null);
|
||||
}
|
||||
} else {
|
||||
logger.error("xcode-select threw error " + err);
|
||||
logger.error("Stderr: " + stderr);
|
||||
logger.error("Stdout: " + stdout);
|
||||
cb(new Error("xcode-select threw an error"), null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
xcode.getVersion = function (cb) {
|
||||
xcode.getPath(function (err, xcodePath) {
|
||||
if (err !== null) {
|
||||
cb(err, null);
|
||||
} else {
|
||||
var xcodebuildPath = path.resolve(xcodePath, "usr/bin/xcodebuild");
|
||||
if (!fs.existsSync(xcodebuildPath)) {
|
||||
cb(new Error("Could not get Xcode version: " + xcodebuildPath + " does not exist on disk."), null);
|
||||
} else {
|
||||
exec(JSON.stringify(xcodebuildPath) + ' -version', { maxBuffer: 524288, timeout: 3000 }, function (err, stdout) {
|
||||
var versionPattern = /\d\.\d\.*\d*/;
|
||||
var match = versionPattern.exec(stdout);
|
||||
if (match === null) {
|
||||
cb(new Error("Could not parse Xcode version (xcodebuild output was: " + stdout + ")"), null);
|
||||
} else {
|
||||
var versionNumber = match[0];
|
||||
cb(null, versionNumber);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
xcode.getiOSSDKVersion = function (cb) {
|
||||
var msg;
|
||||
xcode.getVersion(function (err, versionNumber) {
|
||||
if (err) {
|
||||
msg = "Could not get the iOS SDK version because the Xcode version could not be determined.";
|
||||
logger.error(msg);
|
||||
cb(new Error(msg), null);
|
||||
} else if (versionNumber[0] === '4') {
|
||||
cb(null, '6.1');
|
||||
} else {
|
||||
exec('xcrun --sdk iphonesimulator --show-sdk-version', { maxBuffer: 524288, timeout: 3000 }, function (err, stdout, stderr) {
|
||||
if (!err) {
|
||||
var iosSDKVersion = stdout.replace("\n", "");
|
||||
var match = /\d.\d/.exec(iosSDKVersion);
|
||||
if (match) {
|
||||
cb(null, iosSDKVersion);
|
||||
} else {
|
||||
msg = "xcrun returned a non-numeric iOS SDK version: " + iosSDKVersion;
|
||||
logger.error(msg);
|
||||
cb(new Error(msg), null);
|
||||
}
|
||||
} else {
|
||||
msg = "xcrun threw an error " + err;
|
||||
logger.error(msg);
|
||||
logger.error("Stderr: " + stderr);
|
||||
logger.error("Stdout: " + stdout);
|
||||
cb(new Error(msg), null);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = xcode;
|
||||
+10
-255
@@ -2,15 +2,12 @@
|
||||
|
||||
var logger = require('./server/logger.js').get('appium')
|
||||
, fs = require('fs')
|
||||
, ncp = require('ncp').ncp
|
||||
, request = require('request')
|
||||
, _ = require('underscore')
|
||||
, path = require('path')
|
||||
, rimraf = require('rimraf')
|
||||
, exec = require('child_process').exec
|
||||
, osType = require('os').type()
|
||||
, tempdir = require('./tempdir')
|
||||
, glob = require('glob')
|
||||
, AdmZip = require('adm-zip');
|
||||
|
||||
|
||||
@@ -147,161 +144,6 @@ exports.unzipApp = function (zipPath, appExt, cb) {
|
||||
});
|
||||
};
|
||||
|
||||
exports.checkBuiltInApp = function (appName, version, tmpDir, cb) {
|
||||
logger.debug("Looking for built in app " + appName);
|
||||
var newAppDir = path.resolve(tmpDir, 'Appium-' + appName + '.app');
|
||||
var checkApp = function (s, appPath, cb) {
|
||||
if (!s.isDirectory()) {
|
||||
cb(new Error("App package was not a directory"), appPath);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
exports.getBuiltInAppDir(version, function (err, appDir) {
|
||||
if (err) return cb(err);
|
||||
var appPath = path.resolve(appDir, appName + ".app");
|
||||
fs.stat(appPath, function (err, s) {
|
||||
if (err && err.message.indexOf("ENOENT") !== -1) {
|
||||
logger.debug("App is not at " + appPath);
|
||||
fs.stat(newAppDir, function (err, s) {
|
||||
if (err) {
|
||||
logger.warn("App is also not at " + newAppDir);
|
||||
return cb(new Error("Couldn't find built in app in its home " +
|
||||
"or temp dir!"));
|
||||
}
|
||||
if (checkApp(s, appPath, cb)) {
|
||||
logger.debug("Couldn't find original app, but found the temp " +
|
||||
"Appium one so using that");
|
||||
cb(null, newAppDir, appPath);
|
||||
}
|
||||
});
|
||||
return;
|
||||
} else if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
if (checkApp(s, appPath, cb)) {
|
||||
if (parseInt(version, 10) < 7) {
|
||||
logger.debug("Got app, trying to copy " + appPath + " to tmp dir");
|
||||
ncp(appPath, newAppDir, function (err) {
|
||||
if (err) return cb(err);
|
||||
logger.debug("Copied " + appName);
|
||||
cb(null, newAppDir, null);
|
||||
});
|
||||
} else {
|
||||
logger.debug("Got app, trying to move " + appPath + " to tmp dir");
|
||||
exports.moveBuiltInApp(appPath, appName, newAppDir, cb);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.checkSafari = function (version, tmpDir, cb) {
|
||||
exports.checkBuiltInApp("MobileSafari", version, tmpDir, cb);
|
||||
};
|
||||
|
||||
exports.checkPreferencesApp = function (version, tmpDir, cb) {
|
||||
exports.checkBuiltInApp("Preferences", version, tmpDir, cb);
|
||||
};
|
||||
|
||||
exports.getBuiltInAppDir = function (version, cb) {
|
||||
exports.getXcodeFolder(function (err, xcodeDir) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var appDir = path.resolve(xcodeDir, "Platforms/iPhoneSimulator.platform/" +
|
||||
"Developer/SDKs/iPhoneSimulator" + version +
|
||||
".sdk/Applications/");
|
||||
fs.stat(appDir, function (err, s) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
} else if (!s.isDirectory()) {
|
||||
cb(new Error("Could not load built in applications directory"));
|
||||
} else {
|
||||
cb(null, appDir);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.moveBuiltInApp = function (appPath, appName, newAppDir, cb) {
|
||||
ncp(appPath, newAppDir, function (err) {
|
||||
if (err) return cb(err);
|
||||
logger.debug("Copied " + appName + " to " + newAppDir);
|
||||
rimraf(appPath, function (err) {
|
||||
if (err) {
|
||||
if (err.message.indexOf("EACCES") !== -1) {
|
||||
return cb(new Error("We don't have write access to " + appPath +
|
||||
", please re-run authorize as " + process.env.USER));
|
||||
}
|
||||
return cb(err);
|
||||
}
|
||||
logger.debug("Temporarily deleted original app at " + appPath);
|
||||
cb(null, newAppDir, appPath);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.cleanSafari = function (safariVer, cb) {
|
||||
var baseDir = "Library/Application Support/iPhone Simulator/" +
|
||||
safariVer + "*/Library/";
|
||||
exports.getUser(function (err, user) {
|
||||
if (err) {
|
||||
logger.error(err);
|
||||
cb(err);
|
||||
} else {
|
||||
var baseSupportDirs = path.resolve("/Users", user, baseDir);
|
||||
glob(baseSupportDirs, function (err, pathList) {
|
||||
if (err) return cb(err);
|
||||
if (pathList.length === 0) {
|
||||
logger.debug("Couldn't find Safari support directories in order " +
|
||||
"to clear out old data");
|
||||
return cb();
|
||||
}
|
||||
var pathsFinished = 0;
|
||||
var errToRet = null;
|
||||
var finishAll = function (err) {
|
||||
if (err) errToRet = err;
|
||||
pathsFinished++;
|
||||
if (pathsFinished === pathList.length) {
|
||||
cb(err);
|
||||
}
|
||||
};
|
||||
_.each(pathList, function (baseSupportDir) {
|
||||
var toDeletes = [
|
||||
'Caches/Snapshots/com.apple.mobilesafari'
|
||||
, 'Caches/com.apple.mobilesafari/Cache.db*'
|
||||
, 'Caches/com.apple.WebAppCache/*.db'
|
||||
, 'Safari/*.plist'
|
||||
, 'WebKit/LocalStorage/*.*'
|
||||
, 'Library/WebKit/GeolocationSites.plist'
|
||||
, 'Cookies/*.binarycookies'
|
||||
];
|
||||
var deletes = 0;
|
||||
var errToRet = null;
|
||||
var finishOne = function (err) {
|
||||
deletes++;
|
||||
if (err) {
|
||||
errToRet = err;
|
||||
}
|
||||
if (deletes === toDeletes.length) {
|
||||
finishAll(errToRet);
|
||||
}
|
||||
};
|
||||
_.each(toDeletes, function (del) {
|
||||
var toDelete = path.resolve(baseSupportDir, del);
|
||||
toDelete = toDelete.replace(/ /g, "\\ ");
|
||||
logger.debug("Deleting " + toDelete);
|
||||
var cmd = "rm -rf " + toDelete;
|
||||
exec(cmd, function (err) {
|
||||
finishOne(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.getUser = function (cb) {
|
||||
logger.debug("Determining current user");
|
||||
exec("whoami", { maxBuffer: 524288 }, function (err, stdout) {
|
||||
@@ -315,6 +157,16 @@ exports.getUser = function (cb) {
|
||||
});
|
||||
};
|
||||
|
||||
exports.multiResolve = function (roots) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
var paths = [];
|
||||
_.each(roots, function (root) {
|
||||
var resolveArgs = [root].concat(args);
|
||||
paths.push(path.resolve.apply(null, resolveArgs));
|
||||
});
|
||||
return paths;
|
||||
};
|
||||
|
||||
exports.delay = function (secs) {
|
||||
var date = new Date();
|
||||
var curDate = null;
|
||||
@@ -322,13 +174,6 @@ exports.delay = function (secs) {
|
||||
while (curDate - date < (secs * 1000.0));
|
||||
};
|
||||
|
||||
// var pad0 = function (x) {
|
||||
// if (x.toString().length == 1) {
|
||||
// x = '0' + x;
|
||||
// }
|
||||
// return x;
|
||||
// };
|
||||
|
||||
exports.escapeSpecialChars = function (str, quoteEscape) {
|
||||
if (typeof str !== "string") {
|
||||
return str;
|
||||
@@ -482,96 +327,6 @@ exports.getGitRev = function (cb) {
|
||||
});
|
||||
};
|
||||
|
||||
exports.getXcodeFolder = function (cb) {
|
||||
exec('xcode-select --print-path', { maxBuffer: 524288, timeout: 3000 }, function (err, stdout, stderr) {
|
||||
if (!err) {
|
||||
var xcodeFolderPath = stdout.replace("\n", "");
|
||||
if (fs.existsSync(xcodeFolderPath)) {
|
||||
cb(null, xcodeFolderPath);
|
||||
} else {
|
||||
logger.error(xcodeFolderPath + "does not exist.");
|
||||
cb(new Error("xcode-select could not find xcode"), null);
|
||||
}
|
||||
} else {
|
||||
logger.error("xcode-select threw error " + err);
|
||||
logger.error("Stderr: " + stderr);
|
||||
logger.error("Stdout: " + stdout);
|
||||
cb(new Error("xcode-select threw an error"), null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.getXcodeVersion = function (cb) {
|
||||
exports.getXcodeFolder(function (err, xcodePath) {
|
||||
if (err !== null) {
|
||||
cb(err, null);
|
||||
} else {
|
||||
var xcodebuildPath = path.resolve(xcodePath, "usr/bin/xcodebuild");
|
||||
if (!fs.existsSync(xcodebuildPath)) {
|
||||
cb(new Error("Could not get Xcode version: " + xcodebuildPath + " does not exist on disk."), null);
|
||||
} else {
|
||||
exec(JSON.stringify(xcodebuildPath) + ' -version', { maxBuffer: 524288, timeout: 3000 }, function (err, stdout) {
|
||||
var versionPattern = /\d\.\d\.*\d*/;
|
||||
var match = versionPattern.exec(stdout);
|
||||
if (match === null) {
|
||||
cb(new Error("Could not parse Xcode version (xcodebuild output was: " + stdout + ")"), null);
|
||||
} else {
|
||||
var versionNumber = match[0];
|
||||
cb(null, versionNumber);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.getiOSSDKVersion = function (cb) {
|
||||
var msg;
|
||||
exports.getXcodeVersion(function (err, versionNumber) {
|
||||
if (err) {
|
||||
msg = "Could not get the iOS SDK version because the Xcode version could not be determined.";
|
||||
logger.error(msg);
|
||||
cb(new Error(msg), null);
|
||||
} else if (versionNumber[0] === '4') {
|
||||
cb(null, '6.1');
|
||||
} else {
|
||||
exec('xcrun --sdk iphonesimulator --show-sdk-version', { maxBuffer: 524288, timeout: 3000 }, function (err, stdout, stderr) {
|
||||
if (!err) {
|
||||
var iosSDKVersion = stdout.replace("\n", "");
|
||||
var match = /\d.\d/.exec(iosSDKVersion);
|
||||
if (match) {
|
||||
cb(null, iosSDKVersion);
|
||||
} else {
|
||||
msg = "xcrun returned a non-numeric iOS SDK version: " + iosSDKVersion;
|
||||
logger.error(msg);
|
||||
cb(new Error(msg), null);
|
||||
}
|
||||
} else {
|
||||
msg = "xcrun threw an error " + err;
|
||||
logger.error(msg);
|
||||
logger.error("Stderr: " + stderr);
|
||||
logger.error("Stdout: " + stdout);
|
||||
cb(new Error(msg), null);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.getiOSSimulatorDirectories = function (cb) {
|
||||
var basePath = path.resolve(process.env.HOME, "Library", "Application Support",
|
||||
"iPhone Simulator");
|
||||
glob(basePath + "/*.*", function (err, pathList) {
|
||||
if (err) {
|
||||
var msg = "Could not find any directories for the iOS Simulator";
|
||||
logger.error(msg);
|
||||
cb(new Error(msg));
|
||||
} else {
|
||||
cb(null, pathList);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.getAppiumConfig = function () {
|
||||
var configPath = path.resolve(__dirname, "..", ".appiumconfig.json");
|
||||
var config
|
||||
|
||||
@@ -545,6 +545,20 @@ var args = [
|
||||
, nargs: 0
|
||||
}],
|
||||
|
||||
[['--isolate-sim-device'], {
|
||||
defaultValue: false
|
||||
, dest: 'isolateSimDevice'
|
||||
, action: 'storeTrue'
|
||||
, required: false
|
||||
, help: "Xcode 6 has a bug on some platforms where a certain simulator " +
|
||||
"can only be launched without error if all other simulator devices " +
|
||||
"are first deleted. This option causes Appium to delete all " +
|
||||
"devices other than the one being used by Appium. Note that this " +
|
||||
"is a permanent deletion, and you are responsible for using simctl " +
|
||||
"or xcode to manage the categories of devices used with Appium."
|
||||
, nargs: 0
|
||||
}],
|
||||
|
||||
[['--tmp'], {
|
||||
defaultValue: null
|
||||
, dest: 'tmpDir'
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
"firefoxos",
|
||||
"testing"
|
||||
],
|
||||
"version": "1.2.3",
|
||||
"version": "1.3.0-beta1",
|
||||
"author": "appium-discuss@googlegroups.com",
|
||||
"licenses": [
|
||||
{
|
||||
|
||||
@@ -152,19 +152,21 @@ reset_ios() {
|
||||
set +e
|
||||
sdk_ver=$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null)
|
||||
sdk_status=$?
|
||||
ios7_active=true
|
||||
if [ $sdk_status -gt 0 ] || [[ "$sdk_ver" != "7."* ]]; then
|
||||
echo "--------------------------------------------------"
|
||||
echo "WARNING: you do not appear to have iOS7 SDK active"
|
||||
echo "--------------------------------------------------"
|
||||
ios7_active=false
|
||||
ios7_active=false
|
||||
ios8_active=false
|
||||
if [[ "$sdk_ver" == "7."* ]]; then
|
||||
ios7_active=true
|
||||
elif [[ "$sdk_ver" == "8."* ]]; then
|
||||
ios8_active=true
|
||||
fi
|
||||
if [ $sdk_status -gt 0 ] || (! $ios7_active && ! $ios8_active); then
|
||||
echo "---------------------------------------------------"
|
||||
echo "WARNING: you do not appear to have iOS7/8 SDK active"
|
||||
echo "---------------------------------------------------"
|
||||
fi
|
||||
set -e
|
||||
echo "* Setting iOS config to Appium's version"
|
||||
run_cmd "$grunt" setConfigVer:ios
|
||||
echo "* Installing ios-sim-locale"
|
||||
run_cmd rm -f build/ios-sim-locale
|
||||
run_cmd cp assets/ios-sim-locale build/ios-sim-locale
|
||||
echo "* Cloning/updating udidetect"
|
||||
run_cmd git submodule update --init submodules/udidetect
|
||||
echo "* Building udidetect"
|
||||
@@ -186,7 +188,7 @@ reset_ios() {
|
||||
echo "* Cloning/npm linking appium-adb"
|
||||
run_cmd ./bin/npmlink.sh -l appium-adb
|
||||
fi
|
||||
if $ios7_active ; then
|
||||
if $ios7_active || $ios8_active ; then
|
||||
if $hardcore ; then
|
||||
echo "* Clearing out old UICatalog download"
|
||||
run_cmd rm -rf ./sample-code/apps/UICatalog/
|
||||
|
||||
@@ -8,3 +8,6 @@ Here's a list of things that aren't tested in this suite:
|
||||
* android with --udid (even if emulator)
|
||||
* --avd / avdName
|
||||
* sudo grunt authorize
|
||||
* non-default --tmp
|
||||
* --full-reset
|
||||
* --isolate-sim-device
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var setup = require("../../common/setup-base")
|
||||
, desired = require("./desired");
|
||||
|
||||
describe("apidemos - stability @skip-ci", function () {
|
||||
|
||||
var runs = 20;
|
||||
|
||||
var test = function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
it('should complete successfully', function (done) {
|
||||
driver
|
||||
.elementByName('Animation')
|
||||
.nodeify(done);
|
||||
});
|
||||
};
|
||||
|
||||
for (var n = 0; n < runs; n++) {
|
||||
describe('burn-in test ' + n, test);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -20,11 +20,16 @@ function log(data) {
|
||||
}
|
||||
|
||||
var waitForLaunch = function (app, extraArgs, done) {
|
||||
var args = [".", "-p", crazyPort, "-l", "-dd", "-r", "3", "-lt", JSON.stringify(env.LAUNCH_TIMEOUT)];
|
||||
var args = [".", "-p", crazyPort, "-l", "-dd", "-r", "5", "-lt", JSON.stringify(env.LAUNCH_TIMEOUT), "--platform-version", env.CAPS.platformVersion];
|
||||
if (app) {
|
||||
args = args.concat(["--app", app]);
|
||||
if (app === "safari") {
|
||||
args = args.concat(["--browser-name", "safari"]);
|
||||
} else {
|
||||
args = args.concat(["--app", app]);
|
||||
}
|
||||
}
|
||||
args = args.concat(extraArgs);
|
||||
log("Launching appium with args: " + JSON.stringify(args));
|
||||
var proc = spawn('node', args, {cwd: path.resolve(__dirname, "..", "..", "..")});
|
||||
proc.stdout.setEncoding('utf8');
|
||||
proc.stderr.setEncoding('utf8');
|
||||
|
||||
@@ -22,7 +22,7 @@ module.exports = function (desired) {
|
||||
return;
|
||||
}
|
||||
return driver
|
||||
.execute("mobile: leaveWebView")
|
||||
.context('NATIVE_APP')
|
||||
.title()
|
||||
.should.be.rejectedWith(/status: 13/);
|
||||
}).nodeify(done);
|
||||
|
||||
@@ -6,14 +6,16 @@ var setup = require("../common/setup-base")
|
||||
, fs = require('fs')
|
||||
, path = require('path')
|
||||
, Readable = require('stream').Readable
|
||||
, iOSSettings = require('../../../lib/devices/ios/settings.js')
|
||||
, Simulator = require('../../../lib/devices/ios/simulator.js')
|
||||
, xcode = require('../../../lib/devices/ios/xcode.js')
|
||||
, exec = require('child_process').exec
|
||||
, getSimUdid = require('../../helpers/sim-udid.js').getSimUdid
|
||||
, Unzip = require('unzip');
|
||||
|
||||
describe('file movements - pullFile and pushFile', function () {
|
||||
var driver;
|
||||
var desired = {
|
||||
app: getAppPath('testapp')
|
||||
app: getAppPath('TestApp')
|
||||
};
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
@@ -54,20 +56,47 @@ describe('file movements - pullFile and pushFile', function () {
|
||||
var fullPath = "";
|
||||
before(function (done) {
|
||||
var pv = env.CAPS.platformVersion || '7.1';
|
||||
var simRoots = iOSSettings.getSimRootsWithVersion(pv);
|
||||
if (simRoots.length < 1) {
|
||||
return done(new Error("Didn't find any simulator directories"));
|
||||
}
|
||||
var basePath = path.resolve(simRoots[0], 'Applications')
|
||||
.replace(/\s/g, '\\ ');
|
||||
|
||||
var findCmd = 'find ' + basePath + ' -name "testapp.app"';
|
||||
exec(findCmd, function (err, stdout) {
|
||||
var ios8 = parseFloat(pv) >= 8;
|
||||
xcode.getiOSSDKVersion(function (err, sdk) {
|
||||
if (err) return done(err);
|
||||
if (!stdout) return done(new Error("Could not find testapp.app"));
|
||||
var appRoot = stdout.replace(/\n$/, '');
|
||||
fullPath = path.resolve(appRoot, fileName);
|
||||
fs.writeFile(fullPath, fileContent, done);
|
||||
var next = function (udid) {
|
||||
var sim = new Simulator({
|
||||
platformVer: pv,
|
||||
sdkVer: sdk,
|
||||
udid: udid
|
||||
});
|
||||
var simRoots = sim.getDirs();
|
||||
if (simRoots.length < 1) {
|
||||
return done(new Error("Didn't find any simulator directories"));
|
||||
}
|
||||
var basePath;
|
||||
if (ios8) {
|
||||
// ios8 apps are stored in a different directory structure, need
|
||||
// to navigate down a few more here
|
||||
basePath = path.resolve(simRoots[0], 'Containers', 'Bundle',
|
||||
'Application');
|
||||
} else {
|
||||
basePath = path.resolve(simRoots[0], 'Applications');
|
||||
}
|
||||
basePath = basePath.replace(/\s/g, '\\ ');
|
||||
|
||||
var findCmd = 'find ' + basePath + ' -name "TestApp.app"';
|
||||
exec(findCmd, function (err, stdout) {
|
||||
if (err) return done(err);
|
||||
if (!stdout) return done(new Error("Could not find testapp.app"));
|
||||
var appRoot = stdout.replace(/\n$/, '');
|
||||
fullPath = path.resolve(appRoot, fileName);
|
||||
fs.writeFile(fullPath, fileContent, done);
|
||||
});
|
||||
};
|
||||
if (parseFloat(sdk) >= 8) {
|
||||
getSimUdid('6', sdk, env.CAPS, function (err, udid) {
|
||||
if (err) return done(err);
|
||||
next(udid);
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
});
|
||||
after(function (done) {
|
||||
@@ -78,7 +107,7 @@ describe('file movements - pullFile and pushFile', function () {
|
||||
}
|
||||
});
|
||||
it('should be able to fetch a file from the app directory', function (done) {
|
||||
var arg = path.resolve('/testapp.app', fileName);
|
||||
var arg = path.resolve('/TestApp.app', fileName);
|
||||
driver
|
||||
.pullFile(arg)
|
||||
.then(function (data) {
|
||||
@@ -92,7 +121,7 @@ describe('file movements - pullFile and pushFile', function () {
|
||||
it('should pull all the files in Library/AddressBook', function (done) {
|
||||
var entryCount = 0;
|
||||
driver.pullFolder('Library/AddressBook')
|
||||
.then( function (data) {
|
||||
.then(function (data) {
|
||||
var zipStream = new Readable();
|
||||
zipStream._read = function noop() {};
|
||||
zipStream
|
||||
|
||||
@@ -17,12 +17,14 @@ describe("prefs @skip-ios6", function () {
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
it('should turn off autocomplete', function (done) {
|
||||
var ios7 = env.DEVICE.indexOf("7") !== -1;
|
||||
var ios7up = ["ios7", "ios71", "ios8"].indexOf(env.DEVICE) !== -1;
|
||||
var ios8 = env.DEVICE === "ios8";
|
||||
var switchEl;
|
||||
driver
|
||||
.elementsByClassName("UIATableCell").at(ios7 ? 0 : 1).click()
|
||||
.elementsByClassName("UIATableCell").at(ios7up ? 0 : 1).click()
|
||||
.sleep(1000)
|
||||
.elementsByClassName("UIATableCell").at(ios7 ? 3 : 1).click()
|
||||
.elementsByClassName("UIATableCell").at(ios7up ? (ios8 ? 2 : 3) : 1)
|
||||
.click()
|
||||
.elementByXPath('//UIASwitch[@name="Auto-Correction"]')
|
||||
.then(function (el) { switchEl = el; return el; })
|
||||
.getValue().then(function (checked) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
"use strict";
|
||||
|
||||
var setup = require("../../common/setup-base")
|
||||
, chai = require('chai');
|
||||
|
||||
chai.should();
|
||||
|
||||
var desired = {
|
||||
bundleId: 'com.apple.Preferences'
|
||||
};
|
||||
|
||||
describe('settings app @skip-ios6 @skip-ios7', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
it('should launch via bundle id', function (done) {
|
||||
driver
|
||||
.source()
|
||||
.should.eventually.contain("Settings")
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
var _ = require('underscore');
|
||||
var _ = require('underscore')
|
||||
, env = require('../../../helpers/env.js')
|
||||
, xcode = require('../../../../lib/devices/ios/xcode.js')
|
||||
, Simulator = require('../../../../lib/devices/ios/simulator.js')
|
||||
, settingsPlists = require('../../../../lib/devices/ios/settings.js')
|
||||
, getSimUdid = require('../../../helpers/sim-udid').getSimUdid;
|
||||
|
||||
exports.ios6 = function (driver, setting, expected, cb) {
|
||||
driver
|
||||
@@ -20,29 +25,49 @@ exports.ios6 = function (driver, setting, expected, cb) {
|
||||
}).nodeify(cb);
|
||||
};
|
||||
|
||||
exports.ios7 = function (setting, expected, cb) {
|
||||
var ios7up = function (version, udid, setting, expected, cb) {
|
||||
var settingsSets;
|
||||
var foundSettings;
|
||||
try {
|
||||
var settingsPlists = require('../../../../lib/devices/ios/settings.js');
|
||||
settingsSets = settingsPlists.getSettings('7', 'mobileSafari');
|
||||
} catch (e) {
|
||||
return cb(e);
|
||||
}
|
||||
_.size(settingsSets).should.be.above(0);
|
||||
for (var i = 0; i < settingsSets.length; i++) {
|
||||
xcode.getiOSSDKVersion(function (err, sdk) {
|
||||
var sim = new Simulator({
|
||||
platformVer: env.CAPS.platformVersion,
|
||||
sdkVer: sdk,
|
||||
udid: udid
|
||||
});
|
||||
if (err) return cb(err);
|
||||
try {
|
||||
foundSettings.push(settingsSets[i][setting]);
|
||||
settingsSets = settingsPlists.getSettings(sim, 'mobileSafari');
|
||||
} catch (e) {
|
||||
return cb(e);
|
||||
}
|
||||
}
|
||||
if (settingsSets.length > 0) {
|
||||
console.log("More than one safari settings set found, a failure here " +
|
||||
"might not be accurate");
|
||||
}
|
||||
for (i = 0; i < settingsSets.length; i++) {
|
||||
foundSettings[i].should.eql(expected);
|
||||
}
|
||||
cb();
|
||||
_.size(settingsSets).should.be.above(0);
|
||||
for (var i = 0; i < settingsSets.length; i++) {
|
||||
try {
|
||||
foundSettings.push(settingsSets[i][setting]);
|
||||
} catch (e) {
|
||||
return cb(e);
|
||||
}
|
||||
}
|
||||
if (settingsSets.length > 0) {
|
||||
console.log("More than one safari settings set found, a failure here " +
|
||||
"might not be accurate");
|
||||
}
|
||||
for (i = 0; i < settingsSets.length; i++) {
|
||||
foundSettings[i].should.eql(expected);
|
||||
}
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
exports.ios7up = function (desired, setting, expected, cb) {
|
||||
xcode.getiOSSDKVersion(function (err, sdk) {
|
||||
if (parseFloat(sdk) >= 8) {
|
||||
getSimUdid('6', sdk, desired, function (err, udid) {
|
||||
if (err) return cb(err);
|
||||
ios7up(desired.platformVersion, udid, setting, expected, cb);
|
||||
});
|
||||
} else {
|
||||
ios7up(desired.platformVersion, null, setting, expected, cb);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -10,13 +10,13 @@ var desired = {
|
||||
app: 'settings'
|
||||
};
|
||||
|
||||
describe("prefs @skip-ios7 @skip-ios6", function () {
|
||||
// TODO: check why it fails on ios7
|
||||
describe("prefs @skip-ios6 @skip-ios7 @skip-ios8", function () {
|
||||
// on ios8 sim it crashes when tapping on "location services"
|
||||
// TODO: cannot install settings app on ios6
|
||||
|
||||
var checkLocServ = function (driver, expected, cb) {
|
||||
driver
|
||||
.elementsByClassName('UIATableCell').at(2).click()
|
||||
.elementsByClassName('UIATableCell').at(1).click()
|
||||
.sleep(1000)
|
||||
.elementByClassName('UIATableCell').click()
|
||||
.elementByClassName('UIASwitch')
|
||||
|
||||
@@ -36,11 +36,11 @@ if (env.IOS6) {
|
||||
});
|
||||
});
|
||||
});
|
||||
} else if (env.IOS7) {
|
||||
describe('safari ios7 prefs @skip-ci', function () {
|
||||
} else if (env.IOS7 || env.IOS8) {
|
||||
describe('safari ios7/8 prefs @skip-ci', function () {
|
||||
// TODO modify the test to enable ci, right know it is checking a local file,
|
||||
// not gonna work with sauce
|
||||
var checkSafariSetting = require('./check-safari-settings').ios7;
|
||||
var checkSafariSetting = require('./check-safari-settings').ios7up;
|
||||
|
||||
describe('using safariAllowPopups', function () {
|
||||
var driver;
|
||||
@@ -48,7 +48,9 @@ if (env.IOS6) {
|
||||
.then(function (d) { driver = d; });
|
||||
|
||||
it('should respond to cap when true', function (done) {
|
||||
checkSafariSetting('WebKitJavaScriptCanOpenWindowsAutomatically', true, done);
|
||||
checkSafariSetting(driver._origCaps,
|
||||
'WebKitJavaScriptCanOpenWindowsAutomatically',
|
||||
true, done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,7 +60,9 @@ if (env.IOS6) {
|
||||
.then(function (d) { driver = d; });
|
||||
|
||||
it('should respond to cap when false', function (done) {
|
||||
checkSafariSetting('WebKitJavaScriptCanOpenWindowsAutomatically', false, done);
|
||||
checkSafariSetting(driver._origCaps,
|
||||
'WebKitJavaScriptCanOpenWindowsAutomatically',
|
||||
false, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -36,11 +36,11 @@ if (env.IOS6) {
|
||||
});
|
||||
});
|
||||
});
|
||||
} else if (env.IOS7) {
|
||||
describe('safari ios7 prefs @skip-ci', function () {
|
||||
} else if (env.IOS7 || env.IOS8) {
|
||||
describe('safari ios7/8 prefs @skip-ci', function () {
|
||||
// TODO modify the test to enable ci, right know it is checking a local file,
|
||||
// not gonna work with sauce
|
||||
var checkSafariSetting = require('./check-safari-settings').ios7;
|
||||
var checkSafariSetting = require('./check-safari-settings').ios7up;
|
||||
|
||||
describe('using safariIgnoreFraudWarning', function () {
|
||||
var driver;
|
||||
@@ -48,7 +48,8 @@ if (env.IOS6) {
|
||||
.then(function (d) { driver = d; });
|
||||
|
||||
it('should respond to cap when true', function (done) {
|
||||
checkSafariSetting('WarnAboutFraudulentWebsites', false, done);
|
||||
checkSafariSetting(driver._origCaps, 'WarnAboutFraudulentWebsites',
|
||||
false, done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,8 +59,9 @@ if (env.IOS6) {
|
||||
.then(function (d) { driver = d; });
|
||||
|
||||
it('should respond to cap when false', function (done) {
|
||||
checkSafariSetting('WarnAboutFraudulentWebsites', true, done);
|
||||
checkSafariSetting(driver._origCaps, 'WarnAboutFraudulentWebsites',
|
||||
true, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,11 @@ describe('safari - webview - special capabilities', function () {
|
||||
loadWebView(specialCaps, driver).nodeify(done);
|
||||
});
|
||||
|
||||
it('should not display a phishing warning with safariIgnoreFraudWarning @skip-chrome', function (done) {
|
||||
// iOS8 currently does not disable the phishing warning for foo:bar@ type
|
||||
// addresses, even when running the sim manually
|
||||
// TODO: find another way to trigger the phishing warning that IS disabled
|
||||
// by the pref on iOS8
|
||||
it('should not display a phishing warning with safariIgnoreFraudWarning @skip-chrome @skip-ios8', function (done) {
|
||||
var titleToBecomeRight = new ChaiAsserter(function (driver) {
|
||||
return driver
|
||||
.title()
|
||||
|
||||
@@ -23,7 +23,9 @@ describe('safari - windows and frames (' + env.DEVICE + ') @skip-ios6"', functio
|
||||
.should.be.rejectedWith(/status: 23/)
|
||||
.nodeify(done);
|
||||
});
|
||||
it("should be able to open and close windows", function (done) {
|
||||
it("should be able to open and close windows @skip-ios8", function (done) {
|
||||
// unfortunately, iOS8 doesn't respond to the close() method on window
|
||||
// the way iOS7 does
|
||||
driver
|
||||
.elementById('blanklink').click()
|
||||
.then(function () { return spinTitle("I am another page title", driver); })
|
||||
|
||||
@@ -13,8 +13,8 @@ describe('testapp - autoAcceptAlerts cap = ""', function () {
|
||||
setup(self, caps).then(function (d) { driver = d; });
|
||||
|
||||
it('does not auto-accept alerts', function (done) {
|
||||
driver.elementsByClassName('UIAButton')
|
||||
.then(function (buttons) { return buttons[3].click(); })
|
||||
driver
|
||||
.elementByAccessibilityId('show alert').click()
|
||||
.sleep(2000)
|
||||
.alertText()
|
||||
.should.eventually.exist
|
||||
|
||||
@@ -13,8 +13,8 @@ describe('testapp - autoAcceptAlerts cap = false', function () {
|
||||
setup(self, caps).then(function (d) { driver = d; });
|
||||
|
||||
it('does not auto-accept alerts', function (done) {
|
||||
driver.elementsByClassName('UIAButton')
|
||||
.then(function (buttons) { return buttons[3].click(); })
|
||||
driver
|
||||
.elementByAccessibilityId('show alert').click()
|
||||
.sleep(2000)
|
||||
.alertText()
|
||||
.should.eventually.exist
|
||||
@@ -31,8 +31,8 @@ describe('testapp - autoAcceptAlerts cap = "false"', function () {
|
||||
setup(self, caps).then(function (d) { driver = d; });
|
||||
|
||||
it('does not auto-accept alerts', function (done) {
|
||||
driver.elementsByClassName('UIAButton')
|
||||
.then(function (buttons) { return buttons[3].click(); })
|
||||
driver
|
||||
.elementByAccessibilityId('show alert').click()
|
||||
.sleep(2000)
|
||||
.alertText()
|
||||
.should.eventually.exist
|
||||
|
||||
@@ -13,8 +13,8 @@ describe('testapp - autoAcceptAlerts cap = true', function () {
|
||||
setup(self, caps).then(function (d) { driver = d; });
|
||||
|
||||
it('auto-accepts alerts', function (done) {
|
||||
driver.elementsByClassName('UIAButton')
|
||||
.then(function (buttons) { return buttons[3].click(); })
|
||||
driver
|
||||
.elementByAccessibilityId('show alert').click()
|
||||
.sleep(2000)
|
||||
.alertText()
|
||||
.should.be.rejectedWith(/status: 27/)
|
||||
@@ -31,8 +31,8 @@ describe('testapp - autoAcceptAlerts cap = "true"', function () {
|
||||
setup(self, caps).then(function (d) { driver = d; });
|
||||
|
||||
it('auto-accepts alerts', function (done) {
|
||||
driver.elementsByClassName('UIAButton')
|
||||
.then(function (buttons) { return buttons[3].click(); })
|
||||
driver
|
||||
.elementByAccessibilityId('show alert').click()
|
||||
.sleep(2000)
|
||||
.alertText()
|
||||
.should.be.rejectedWith(/status: 27/)
|
||||
|
||||
@@ -52,7 +52,7 @@ describe('testapp - basics - calc app 2', function () {
|
||||
});
|
||||
|
||||
// TODO: Fails on sauce, investigate
|
||||
it('should be able to get syslog logs @skip-ios6 @skip-ci', function (done) {
|
||||
it('should be able to get syslog logs @skip-ios6 @skip-ios8 @skip-ci', function (done) {
|
||||
driver
|
||||
.setImplicitWaitTimeout(4000)
|
||||
.elementByName('SumLabelz')
|
||||
|
||||
@@ -1,41 +1,59 @@
|
||||
"use strict";
|
||||
|
||||
var setup = require("../../common/setup-base"),
|
||||
_ = require('underscore'),
|
||||
var _ = require('underscore'),
|
||||
initSession = require('../../../helpers/session').initSession,
|
||||
should = require('chai').should(),
|
||||
desired = require('./desired');
|
||||
|
||||
require('../../../helpers/setup-chai.js');
|
||||
|
||||
describe('testapp - device', function () {
|
||||
|
||||
describe('target actions', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
it("should die in background and respond within (+/- 6 secs)", function (done) {
|
||||
var before;
|
||||
driver
|
||||
.sleep(5000)
|
||||
.then(function () { before = new Date().getTime() / 1000; })
|
||||
.backgroundApp(1)
|
||||
.catch(function (err) {
|
||||
err.cause.value.message.should.contain("Instruments died");
|
||||
throw err;
|
||||
}).should.be.rejectedWith(/status: 13/)
|
||||
.then(function () { ((new Date().getTime() / 1000) - before).should.be.below(10); })
|
||||
.sleep(5000) // cooldown
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deviceName @skip-ios6', function () {
|
||||
describe('invalid deviceName @skip-ios6', function () {
|
||||
var newDesired = _.extend(_.clone(desired), {deviceName: "iFailure 3.5-inch"});
|
||||
var session = initSession(newDesired, {'no-retry': true});
|
||||
|
||||
it('should fail gracefully with an invalid deviceName', function (done) {
|
||||
session.setUp()
|
||||
.should.be.rejectedWith(/environment you requested was unavailable/)
|
||||
.should.eventually.be.rejectedWith(/environment you requested was unavailable/)
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
_.each(['iPhone', 'iPad'], function (device) {
|
||||
describe('generic ' + device + ' deviceName @skip-ios6', function () {
|
||||
var newDesired = _.extend(_.clone(desired), {
|
||||
deviceName: device + " Simulator"
|
||||
});
|
||||
var session = initSession(newDesired, {'no-retry': true});
|
||||
|
||||
after(function (done) {
|
||||
session.tearDown(this.currentTest.state === 'passed').nodeify(done);
|
||||
});
|
||||
|
||||
it('should work with a generic ' + device + ' deviceName', function (done) {
|
||||
session.setUp()
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("real device", function () {
|
||||
var newDesired = _.extend(_.clone(desired), {
|
||||
deviceName: "BadSimulator",
|
||||
udid: "12341234123412341234"
|
||||
});
|
||||
var session = initSession(newDesired, {'no-retry': true});
|
||||
it("shouldn't try to validate against sims", function (done) {
|
||||
session.setUp()
|
||||
.nodeify(function (err) {
|
||||
should.exist(err);
|
||||
var data = JSON.parse(err.data);
|
||||
data.value.origValue.should.not.contain("BadSimulator");
|
||||
err.message.should.contain("requested was unavailable");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -129,14 +129,4 @@ describe('testapp - find element', function () {
|
||||
driver.elementsByName('AppElem').should.eventually.have.length(3)
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
it('should find an element within its parent', function (done) {
|
||||
// there are 2 textfields with the same name imbricated.
|
||||
driver
|
||||
.elementById('TextField2').then(function (parent) {
|
||||
parent.should.exist;
|
||||
return parent.elementById('TextField2').should.eventually.exist;
|
||||
})
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ describe("testapp - keyboard stability @skip-ci", function () {
|
||||
|
||||
var driver;
|
||||
setup(this, _.defaults({
|
||||
deviceName: 'iPad Simulator',
|
||||
deviceName: 'iPad 2',
|
||||
}, desired)).then(function (d) { driver = d; });
|
||||
|
||||
var test = function () {
|
||||
|
||||
@@ -7,7 +7,7 @@ var env = require('../../../../helpers/env'),
|
||||
rimraf = require('rimraf'),
|
||||
path = require('path');
|
||||
|
||||
describe('localization - calendarFormat', function () {
|
||||
describe('localization - calendarFormat @skip-ios8', function () {
|
||||
this.timeout(env.MOCHA_INIT_TIMEOUT);
|
||||
|
||||
after(function () {
|
||||
@@ -19,7 +19,7 @@ describe('localization - calendarFormat', function () {
|
||||
|
||||
describe('changing to gregorian calendar', function () {
|
||||
var driver;
|
||||
setup(this, _.defaults({calendarFormat: 'gregorian'} , desired)).then(function (d) { driver = d; });
|
||||
setup(this, _.defaults({calendarFormat: 'gregorian'}, desired)).then(function (d) { driver = d; });
|
||||
|
||||
it('should have gregorian calendar format', function (done) {
|
||||
driver.execute('$.mainApp().preferencesValueForKey("AppleLocale");')
|
||||
@@ -30,7 +30,7 @@ describe('localization - calendarFormat', function () {
|
||||
|
||||
describe('changing to buddhist calendar', function () {
|
||||
var driver;
|
||||
setup(this, _.defaults({calendarFormat: 'buddhist'} , desired)).then(function (d) { driver = d; });
|
||||
setup(this, _.defaults({calendarFormat: 'buddhist'}, desired)).then(function (d) { driver = d; });
|
||||
|
||||
it('should have buddhist calendar format', function (done) {
|
||||
driver.execute('$.mainApp().preferencesValueForKey("AppleLocale");')
|
||||
|
||||
@@ -7,7 +7,7 @@ var env = require('../../../../helpers/env'),
|
||||
rimraf = require('rimraf'),
|
||||
path = require('path');
|
||||
|
||||
describe('localization - language', function () {
|
||||
describe('localization - language @skip-ios8', function () {
|
||||
this.timeout(env.MOCHA_INIT_TIMEOUT);
|
||||
|
||||
after(function () {
|
||||
@@ -19,7 +19,7 @@ describe('localization - language', function () {
|
||||
|
||||
describe('changing to fr', function () {
|
||||
var driver;
|
||||
setup(this, _.defaults({language: 'fr'} , desired)).then(function (d) { driver = d; });
|
||||
setup(this, _.defaults({language: 'fr'}, desired)).then(function (d) { driver = d; });
|
||||
|
||||
it('should be fr', function (done) {
|
||||
driver.execute('$.mainApp().preferencesValueForKey("AppleLanguages")[0];')
|
||||
@@ -30,7 +30,7 @@ describe('localization - language', function () {
|
||||
|
||||
describe('changing to de', function () {
|
||||
var driver;
|
||||
setup(this, _.defaults({language: 'de'} , desired)).then(function (d) { driver = d; });
|
||||
setup(this, _.defaults({language: 'de'}, desired)).then(function (d) { driver = d; });
|
||||
|
||||
it('should be de', function (done) {
|
||||
driver.execute('$.mainApp().preferencesValueForKey("AppleLanguages")[0];')
|
||||
|
||||
@@ -20,7 +20,9 @@ describe('localization - locale', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
it('should be english', function (done) {
|
||||
it('should be english @skip-ios8', function (done) {
|
||||
// ios8 doesn't do default locale; it will be whatever was last in
|
||||
// the sim
|
||||
driver.execute('$.mainApp().preferencesValueForKey("AppleLocale");')
|
||||
.should.become('en_US')
|
||||
.nodeify(done);
|
||||
@@ -29,7 +31,7 @@ describe('localization - locale', function () {
|
||||
|
||||
describe('changing locale', function () {
|
||||
var driver;
|
||||
setup(this, _.defaults({locale: 'fr'} , desired)).then(function (d) { driver = d; });
|
||||
setup(this, _.defaults({locale: 'fr'}, desired)).then(function (d) { driver = d; });
|
||||
|
||||
it('should be fr', function (done) {
|
||||
driver.execute('$.mainApp().preferencesValueForKey("AppleLocale");')
|
||||
@@ -40,7 +42,7 @@ describe('localization - locale', function () {
|
||||
|
||||
describe('changing back', function () {
|
||||
var driver;
|
||||
setup(this, _.defaults({locale: 'en_US'} , desired)).then(function (d) { driver = d; });
|
||||
setup(this, _.defaults({locale: 'en_US'}, desired)).then(function (d) { driver = d; });
|
||||
|
||||
it('should be en', function (done) {
|
||||
driver.execute('$.mainApp().preferencesValueForKey("AppleLocale");')
|
||||
|
||||
@@ -16,7 +16,8 @@ describe('testapp - location - 1 @skip-ci', function () {
|
||||
it('should return the right x/y coordinates', function (done) {
|
||||
driver
|
||||
.elementByClassName('UIAButton').getLocation().then(function (location) {
|
||||
location.x.should.equal(94);
|
||||
var possibleLocs = [94, 110]; // 110 is for iphone 6
|
||||
possibleLocs.should.contain(parseInt(location.x, 10));
|
||||
location.y.should.be.above(120);
|
||||
})
|
||||
.nodeify(done);
|
||||
|
||||
@@ -11,8 +11,8 @@ describe('testapp - size', function () {
|
||||
|
||||
it('should return the right element size', function (done) {
|
||||
driver.elementByClassName('UIAButton').getSize().then(function (size) {
|
||||
size.width.should.eql(113);
|
||||
size.height.should.eql(37);
|
||||
size.width.should.be.above(112);
|
||||
size.height.should.be.above(36);
|
||||
}).nodeify(done);
|
||||
});
|
||||
|
||||
|
||||
@@ -3,19 +3,26 @@
|
||||
var setup = require("../../common/setup-base")
|
||||
, xpath = require("xpath")
|
||||
, XMLDom = require("xmldom").DOMParser
|
||||
, ChaiAsserter = require("../../../helpers/asserter").ChaiAsserter
|
||||
, desired = require('./desired');
|
||||
|
||||
var sourceIsRight = function (driver) {
|
||||
return new ChaiAsserter(function () {
|
||||
return driver.source().then(function (source) {
|
||||
var dom = new XMLDom().parseFromString(source);
|
||||
var nodes = xpath.select('//UIAButton', dom);
|
||||
nodes.length.should.equal(7);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
describe('testapp - source', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
it('should return page source', function (done) {
|
||||
driver
|
||||
.source()
|
||||
.then(function (source) {
|
||||
var dom = new XMLDom().parseFromString(source);
|
||||
var nodes = xpath.select('//UIAButton', dom);
|
||||
nodes.length.should.equal(7);
|
||||
}).nodeify(done);
|
||||
.waitFor(sourceIsRight(driver), 3000)
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* global should:true */
|
||||
|
||||
"use strict";
|
||||
|
||||
var setup = require("../../../common/setup-base"),
|
||||
@@ -11,23 +13,40 @@ describe('testapp - timeout', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
var impWaitCheck = function (impWaitMs) {
|
||||
var impWaitCheck = function (strat, sel, impWaitMs) {
|
||||
return function () {
|
||||
var before = new Date().getTime();
|
||||
return driver
|
||||
.elementsByClassName('UIANotGonnaBeThere').then(function (missing) {
|
||||
var after = new Date().getTime();
|
||||
(after - before).should.be.below(impWaitMs + 2000);
|
||||
(after - before).should.be.above(impWaitMs);
|
||||
missing.should.have.length(0);
|
||||
});
|
||||
var method = driver['elementsBy' + strat](sel);
|
||||
return method.then(function (missing) {
|
||||
var after = new Date().getTime();
|
||||
(after - before).should.be.below(impWaitMs + 2000);
|
||||
(after - before).should.be.above(impWaitMs);
|
||||
missing.should.have.length(0);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
var impWaitCheckSingle = function (strat, sel, impWaitMs) {
|
||||
return function () {
|
||||
var before = new Date().getTime();
|
||||
var method = driver['elementBy' + strat](sel);
|
||||
return method.then(function (missing) {
|
||||
should.not.exist(missing);
|
||||
}).catch(function (err) {
|
||||
err.status.should.equal(7);
|
||||
var after = new Date().getTime();
|
||||
(after - before).should.be.below(impWaitMs + 2000);
|
||||
(after - before).should.be.above(impWaitMs);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
it('should set the implicit wait for finding elements', function (done) {
|
||||
driver
|
||||
.setImplicitWaitTimeout(4000)
|
||||
.then(impWaitCheck(4000))
|
||||
.then(impWaitCheck('ClassName', 'UIANotGonnaBeHere', 4000))
|
||||
.then(impWaitCheck('AccessibilityId', 'FoShoIAintHere', 4000))
|
||||
.then(impWaitCheckSingle('AccessibilityId', 'FoShoIAintHere', 4000))
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
@@ -35,7 +54,7 @@ describe('testapp - timeout', function () {
|
||||
driver
|
||||
.setCommandTimeout(5000)
|
||||
.setImplicitWaitTimeout(10000)
|
||||
.then(impWaitCheck(10000))
|
||||
.then(impWaitCheck('ClassName', 'UIANotGonnaBeHere', 10000))
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
@@ -43,10 +62,10 @@ describe('testapp - timeout', function () {
|
||||
driver
|
||||
.setCommandTimeout(60000)
|
||||
.setImplicitWaitTimeout(4000)
|
||||
.then(impWaitCheck(4000))
|
||||
.then(impWaitCheck('ClassName', 'UIANotGonnaBeHere', 4000))
|
||||
.resetApp()
|
||||
.sleep(3000) // cooldown
|
||||
.then(impWaitCheck)
|
||||
.then(impWaitCheck('ClassName', 'UIANotGonnaBeHere', 4000))
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ var options = {
|
||||
'force new connection': true
|
||||
};
|
||||
|
||||
describe('uicatalog - alerts @skip-ios7', function () {
|
||||
describe('uicatalog - alerts @skip-ios7up', function () {
|
||||
var alertTag = env.IOS7 ? '@label' : '@value';
|
||||
|
||||
var driver;
|
||||
|
||||
@@ -4,7 +4,7 @@ var env = require('../../../helpers/env')
|
||||
, setup = require("../../common/setup-base")
|
||||
, desired = require('./desired');
|
||||
|
||||
describe('uicatalog - basic @skip-ios7', function () {
|
||||
describe('uicatalog - basic @skip-ios7up', function () {
|
||||
|
||||
describe('api', function () {
|
||||
var driver;
|
||||
@@ -34,7 +34,7 @@ describe('uicatalog - basic @skip-ios7', function () {
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
it('should confirm element is selected @skip-ios7', function (done) {
|
||||
it('should confirm element is selected @skip-ios7up', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIATableCell/UIAStaticText[contains(@label, 'Pickers')]")
|
||||
.click()
|
||||
|
||||
@@ -4,7 +4,7 @@ var env = require('../../../helpers/env')
|
||||
, setup = require("../../common/setup-base")
|
||||
, desired = require('./desired');
|
||||
|
||||
describe('uicatalog - controls @skip-ios7', function () {
|
||||
describe('uicatalog - controls @skip-ios7up', function () {
|
||||
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
@@ -4,7 +4,7 @@ var env = require('../../../helpers/env'),
|
||||
setup = require("../../common/setup-base"),
|
||||
desired = require('./desired');
|
||||
|
||||
describe('uicatalog - device @skip-ios7', function () {
|
||||
describe('uicatalog - device @skip-ios7up', function () {
|
||||
|
||||
describe('lock device', function () {
|
||||
var driver;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var setup = require("../../common/setup-base"),
|
||||
desired = require('./desired');
|
||||
|
||||
describe('uicatalog - execute @skip-ios7', function () {
|
||||
describe('uicatalog - execute @skip-ios7up', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ var setup = require("../../common/setup-base")
|
||||
, _ = require("underscore")
|
||||
, spinWait = require("../../../helpers/spin.js").spinWait;
|
||||
|
||||
describe('uicatalog - find element @skip-ios7', function () {
|
||||
describe('uicatalog - find element @skip-ios7up', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ var env = require('../../../helpers/env')
|
||||
|
||||
var SLOW_DOWN_MS = 1000;
|
||||
|
||||
describe('uicatalog - gestures @skip-ios7', function () {
|
||||
describe('uicatalog - gestures @skip-ios7up', function () {
|
||||
|
||||
describe('flick @skip-ios7', function () {
|
||||
describe('flick @skip-ios7up', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
@@ -75,7 +75,7 @@ describe('uicatalog - gestures @skip-ios7', function () {
|
||||
}).nodeify(done);
|
||||
});
|
||||
});
|
||||
describe('swipe gesture @skip-ios7', function () {
|
||||
describe('swipe gesture @skip-ios7up', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
@@ -163,7 +163,7 @@ describe('uicatalog - gestures @skip-ios7', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("flick element @skip-ios7", function () {
|
||||
describe("flick element @skip-ios7up", function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
@@ -232,7 +232,7 @@ describe('uicatalog - gestures @skip-ios7', function () {
|
||||
}).nodeify(done);
|
||||
});
|
||||
});
|
||||
describe("swipe element @skip-ios7", function () {
|
||||
describe("swipe element @skip-ios7up", function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
@@ -314,7 +314,7 @@ describe('uicatalog - gestures @skip-ios7', function () {
|
||||
})
|
||||
.nodeify(done);
|
||||
});
|
||||
it('should work in relative units @skip-ios7', function (done) {
|
||||
it('should work in relative units @skip-ios7up', function (done) {
|
||||
var tapOpts = {
|
||||
tapCount: 1 // how many taps
|
||||
, duration: 2.3 // how long
|
||||
@@ -330,7 +330,7 @@ describe('uicatalog - gestures @skip-ios7', function () {
|
||||
})
|
||||
.nodeify(done);
|
||||
});
|
||||
it('should work with default options @skip-ios7', function (done) {
|
||||
it('should work with default options @skip-ios7up', function (done) {
|
||||
driver
|
||||
.execute("mobile: tap")
|
||||
.elementByClassName('UIATextView').text()
|
||||
@@ -387,7 +387,7 @@ describe('uicatalog - gestures @skip-ios7', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('scroll to element @skip-ios7', function () {
|
||||
describe('scroll to element @skip-ios7up', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ var env = require('../../../../helpers/env')
|
||||
, setup = require("../../../common/setup-base")
|
||||
, path = require('path');
|
||||
|
||||
describe('uicatalog - basic @skip-ios7', function () {
|
||||
describe('uicatalog - basic @skip-ios7up', function () {
|
||||
|
||||
describe('load zipped app', function () {
|
||||
var driver;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
var setup = require("../../../common/setup-base");
|
||||
|
||||
describe('uicatalog - basic @skip-ios7', function () {
|
||||
describe('uicatalog - basic @skip-ios7up', function () {
|
||||
|
||||
describe('load zipped app with relative path', function () {
|
||||
var driver;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
var setup = require("../../../common/setup-base");
|
||||
|
||||
describe('uicatalog - basic @skip-ios7', function () {
|
||||
describe('uicatalog - basic @skip-ios7up', function () {
|
||||
|
||||
describe('load zipped app via url', function () {
|
||||
var driver;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var setup = require("../../common/setup-base"),
|
||||
desired = require('./desired');
|
||||
|
||||
describe('uicatalog - move @skip-ios7', function () {
|
||||
describe('uicatalog - move @skip-ios7up', function () {
|
||||
|
||||
describe('moveTo and click', function () {
|
||||
var driver;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var setup = require("../../common/setup-base"),
|
||||
desired = require('./desired');
|
||||
|
||||
describe('uicatalog - reset @skip-ios7', function () {
|
||||
describe('uicatalog - reset @skip-ios7up', function () {
|
||||
|
||||
describe('app reset', function () {
|
||||
var driver;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var setup = require("../../common/setup-base"),
|
||||
desired = require('./desired');
|
||||
|
||||
describe('uicatalog - contexts @skip-ios7', function () {
|
||||
describe('uicatalog - contexts @skip-ios7up', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
|
||||
@@ -11,18 +11,18 @@ describe('uicatalog - basic @skip-ios6', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
// if (env.FAST_TESTS) {
|
||||
// beforeEach(function (done) {
|
||||
// driver
|
||||
// .back()
|
||||
// .nodeify(function () { done(); });
|
||||
// });
|
||||
// }
|
||||
if (env.FAST_TESTS) {
|
||||
beforeEach(function (done) {
|
||||
driver
|
||||
.back()
|
||||
.nodeify(function () { done(); });
|
||||
});
|
||||
}
|
||||
|
||||
it('should confirm element is not visible', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(" + textTag + ", 'Buttons')]").click()
|
||||
.elementByXPath("//UIAButton[contains(@name, 'UINavigationBarBackIndicatorDefault')]")
|
||||
.elementByXPath("//UIANavigationBar/UIAImage")
|
||||
.isDisplayed()
|
||||
.should.not.eventually.be.ok
|
||||
.nodeify(done);
|
||||
@@ -36,20 +36,20 @@ describe('uicatalog - basic @skip-ios6', function () {
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
it('should confirm element is selected @skip-ios7', function (done) {
|
||||
// TODO: review select implementation for ios7
|
||||
it('should confirm element is selected', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@label, 'Pickers')]").click()
|
||||
.elementByXPath("//UIAButton[contains(@label, 'UIPicker')]").isSelected()
|
||||
.execute("mobile: scroll", {direction: 'down'})
|
||||
.elementByXPath("//UIAStaticText[contains(@label, 'Switches')]").click()
|
||||
.elementByClassName("UIASwitch").isSelected()
|
||||
.should.eventually.be.ok
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
it('should confirm element is not selected returns false @skip-ios7', function (done) {
|
||||
// TODO: review select implementation for ios7
|
||||
it('should confirm element is not selected returns false', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@label, 'Pickers')]").click()
|
||||
.elementByXPath("//UIAButton[contains(@label, 'Custom')]").isSelected()
|
||||
.execute("mobile: scroll", {direction: 'down'})
|
||||
.elementByXPath("//UIAStaticText[contains(@label, 'Switches')]").click()
|
||||
.elementByClassName("UIASwitch").click().isSelected()
|
||||
.should.not.eventually.be.ok
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
@@ -16,7 +16,8 @@ describe('uicatalog - clear @skip-ios6', function () {
|
||||
|
||||
it('should be able to hide keyboard with the default strategy', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@name, 'Web View')]").moveTo(10, 10).click()
|
||||
.execute("mobile: scroll", {direction: 'down'})
|
||||
.elementByXPath("//UIAStaticText[contains(@name, 'Web View')]").click()
|
||||
.waitForElementByXPath('//UIANavigationBar[@name="Web View"]', 5000, 500)
|
||||
.elementByXPath("//UIATextField").click()
|
||||
.waitForElementByAccessibilityId("Go", 5000, 500)
|
||||
@@ -29,7 +30,8 @@ describe('uicatalog - clear @skip-ios6', function () {
|
||||
|
||||
it('should be able to hide keyboard with the tapOutside strategy', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@name, 'Web View')]").moveTo(10, 10).click()
|
||||
.execute("mobile: scroll", {direction: 'down'})
|
||||
.elementByXPath("//UIAStaticText[contains(@name, 'Web View')]").click()
|
||||
.waitForElementByXPath('//UIANavigationBar[@name="Web View"]', 5000, 500)
|
||||
.elementByXPath("//UIATextField").click()
|
||||
.waitForElementByAccessibilityId("Go", 5000, 500)
|
||||
@@ -42,7 +44,8 @@ describe('uicatalog - clear @skip-ios6', function () {
|
||||
|
||||
it('should be able to hide keyboard with the tapOut strategy', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@name, 'Web View')]").moveTo(10, 10).click()
|
||||
.execute("mobile: scroll", {direction: 'down'})
|
||||
.elementByXPath("//UIAStaticText[contains(@name, 'Web View')]").click()
|
||||
.waitForElementByXPath('//UIANavigationBar[@name="Web View"]', 5000, 500)
|
||||
.elementByXPath("//UIATextField").click()
|
||||
.waitForElementByAccessibilityId("Go", 5000, 500)
|
||||
|
||||
@@ -24,11 +24,11 @@ describe('uicatalog - controls @skip-ios6', function () {
|
||||
.then(function (wheel) {
|
||||
return wheel
|
||||
.getAttribute("value")
|
||||
.should.become("65. 14 of 52")
|
||||
.should.eventually.contain("65")
|
||||
.then(function () {
|
||||
return wheel.type("70")
|
||||
.getAttribute("value")
|
||||
.should.become("70. 15 of 52");
|
||||
.should.eventually.contain("70");
|
||||
});
|
||||
})
|
||||
.elementByXPath("//UIAPickerWheel[@name = 'Green color component value']")
|
||||
@@ -36,14 +36,14 @@ describe('uicatalog - controls @skip-ios6', function () {
|
||||
return wheel
|
||||
.type("70")
|
||||
.getAttribute("value")
|
||||
.should.become("70. 15 of 52");
|
||||
.should.eventually.contain("70");
|
||||
})
|
||||
.elementByXPath("//UIAPickerWheel[@name = 'Blue color component value']")
|
||||
.then(function (wheel) {
|
||||
return wheel
|
||||
.type("70")
|
||||
.getAttribute("value")
|
||||
.should.become("70. 15 of 52");
|
||||
.should.eventually.contain("70");
|
||||
})
|
||||
.elementByClassName("UIAPickerWheel")
|
||||
.getAttribute("values")
|
||||
@@ -59,7 +59,11 @@ describe('uicatalog - controls @skip-ios6', function () {
|
||||
.getAttribute("value").should.become('42%')
|
||||
.then(function () {
|
||||
return slider.sendKeys(0.8).getAttribute("value")
|
||||
.should.become('80%');
|
||||
.then(function (val) {
|
||||
var numeric = parseInt(val.replace('%', ''));
|
||||
numeric.should.be.above(75);
|
||||
numeric.should.be.below(85);
|
||||
});
|
||||
})
|
||||
;
|
||||
}).nodeify(done);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
var setup = require("../../common/setup-base")
|
||||
, env = require("../../../helpers/env.js")
|
||||
, desired = require('./desired')
|
||||
, _ = require('underscore');
|
||||
|
||||
@@ -8,44 +9,44 @@ describe('uicatalog - find - basics @skip-ios6', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
it('should find a single element by id @skip-ios7', function (done) {
|
||||
// ById is not avalable in ios7
|
||||
it('should find a single element by id', function (done) {
|
||||
driver
|
||||
.elementById('Date Picker')
|
||||
.should.eventually.exist
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
it('should find a single element by id wrapped in array for multi @skip-ios7', function (done) {
|
||||
// ById is not avalable in ios7
|
||||
it('should find a single element by id wrapped in array for multi', function (done) {
|
||||
driver
|
||||
.elementsById('Date Picker')
|
||||
.elementsById('Back')
|
||||
.then(function (els) {
|
||||
els.length.should.equal(1);
|
||||
})
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
it('should find a single element using elementByName @skip-ios7', function (done) {
|
||||
it('should find a single element using elementByAccessibilityId', function (done) {
|
||||
var axId = env.IOS8 ? 'AAPLImageViewController' :
|
||||
'Image View, AAPLImageViewController';
|
||||
driver
|
||||
.elementByName('Image View, AAPLImageViewController')
|
||||
.elementByAccessibilityId(axId)
|
||||
.then(function (el) {
|
||||
el.should.exist;
|
||||
}).nodeify(done);
|
||||
});
|
||||
it('should find an element within descendants @skip-ios7', function (done) {
|
||||
it('should find an element within descendants', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIATableCell[@name = 'Buttons, AAPLButtonViewController']")
|
||||
.elementByXPath("//UIATableCell[contains(@name, 'Buttons')]")
|
||||
.then(function (el) {
|
||||
el.should.exist;
|
||||
return el.elementByClassName('UIAStaticText').getAttribute('name')
|
||||
.should.become("Buttons, AAPLButtonViewController");
|
||||
.should.eventually.contain("Buttons");
|
||||
}).nodeify(done);
|
||||
});
|
||||
|
||||
it('should not find an element not within itself', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIATableCell[@name = 'Buttons, AAPLButtonViewController']")
|
||||
.elementByXPath("//UIATableCell[contains(@name, 'Buttons')]")
|
||||
.then(function (el) {
|
||||
el.should.exist;
|
||||
return el.elementByClassName('UIANavigationBar')
|
||||
@@ -54,18 +55,19 @@ describe('uicatalog - find - basics @skip-ios6', function () {
|
||||
});
|
||||
|
||||
it('should find some elements within itself', function (done) {
|
||||
var elLength = env.IOS8 ? 2 : 1;
|
||||
driver
|
||||
.elementByXPath("//UIATableCell[@name = 'Buttons, AAPLButtonViewController']")
|
||||
.elementByXPath("//UIATableCell[contains(@name, 'Buttons')]")
|
||||
.then(function (el) {
|
||||
el.should.exist;
|
||||
return el.elementsByClassName('UIAStaticText')
|
||||
.should.eventually.have.length(1);
|
||||
.should.eventually.have.length(elLength);
|
||||
}).nodeify(done);
|
||||
});
|
||||
|
||||
it('should not find elements not within itself', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIATableCell[@name = 'Buttons, AAPLButtonViewController']")
|
||||
.elementByXPath("//UIATableCell[contains(@name, 'Buttons')]")
|
||||
.then(function (el) {
|
||||
el.should.exist;
|
||||
el.elementsByClassName('UIANavigationBar')
|
||||
@@ -124,72 +126,71 @@ describe('uicatalog - find - basics @skip-ios6', function () {
|
||||
driver.clickButton('UICatalog')
|
||||
.nodeify(done);
|
||||
});
|
||||
var axIdExt = env.IOS8 ? '' : ', AAPLActionSheetViewController';
|
||||
it('should find only one textfield', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@label,'Action Sheets')]").click()
|
||||
.elementByName('Okay / Cancel')
|
||||
.elementByAccessibilityId("Action Sheets" + axIdExt).click()
|
||||
.elementByAccessibilityId('Okay / Cancel')
|
||||
.elementsByClassName('>', 'UIAStaticText')
|
||||
.should.eventually.have.length(1)
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findElement(s) containing name', function () {
|
||||
after(function (done) {
|
||||
describe('findElement(s) containing accessibility id', function () {
|
||||
afterEach(function (done) {
|
||||
driver
|
||||
.elementByName('UICatalog').click()
|
||||
.clickButton('UICatalog')
|
||||
.sleep(1000)
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
var axIdExt = env.IOS8 ? '' : ', AAPLActionSheetViewController';
|
||||
it('should find one element', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@label,'Action Sheets')]").click()
|
||||
.elementByName('*Okay*').getAttribute('name')
|
||||
.elementByAccessibilityId("Action Sheets" + axIdExt).click()
|
||||
.elementByAccessibilityId('Okay / Cancel').getAttribute('name')
|
||||
.should.become('Okay / Cancel')
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
it('should find several element', function (done) {
|
||||
it('should find several elements', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@label,'Action Sheets')]").click()
|
||||
.elementsByName('*Okay*')
|
||||
.elementByAccessibilityId("Action Sheets" + axIdExt).click()
|
||||
.elementsByAccessibilityId('Okay / Cancel')
|
||||
.should.eventually.have.length(2)
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('duplicate text field', function () {
|
||||
after(function (done) {
|
||||
afterEach(function (done) {
|
||||
driver
|
||||
.elementByName('UICatalog').click()
|
||||
.clickButton('UICatalog')
|
||||
.sleep(1000)
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
it('should find only one text field', function (done) {
|
||||
var axIdExt = env.IOS8 ? '' : ', AAPLTextFieldViewController';
|
||||
it('should find only one element per text field', function (done) {
|
||||
driver
|
||||
.waitForElementByName('*Text Fields*', 3000, 500).click()
|
||||
.execute("mobile: scroll", {direction: 'down'})
|
||||
.waitForElementByAccessibilityId('Text Fields' + axIdExt, 3000, 500)
|
||||
.click()
|
||||
.sleep(2000)
|
||||
.elementByName('Empty list')
|
||||
.elementByClassName('>','UIATableCell')
|
||||
.elementsByClassName('>','UIATextField')
|
||||
.should.eventually.have.length(1)
|
||||
.elementsByClassName('UIATextField')
|
||||
.should.eventually.have.length(4)
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
it('should find only one secure text field', function (done) {
|
||||
it('should find only one element per secure text field', function (done) {
|
||||
driver
|
||||
.waitForElementByName('*Text Fields*', 3000, 500).click()
|
||||
.waitForElementByAccessibilityId('Text Fields' + axIdExt, 3000, 500)
|
||||
.click()
|
||||
.sleep(2000)
|
||||
.elementByName('Empty list')
|
||||
.elementsByClassName('>','UIATableCell').at(2)
|
||||
.elementsByClassName('>','UIASecureTextField')
|
||||
.should.eventually.have.length(1)
|
||||
.elementsByClassName('UIASecureTextField')
|
||||
.should.eventually.have.length(1)
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
var setup = require("../../common/setup-base")
|
||||
, env = require('../../../helpers/env.js')
|
||||
, desired = require('./desired');
|
||||
|
||||
describe('uicatalog - find by accessibility id @skip-ios6', function () {
|
||||
@@ -11,37 +12,12 @@ describe('uicatalog - find by accessibility id @skip-ios6', function () {
|
||||
driver.clickButton('UICatalog')
|
||||
.nodeify(done);
|
||||
});
|
||||
it('should find an element', function (done) {
|
||||
driver.element('accessibility id', 'UICatalog').then(function (el) {
|
||||
el.should.exist;
|
||||
}).nodeify(done);
|
||||
});
|
||||
it('should find a deeply nested element', function (done) {
|
||||
|
||||
it('should find an element by name beneath another element', function (done) {
|
||||
var axIdExt = env.IOS8 ? '' : ', AAPLActionSheetViewController';
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@label,'Action Sheets')]").click()
|
||||
.element('accessibility id', 'Okay / Cancel').then(function (el) {
|
||||
el.should.exist;
|
||||
})
|
||||
.nodeify(done);
|
||||
});
|
||||
it('should find an element by name beneath another element @skip-ios7', function (done) {
|
||||
// TODO: this does not work
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@label,'Action Sheets')]").click()
|
||||
.element('accessibility id', 'Empty list').then(function (el) {
|
||||
el.element('accessibility id', 'Other')
|
||||
.then(function (innerEl) {
|
||||
innerEl.should.exist;
|
||||
})
|
||||
.elementByAccessibilityId("UICatalog").click()
|
||||
.elementByAccessibilityId("Action Sheets" + axIdExt)
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
it('should return an array of one element if the plural "elements" is used', function (done) {
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@label,'Action Sheets')]").click()
|
||||
.elements('accessibility id', 'Okay / Cancel').then(function (els) {
|
||||
els.length.should.equal(2);
|
||||
})
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
var setup = require("../../common/setup-base")
|
||||
, desired = require('./desired')
|
||||
, env = require('../../../helpers/env.js')
|
||||
, Q = require("q")
|
||||
, _ = require("underscore")
|
||||
, filterVisible = require('../../../helpers/ios-uiautomation').filterVisible;
|
||||
@@ -36,7 +37,7 @@ describe('uicatalog - find by ios-ui-automation @skip-ios6', function () {
|
||||
.should.eventually.have.length(2)
|
||||
.nodeify(done);
|
||||
});
|
||||
it('should use raw selector code if selector doesn\'t start with a dot' , function (done) {
|
||||
it('should use raw selector code if selector doesn\'t start with a dot', function (done) {
|
||||
driver
|
||||
.elements(byUIA, '$.mainWindow().elements()').then(filterDisplayed)
|
||||
.should.eventually.have.length(2)
|
||||
@@ -47,9 +48,10 @@ describe('uicatalog - find by ios-ui-automation @skip-ios6', function () {
|
||||
.should.become('UICatalog')
|
||||
.nodeify(done);
|
||||
});
|
||||
it('should get a single element', function (done) {
|
||||
it('should get a single element with non-zero index', function (done) {
|
||||
var variableName = env.IOS8 ? '' : 'Empty list';
|
||||
driver.element(byUIA, '.elements()[1]').getAttribute('name')
|
||||
.should.become('Empty list')
|
||||
.should.become(variableName)
|
||||
.nodeify(done);
|
||||
});
|
||||
it('should get single element as array', function (done) {
|
||||
@@ -61,8 +63,7 @@ describe('uicatalog - find by ios-ui-automation @skip-ios6', function () {
|
||||
it('should find elements by index multiple times', function (done) {
|
||||
driver
|
||||
.element(byUIA, '.elements()[1].cells()[2]').getAttribute('name')
|
||||
// TODO: the cells index looks wrong, should start at 1, investigate
|
||||
.should.become('Alert Views, AAPLAlertViewController')
|
||||
.should.eventually.contain('Alert Views')
|
||||
.nodeify(done);
|
||||
});
|
||||
it('should find elements by name', function (done) {
|
||||
@@ -70,10 +71,9 @@ describe('uicatalog - find by ios-ui-automation @skip-ios6', function () {
|
||||
.should.become('UICatalog')
|
||||
.nodeify(done);
|
||||
});
|
||||
it('should find elements by name and index', function (done) {
|
||||
driver.element(byUIA, '.elements()["Empty list"].cells()[3]').getAttribute('name')
|
||||
// TODO: the cells index looks wrong, should start at 1, investigate
|
||||
.should.become('Buttons, AAPLButtonViewController')
|
||||
it('should find elements by type and index', function (done) {
|
||||
driver.element(byUIA, '.navigationBar().elements()[1]').getAttribute('name')
|
||||
.should.become('Back')
|
||||
.nodeify(done);
|
||||
});
|
||||
describe('start from a given context instead of root target', function () {
|
||||
@@ -86,9 +86,10 @@ describe('uicatalog - find by ios-ui-automation @skip-ios6', function () {
|
||||
});
|
||||
});
|
||||
it('should find elements by name', function (done) {
|
||||
var axIdExt = env.IOS8 ? "" : ", AAPLButtonViewController";
|
||||
driver.element(byUIA, '.elements()[1]').then(function (el) {
|
||||
el
|
||||
.element(byUIA, '.elements()["Buttons, AAPLButtonViewController"]')
|
||||
.element(byUIA, '.elements()["Buttons' + axIdExt + '"]')
|
||||
.should.eventually.exist
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ var env = require('../../../../helpers/env')
|
||||
|
||||
var SLOW_DOWN_MS = 1000;
|
||||
|
||||
describe('uicatalog - gestures - flick @skip-ios7 @skip-ios6', function () {
|
||||
describe('uicatalog - gestures - flick @skip-ios8 @skip-ios7 @skip-ios6', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
@@ -22,11 +22,11 @@ describe('uicatalog - gestures - flick @skip-ios7 @skip-ios6', function () {
|
||||
|
||||
it('should work via webdriver method', function (done) {
|
||||
driver
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location1) {
|
||||
return driver
|
||||
.flick(0, -100, false)
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location2) {
|
||||
location2.x.should.equal(location1.x);
|
||||
location2.y.should.not.equal(location1.y);
|
||||
@@ -35,11 +35,11 @@ describe('uicatalog - gestures - flick @skip-ios7 @skip-ios6', function () {
|
||||
});
|
||||
it('should work via mobile only method', function (done) {
|
||||
driver
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location1) {
|
||||
return driver
|
||||
.execute("mobile: flick", [{endX: 0, endY: 0}])
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location2) {
|
||||
location2.x.should.equal(location1.x);
|
||||
location2.y.should.not.equal(location1.y);
|
||||
@@ -56,11 +56,11 @@ describe('uicatalog - gestures - flick @skip-ios7 @skip-ios6', function () {
|
||||
it('should work via mobile only method with percentage', function (done) {
|
||||
var opts = {startX: 0.75, startY: 0.75, endX: 0.25, endY: 0.25};
|
||||
driver
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location1) {
|
||||
return driver
|
||||
.execute("mobile: flick", [opts])
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location2) {
|
||||
location2.x.should.equal(location1.x);
|
||||
location2.y.should.not.equal(location1.y);
|
||||
|
||||
@@ -11,12 +11,12 @@ describe('uicatalog - gestures - mobile scroll @skip-ios6', function () {
|
||||
var firstEl, location1, location2;
|
||||
driver
|
||||
.elementByClassName('UIATableCell')
|
||||
.then(function (el) { firstEl = el; return el.getLocation(); })
|
||||
.then(function (el) { firstEl = el; return el.getLocationInView(); })
|
||||
.then(function (loc) { location1 = loc; })
|
||||
.then(function () {
|
||||
return driver.execute("mobile: scroll", [{direction: 'down'}]);
|
||||
})
|
||||
.then(function () { return firstEl.getLocation(); })
|
||||
.then(function () { return firstEl.getLocationInView(); })
|
||||
.then(function (loc2) {
|
||||
location2 = loc2;
|
||||
loc2.x.should.equal(location1.x);
|
||||
@@ -25,7 +25,7 @@ describe('uicatalog - gestures - mobile scroll @skip-ios6', function () {
|
||||
.then(function () {
|
||||
return driver.execute("mobile: scroll", [{direction: 'up'}]);
|
||||
})
|
||||
.then(function () { return firstEl.getLocation(); })
|
||||
.then(function () { return firstEl.getLocationInView(); })
|
||||
.then(function (loc3) {
|
||||
loc3.x.should.equal(location2.x);
|
||||
loc3.y.should.not.equal(location2.y);
|
||||
@@ -38,12 +38,12 @@ describe('uicatalog - gestures - mobile scroll @skip-ios6', function () {
|
||||
table_view = el;
|
||||
})
|
||||
.elementByClassName('UIATableCell')
|
||||
.then(function (el) { firstEl = el; return el.getLocation(); })
|
||||
.then(function (el) { firstEl = el; return el.getLocationInView(); })
|
||||
.then(function (loc) { location1 = loc; })
|
||||
.then(function () {
|
||||
return driver.execute("mobile: scroll", [{element: table_view.value, direction: 'down'}]);
|
||||
})
|
||||
.then(function () { return firstEl.getLocation(); })
|
||||
.then(function () { return firstEl.getLocationInView(); })
|
||||
.then(function (loc2) {
|
||||
location2 = loc2;
|
||||
loc2.x.should.equal(location1.x);
|
||||
@@ -52,7 +52,7 @@ describe('uicatalog - gestures - mobile scroll @skip-ios6', function () {
|
||||
.then(function () {
|
||||
return driver.execute("mobile: scroll", [{element: table_view.value, direction: 'up'}]);
|
||||
})
|
||||
.then(function () { return firstEl.getLocation(); })
|
||||
.then(function () { return firstEl.getLocationInView(); })
|
||||
.then(function (loc3) {
|
||||
loc3.x.should.equal(location2.x);
|
||||
loc3.y.should.not.equal(location2.y);
|
||||
|
||||
@@ -1,36 +1,23 @@
|
||||
"use strict";
|
||||
|
||||
var env = require('../../../../helpers/env')
|
||||
, setup = require("../../../common/setup-base")
|
||||
var setup = require("../../../common/setup-base")
|
||||
, desired = require('../desired');
|
||||
|
||||
var SLOW_DOWN_MS = 1000;
|
||||
|
||||
describe('uicatalog - gestures - scroll to el @skip-ios7 @skip-ios6', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
if (env.FAST_TESTS) {
|
||||
afterEach(function (done) {
|
||||
driver
|
||||
.flick(0, 100, false)
|
||||
.flick(0, 100, false)
|
||||
.sleep(SLOW_DOWN_MS)
|
||||
.nodeify(done);
|
||||
});
|
||||
}
|
||||
|
||||
it('should bring the element into view', function (done) {
|
||||
var el, scrollOpts, location1;
|
||||
driver.elementsByClassName('UIATableCell').then(function (els) {
|
||||
el = els[10];
|
||||
scrollOpts = { element: el.value };
|
||||
})
|
||||
.then(function () { return el.getLocation(); })
|
||||
.then(function () { return el.getLocationInView(); })
|
||||
.then(function (loc) { location1 = loc; })
|
||||
.then(function () {
|
||||
return driver.execute("mobile: scrollTo", [scrollOpts]);
|
||||
}).then(function () { return el.getLocation(); })
|
||||
}).then(function () { return el.getLocationInView(); })
|
||||
.then(function (location2) {
|
||||
location2.x.should.equal(location1.x);
|
||||
location2.y.should.not.equal(location1.y);
|
||||
|
||||
@@ -14,18 +14,23 @@ describe("uicatalog - gestures - swipe element @skip-ios7 @skip-ios6", function
|
||||
afterEach(function (done) {
|
||||
driver
|
||||
.elementByClassName("UIASlider")
|
||||
.then(function (el) { if (el) return el.sendKeys(0.5); })
|
||||
.clickBack()
|
||||
.then(function (el) { if (el) return el.sendKeys(0.42); })
|
||||
.clickButton('UICatalog')
|
||||
.sleep(SLOW_DOWN_MS)
|
||||
.nodeify(done);
|
||||
});
|
||||
}
|
||||
|
||||
var getNumericValue = function (pctVal) {
|
||||
pctVal = pctVal.replace("%", "");
|
||||
pctVal = parseInt(pctVal, 10);
|
||||
return pctVal;
|
||||
};
|
||||
|
||||
it("slider value should change", function (done) {
|
||||
var valueBefore, slider;
|
||||
driver
|
||||
.elementsByClassName('UIATableCell').then(function (els) { return els[1]; })
|
||||
.click()
|
||||
.elementByAccessibilityId('Sliders').click()
|
||||
.elementByClassName("UIASlider").then(function (el) { slider = el; })
|
||||
.then(function () { return slider.getAttribute("value"); })
|
||||
.then(function (value) { valueBefore = value; })
|
||||
@@ -36,15 +41,17 @@ describe("uicatalog - gestures - swipe element @skip-ios7 @skip-ios6", function
|
||||
})
|
||||
.then(function () { return slider.getAttribute("value"); })
|
||||
.then(function (valueAfter) {
|
||||
valueBefore.should.equal("50%");
|
||||
valueAfter.should.equal("20%");
|
||||
valueBefore.should.equal("42%");
|
||||
valueAfter = getNumericValue(valueAfter);
|
||||
// should be around 20
|
||||
valueAfter.should.be.above(15);
|
||||
valueAfter.should.be.below(25);
|
||||
}).nodeify(done);
|
||||
});
|
||||
it("slider value should change by pixels", function (done) {
|
||||
var valueBefore, slider;
|
||||
driver
|
||||
.elementsByClassName('UIATableCell').then(function (els) { return els[1]; })
|
||||
.click()
|
||||
.elementByAccessibilityId('Sliders').click()
|
||||
.elementByClassName("UIASlider").then(function (el) { slider = el; })
|
||||
.then(function () { return slider.getAttribute("value"); })
|
||||
.then(function (value) { valueBefore = value; })
|
||||
@@ -54,8 +61,10 @@ describe("uicatalog - gestures - swipe element @skip-ios7 @skip-ios6", function
|
||||
})
|
||||
.then(function () { return slider.getAttribute("value"); })
|
||||
.then(function (valueAfter) {
|
||||
valueBefore.should.equal("50%");
|
||||
valueAfter.should.equal("5%");
|
||||
valueBefore.should.equal("42%");
|
||||
valueAfter = getNumericValue(valueAfter);
|
||||
// should be around 5
|
||||
valueAfter.should.be.below(8);
|
||||
}).nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ var env = require('../../../../helpers/env')
|
||||
|
||||
var SLOW_DOWN_MS = 1000;
|
||||
|
||||
describe('uicatalog - gestures - swipe @skip-ios7 @skip-ios6', function () {
|
||||
describe('uicatalog - gestures - swipe @skip-ios8 @skip-ios7 @skip-ios6', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
@@ -22,12 +22,12 @@ describe('uicatalog - gestures - swipe @skip-ios7 @skip-ios6', function () {
|
||||
}
|
||||
it('should work with wd function in pixels', function (done) {
|
||||
driver
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location1) {
|
||||
return spinWait(function () {
|
||||
return driver
|
||||
.flick(0, -70, true)
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location2) {
|
||||
((location2.x === location1.x) &&
|
||||
(location2.y !== location1.y)
|
||||
@@ -39,13 +39,13 @@ describe('uicatalog - gestures - swipe @skip-ios7 @skip-ios6', function () {
|
||||
});
|
||||
it('should work with wd function in percent', function (done) {
|
||||
driver
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location1) {
|
||||
return driver
|
||||
.flick(0, -0.1, true) // flaky
|
||||
.flick(0, -0.1, true)
|
||||
.flick(0, -0.1, true)
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location2) {
|
||||
location2.x.should.equal(location1.x);
|
||||
location2.y.should.not.equal(location1.y, '===y');
|
||||
@@ -55,12 +55,12 @@ describe('uicatalog - gestures - swipe @skip-ios7 @skip-ios6', function () {
|
||||
it('should work with mobile function in pixels', function (done) {
|
||||
var opts = {startX: 50, startY: 400, endX: 50, endY: 300, duration: 2};
|
||||
driver
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location1) {
|
||||
return spinWait(function () {
|
||||
return driver
|
||||
.execute("mobile: swipe", [opts])
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location2) {
|
||||
location2.x.should.equal(location1.x);
|
||||
location2.y.should.not.equal(location1.y);
|
||||
@@ -71,12 +71,12 @@ describe('uicatalog - gestures - swipe @skip-ios7 @skip-ios6', function () {
|
||||
it('should work with mobile function in percent', function (done) {
|
||||
var opts = {startX: 0.5, startY: 0.9, endX: 0.5, endY: 0.7, duration: 2};
|
||||
driver
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location1) {
|
||||
return spinWait(function () {
|
||||
return driver
|
||||
.execute("mobile: swipe", [opts])
|
||||
.elementByClassName('UIATableCell').getLocation()
|
||||
.elementByClassName('UIATableCell').getLocationInView()
|
||||
.then(function (location2) {
|
||||
location2.x.should.equal(location1.x);
|
||||
location2.y.should.not.equal(location1.y);
|
||||
|
||||
@@ -8,7 +8,7 @@ var env = require('../../../../helpers/env')
|
||||
|
||||
describe('uicatalog - load app with absolute path @skip-ios6', function () {
|
||||
var driver;
|
||||
var appPath = path.resolve(env.SAUCE? '/Users/chef/appium' : process.cwd(), desired.app);
|
||||
var appPath = path.resolve(env.SAUCE ? '/Users/chef/appium' : process.cwd(), desired.app);
|
||||
setup(this, _.defaults({'app': appPath}, desired))
|
||||
.then(function (d) { driver = d; });
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ var env = require('../../../../helpers/env')
|
||||
|
||||
describe('uicatalog - load zipped app @skip-ios6', function () {
|
||||
var driver;
|
||||
var appZip = path.resolve(env.SAUCE? '/Users/chef/appium' : process.cwd(), 'assets/UICatalog6.0.app.zip');
|
||||
var appZip = path.resolve(env.SAUCE ? '/Users/chef/appium' : process.cwd(), 'assets/UICatalog7.1.app.zip');
|
||||
setup(this, {app: appZip})
|
||||
.then(function (d) { driver = d; });
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ var setup = require("../../../common/setup-base");
|
||||
|
||||
describe('uicatalog - load zipped app with relative path @skip-ios6', function () {
|
||||
var driver;
|
||||
var appZip = "assets/UICatalog6.0.app.zip";
|
||||
var appZip = "assets/UICatalog7.1.app.zip";
|
||||
setup(this, {app: appZip})
|
||||
.then(function (d) { driver = d; });
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ var setup = require("../../../common/setup-base");
|
||||
|
||||
describe('uicatalog - load zipped app via url @skip-ios6', function () {
|
||||
var driver;
|
||||
var appUrl = 'http://appium.s3.amazonaws.com/UICatalog6.0.app.zip';
|
||||
var appUrl = 'http://appium.s3.amazonaws.com/WebViewApp7.1.app.zip';
|
||||
setup(this, {app: appUrl})
|
||||
.then(function (d) { driver = d; });
|
||||
|
||||
it('should load a zipped app via url', function (done) {
|
||||
driver
|
||||
.elementByClassName('UIATableView')
|
||||
.elementByClassName('UIAWebView')
|
||||
.should.eventually.exist
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
@@ -7,8 +7,8 @@ var env = require('../../../helpers/env'),
|
||||
describe('uicatalog - lock device @skip-ios6', function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
var allowance = env.IOS7 ? 5 : 2;
|
||||
it("should lock the device for 4 of seconds (+/- " + allowance + " secs)", function (done) {
|
||||
var allowance = (env.IOS7 || env.IOS8) ? 9 : 2;
|
||||
it("should lock the device for 4 seconds (+/- " + allowance + " secs)", function (done) {
|
||||
var before = new Date().getTime() / 1000;
|
||||
driver
|
||||
.lockDevice(4)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
var setup = require("../../common/setup-base"),
|
||||
env = require("../../../helpers/env.js"),
|
||||
desired = require('./desired');
|
||||
|
||||
describe('uicatalog - move @skip-ios6', function () {
|
||||
@@ -10,10 +11,11 @@ describe('uicatalog - move @skip-ios6', function () {
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
it('should be able to click on arbitrary x-y elements', function (done) {
|
||||
var axIdExt = env.IOS8 ? "" : ", AAPLButtonViewController";
|
||||
driver
|
||||
.elementByXPath("//UIAStaticText[contains(@name, 'Buttons')]").moveTo(10, 10).click()
|
||||
.elementByAccessibilityId("Buttons" + axIdExt).moveTo(10, 10).click()
|
||||
.elementByXPath("//UIAElement['SYSTEM (CONTACT ADD)']")
|
||||
.should.eventually.exist .should.eventually.exist
|
||||
.should.eventually.exist.should.eventually.exist
|
||||
.nodeify(done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var setup = require("../../common/setup-base")
|
||||
, desired = require("./desired");
|
||||
|
||||
describe("uicatalog - stability @skip-ci @skip-ios6", function () {
|
||||
|
||||
var runs = 20;
|
||||
|
||||
var test = function () {
|
||||
var driver;
|
||||
setup(this, desired).then(function (d) { driver = d; });
|
||||
|
||||
it('should complete successfully', function (done) {
|
||||
driver
|
||||
.elementByClassName('UIATableView')
|
||||
.nodeify(done);
|
||||
});
|
||||
};
|
||||
|
||||
for (var n = 0; n < runs; n++) {
|
||||
describe('burn-in test ' + n, test);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ describe('uicatalog - touch @skip-ios6', function () {
|
||||
return action.perform();
|
||||
});
|
||||
})
|
||||
.elementsByAccessibilityId('3')
|
||||
.waitForElementsByAccessibilityId('3', 3000, 500)
|
||||
.should.eventually.have.length(2)
|
||||
.nodeify(done);
|
||||
});
|
||||
|
||||
@@ -19,12 +19,6 @@ describe('webview - basics', function () {
|
||||
driver.contexts().should.eventually.have.length.above(0)
|
||||
.nodeify(done);
|
||||
});
|
||||
it('getting list twice should not crash appium', function (done) {
|
||||
driver
|
||||
.contexts().should.eventually.have.length.above(0)
|
||||
.contexts().should.eventually.have.length.above(0)
|
||||
.nodeify(done);
|
||||
});
|
||||
it('getting list multiple times should not crash appium', function (done) {
|
||||
driver
|
||||
.contexts().should.eventually.have.length.above(0)
|
||||
|
||||
+16
-4
@@ -62,9 +62,9 @@ function iphoneOrIpadSimulator(device, version) {
|
||||
case '6.1':
|
||||
case '7.0':
|
||||
case '7.1':
|
||||
return isIpad ? 'iPad Simulator' : 'iPhone Simulator';
|
||||
// case '7.1':
|
||||
// return isIpad ? 'iPad Retina' : 'iPhone Retina 4-inch';
|
||||
return isIpad ? 'iPad 2' : 'iPhone 5s';
|
||||
case '8.0':
|
||||
return isIpad ? 'iPad 2' : 'iPhone 6';
|
||||
default:
|
||||
throw new Error("invalid version");
|
||||
}
|
||||
@@ -99,6 +99,15 @@ switch (env.DEVICE) {
|
||||
, app: process.env.APP ? path.resolve(__dirname, "../../sample-code/apps/" + process.env.APP + "/build/Release-iphonesimulator/" + process.env.APP + ".app") : ''
|
||||
};
|
||||
break;
|
||||
case 'ios8':
|
||||
case 'ios8_iphone':
|
||||
case 'ios8_ipad':
|
||||
env.CAPS = {
|
||||
browserName: ''
|
||||
, deviceName: iphoneOrIpadSimulator(env.DEVICE, "8.0")
|
||||
, app: process.env.APP ? path.resolve(__dirname, "../../sample-code/apps/" + process.env.APP + "/build/Release-iphonesimulator/" + process.env.APP + ".app") : ''
|
||||
};
|
||||
break;
|
||||
case 'android':
|
||||
env.CAPS = {
|
||||
browserName: ''
|
||||
@@ -132,12 +141,13 @@ env.IOS = env.DEVICE.match(/ios/i);
|
||||
env.IOS6 = env.DEVICE.match(/ios6/i);
|
||||
env.IOS7 = env.DEVICE.match(/ios7/i);
|
||||
env.IOS71 = env.DEVICE.match(/ios71/i);
|
||||
env.IOS8 = env.DEVICE.match(/ios8/i);
|
||||
env.ANDROID = env.DEVICE.match(/android/i);
|
||||
env.SELENDROID = env.DEVICE.match(/selendroid/i);
|
||||
|
||||
// better timeout settings for 71
|
||||
env.LAUNCH_TIMEOUT = process.env.LAUNCH_TIMEOUT ? JSON.parse(process.env.LAUNCH_TIMEOUT) :
|
||||
(env.IOS71 ? {"global": 60000, "afterSimLaunch": 10000} : 60000);
|
||||
((env.IOS71 || env.IOS8) ? {"global": 60000, "afterSimLaunch": 10000} : 60000);
|
||||
|
||||
env.CAPS.launchTimeout = env.LAUNCH_TIMEOUT;
|
||||
|
||||
@@ -157,6 +167,8 @@ if (env.VERSION) {
|
||||
env.CAPS.platformVersion = "7.1";
|
||||
} else if (env.IOS7) {
|
||||
env.CAPS.platformVersion = "7.0";
|
||||
} else if (env.IOS8) {
|
||||
env.CAPS.platformVersion = "8.0";
|
||||
}
|
||||
|
||||
// max retry
|
||||
|
||||
@@ -4,10 +4,11 @@ var ChaiAsserter = require('./asserter').ChaiAsserter;
|
||||
|
||||
function textCleared(el) {
|
||||
return new ChaiAsserter(function () {
|
||||
return el.text().should.become(''); });
|
||||
return el.text().should.become('');
|
||||
});
|
||||
}
|
||||
|
||||
var safeClear = function (el ,remainingAttempts) {
|
||||
var safeClear = function (el, remainingAttempts) {
|
||||
if (typeof remainingAttempts !== 'number') remainingAttempts = 3;
|
||||
return el
|
||||
.clear()
|
||||
|
||||
@@ -3,7 +3,6 @@ var env = require('./env')
|
||||
, wd = require("wd")
|
||||
, Q = require("q")
|
||||
, _ = require("underscore")
|
||||
, iosReset = require('./reset').iosReset
|
||||
, androidUninstall = require('./reset').androidUninstall;
|
||||
|
||||
require('colors');
|
||||
@@ -55,6 +54,10 @@ module.exports.initSession = function (desired, opts) {
|
||||
});
|
||||
});
|
||||
|
||||
wd.addPromiseChainMethod('printSource', function () {
|
||||
return this.source().then(function (s) { console.log(s); });
|
||||
});
|
||||
|
||||
return {
|
||||
setUp: function (name) {
|
||||
if (env.VERBOSE) {
|
||||
@@ -121,18 +124,16 @@ module.exports.initSession = function (desired, opts) {
|
||||
if (env.MAX_RETRY) attempts = Math.min(env.MAX_RETRY, attempts);
|
||||
return browser.chain()
|
||||
.then(function () {
|
||||
if (!env.SAUCE && env.IOS && env.RESET_IOS && !opts['no-reset']) {
|
||||
// TODO this should not be necessary
|
||||
return iosReset();
|
||||
}
|
||||
}).then(function () {
|
||||
// if android uninstall package first
|
||||
if (!env.SAUCE && desired.platformName === 'Android' && desired.appPackage) {
|
||||
// TODO this should not be necessary
|
||||
return androidUninstall(desired.appPackage);
|
||||
}
|
||||
}).then(function () { return init(attempts); })
|
||||
.then(function () { initialized = true; })
|
||||
.then(function () {
|
||||
initialized = true;
|
||||
browser._origCaps = caps;
|
||||
})
|
||||
.setImplicitWaitTimeout(env.IMPLICIT_WAIT_TIMEOUT);
|
||||
},
|
||||
tearDown: function (passed) {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
|
||||
var IOS = require("../../lib/devices/ios/ios")
|
||||
, Instruments = require('../../lib/devices/ios/instruments');
|
||||
|
||||
exports.getSimUdid = function (xcodeVer, sdkVer, desired, cb) {
|
||||
var opts = {
|
||||
forceIphone: false,
|
||||
forceIpad: false,
|
||||
xcodeVersion: xcodeVer,
|
||||
deviceName: desired.deviceName,
|
||||
platformVersion: desired.platformVersion,
|
||||
iOSSDKVersion: sdkVer
|
||||
};
|
||||
Instruments.getAvailableDevices(function (err, availDevices) {
|
||||
if (err) return cb(err);
|
||||
var dString = IOS.getDeviceStringFromOpts(opts);
|
||||
var sim = IOS.getSimForDeviceString(dString, availDevices);
|
||||
if (sim[1] === null) {
|
||||
return cb(new Error("Could not get UDID"));
|
||||
}
|
||||
cb(null, sim[1]);
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user