Files
appium/lib/parser.js
2015-12-17 14:19:00 -08:00

758 lines
21 KiB
JavaScript

import path from 'path';
import _ from 'lodash';
import { ArgumentParser } from 'argparse';
import pkgObj from '../../package.json';
const args = [
[['--shell'], {
required: false,
defaultValue: null,
help: 'Enter REPL mode',
nargs: 0,
}],
[['--ipa'], {
required: false,
defaultValue: null,
help: '(IOS-only) abs path to compiled .ipa file',
example: '/abs/path/to/my.ipa',
}],
[['-a', '--address'], {
defaultValue: '0.0.0.0',
required: false,
example: '0.0.0.0',
help: 'IP Address to listen on',
}],
[['-p', '--port'], {
defaultValue: 4723,
required: false,
type: 'int',
example: '4723',
help: 'port to listen on',
}],
[['-ca', '--callback-address'], {
required: false,
dest: 'callbackAddress',
defaultValue: null,
example: '127.0.0.1',
help: 'callback IP Address (default: same as --address)',
}],
[['-cp', '--callback-port'], {
required: false,
dest: 'callbackPort',
defaultValue: null,
type: 'int',
example: '4723',
help: 'callback port (default: same as port)',
}],
[['-bp', '--bootstrap-port'], {
defaultValue: 4724,
dest: 'bootstrapPort',
required: false,
type: 'int',
example: '4724',
help: '(Android-only) port to use on device to talk to Appium',
}],
[['-r', '--backend-retries'], {
defaultValue: 3,
dest: 'backendRetries',
required: false,
type: 'int',
example: '3',
help: '(iOS-only) How many times to retry launching Instruments ' +
'before saying it crashed or timed out',
}],
[['--session-override'], {
defaultValue: false,
dest: 'sessionOverride',
action: 'storeTrue',
required: false,
help: 'Enables session override (clobbering)',
nargs: 0,
}],
[['-l', '--pre-launch'], {
defaultValue: false,
dest: 'launch',
action: 'storeTrue',
required: false,
help: 'Pre-launch the application before allowing the first session ' +
'(Requires --app and, for Android, --app-pkg and --app-activity)',
nargs: 0,
}],
[['-g', '--log'], {
defaultValue: null,
dest: 'log',
required: false,
example: '/path/to/appium.log',
help: 'Also send log output to this file',
}],
[['--log-level'], {
choices: ['info', 'info:debug', 'info:info', 'info:warn', 'info:error',
'warn', 'warn:debug', 'warn:info', 'warn:warn', 'warn:error',
'error', 'error:debug', 'error:info', 'error:warn', 'error:error',
'debug', 'debug:debug', 'debug:info', 'debug:warn', 'debug:error'],
defaultValue: 'debug',
dest: 'loglevel',
required: false,
example: 'debug',
help: 'log level; default (console[:file]): debug[:debug]',
}],
[['--log-timestamp'], {
defaultValue: false,
required: false,
help: 'Show timestamps in console output',
nargs: 0,
action: 'storeTrue',
dest: 'logTimestamp',
}],
[['--local-timezone'], {
defaultValue: false,
required: false,
help: 'Use local timezone for timestamps',
nargs: 0,
action: 'storeTrue',
dest: 'localTimezone',
}],
[['--log-no-colors'], {
defaultValue: false,
required: false,
help: 'Do not use colors in console output',
nargs: 0,
action: 'storeTrue',
dest: 'logNoColors',
}],
[['-G', '--webhook'], {
defaultValue: null,
required: false,
example: 'localhost:9876',
help: 'Also send log output to this HTTP listener',
}],
[['--safari'], {
defaultValue: false,
action: 'storeTrue',
required: false,
help: '(IOS-Only) Use the safari app',
nargs: 0,
}],
[['--default-device', '-dd'], {
dest: 'defaultDevice',
defaultValue: false,
action: 'storeTrue',
required: false,
help: '(IOS-Simulator-only) use the default simulator that instruments ' +
'launches on its own',
}],
[['--force-iphone'], {
defaultValue: false,
dest: 'forceIphone',
action: 'storeTrue',
required: false,
help: '(IOS-only) Use the iPhone Simulator no matter what the app wants',
nargs: 0,
}],
[['--force-ipad'], {
defaultValue: false,
dest: 'forceIpad',
action: 'storeTrue',
required: false,
help: '(IOS-only) Use the iPad Simulator no matter what the app wants',
nargs: 0,
}],
[['--tracetemplate'], {
defaultValue: null,
dest: 'automationTraceTemplatePath',
required: false,
example: '/Users/me/Automation.tracetemplate',
help: '(IOS-only) .tracetemplate file to use with Instruments',
}],
[['--instruments'], {
defaultValue: null,
dest: 'instrumentsPath',
require: false,
example: '/path/to/instruments',
help: '(IOS-only) path to instruments binary',
}],
[['--nodeconfig'], {
required: false,
defaultValue: null,
help: 'Configuration JSON file to register appium with selenium grid',
example: '/abs/path/to/nodeconfig.json',
}],
[['-ra', '--robot-address'], {
defaultValue: '0.0.0.0',
dest: 'robotAddress',
required: false,
example: '0.0.0.0',
help: 'IP Address of robot',
}],
[['-rp', '--robot-port'], {
defaultValue: -1,
dest: 'robotPort',
required: false,
type: 'int',
example: '4242',
help: 'port for robot',
}],
[['--selendroid-port'], {
defaultValue: 8080,
dest: 'selendroidPort',
required: false,
type: 'int',
example: '8080',
help: 'Local port used for communication with Selendroid',
}],
[['--chromedriver-port'], {
defaultValue: 9515,
dest: 'chromeDriverPort',
required: false,
type: 'int',
example: '9515',
help: 'Port upon which ChromeDriver will run',
}],
[['--chromedriver-executable'], {
defaultValue: null,
dest: 'chromedriverExecutable',
required: false,
help: 'ChromeDriver executable full path',
}],
[['--show-config'], {
defaultValue: false,
dest: 'showConfig',
action: 'storeTrue',
required: false,
help: 'Show info about the appium server configuration and exit',
}],
[['--no-perms-check'], {
defaultValue: false,
dest: 'noPermsCheck',
action: 'storeTrue',
required: false,
help: 'Bypass Appium\'s checks to ensure we can read/write necessary files',
}],
[['--command-timeout'], {
defaultValue: 60,
dest: 'defaultCommandTimeout',
type: 'int',
required: false,
help: 'The default command timeout for the server to use for all ' +
'sessions (in seconds and should be less than 2147483). ' +
'Will still be overridden by newCommandTimeout cap',
}],
[['--strict-caps'], {
defaultValue: false,
dest: 'enforceStrictCaps',
action: 'storeTrue',
required: false,
help: 'Cause sessions to fail if desired caps are sent in that Appium ' +
'does not recognize as valid for the selected device',
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',
required: false,
help: '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'], {
defaultValue: null,
dest: 'traceDir',
required: false,
help: 'Absolute path to directory Appium use to save ios instruments ' +
'traces, defaults to <tmp dir>/appium-instruments',
}],
[['--debug-log-spacing'], {
dest: 'debugLogSpacing',
defaultValue: false,
action: 'storeTrue',
required: false,
help: 'Add exaggerated spacing in logs to help with visual inspection',
}],
[['--suppress-adb-kill-server'], {
dest: 'suppressAdbKillServer',
defaultValue: false,
action: 'storeTrue',
required: false,
help: '(Android-only) If set, prevents Appium from killing the adb server instance',
nargs: 0,
}],
[['--async-trace'], {
dest: 'asyncTrace',
defaultValue: false,
required: false,
action: 'storeTrue',
help: 'Add long stack traces to log entries. Recommended for debugging only.',
}],
[['--webkit-debug-proxy-port'], {
defaultValue: 27753,
dest: 'webkitDebugProxyPort',
required: false,
type: 'int',
example: "27753",
help: '(IOS-only) Local port used for communication with ios-webkit-debug-proxy'
}],
[['--default-capabilities'], {
dest: 'defaultCapabilities',
defaultValue: {},
type: JSON.parse,
required: false,
example: '{"app": "myapp.app", "deviceName": "iPhone Simulator"}',
help: 'Set the default desired capabilities, which will be set on each ' +
'session unless overridden by received capabilities.'
}],
];
const deprecatedArgs = [
[['-k', '--keep-artifacts'], {
defaultValue: false,
dest: 'keepArtifacts',
action: 'storeTrue',
required: false,
help: '[DEPRECATED] - no effect, trace is now in tmp dir by default and is ' +
'cleared before each run. Please also refer to the --trace-dir flag.',
nargs: 0,
}],
[['--platform-name'], {
dest: 'platformName',
defaultValue: null,
required: false,
deprecatedFor: '--default-capabilities',
example: 'iOS',
help: '[DEPRECATED] - Name of the mobile platform: iOS, Android, or FirefoxOS',
}],
[['--platform-version'], {
dest: 'platformVersion',
defaultValue: null,
required: false,
deprecatedFor: '--default-capabilities',
example: '7.1',
help: '[DEPRECATED] - Version of the mobile platform',
}],
[['--automation-name'], {
dest: 'automationName',
defaultValue: null,
required: false,
deprecatedFor: '--default-capabilities',
example: 'Appium',
help: '[DEPRECATED] - Name of the automation tool: Appium or Selendroid',
}],
[['--device-name'], {
dest: 'deviceName',
defaultValue: null,
required: false,
deprecatedFor: '--default-capabilities',
example: 'iPhone Retina (4-inch), Android Emulator',
help: '[DEPRECATED] - Name of the mobile device to use',
}],
[['--browser-name'], {
dest: 'browserName',
defaultValue: null,
required: false,
deprecatedFor: '--default-capabilities',
example: 'Safari',
help: '[DEPRECATED] - Name of the mobile browser: Safari or Chrome',
}],
[['--app'], {
dest: 'app',
required: false,
defaultValue: null,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - IOS: abs path to simulator-compiled .app file or the bundle_id of the desired target on device; Android: abs path to .apk file',
example: '/abs/path/to/my.app',
}],
[['-lt', '--launch-timeout'], {
defaultValue: 90000,
dest: 'launchTimeout',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (iOS-only) how long in ms to wait for Instruments to launch',
}],
[['--language'], {
defaultValue: null,
dest: 'language',
required: false,
example: 'en',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - Language for the iOS simulator / Android Emulator',
}],
[['--locale'], {
defaultValue: null,
dest: 'locale',
required: false,
example: 'en_US',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - Locale for the iOS simulator / Android Emulator',
}],
[['-U', '--udid'], {
dest: 'udid',
required: false,
defaultValue: null,
example: '1adsf-sdfas-asdf-123sdf',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - Unique device identifier of the connected physical device',
}],
[['--orientation'], {
dest: 'orientation',
defaultValue: null,
required: false,
example: 'LANDSCAPE',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (IOS-only) use LANDSCAPE or PORTRAIT to initialize all requests ' +
'to this orientation',
}],
[['--no-reset'], {
defaultValue: false,
dest: 'noReset',
action: 'storeTrue',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - Do not reset app state between sessions (IOS: do not delete app ' +
'plist files; Android: do not uninstall app before new session)',
nargs: 0,
}],
[['--full-reset'], {
defaultValue: false,
dest: 'fullReset',
action: 'storeTrue',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (iOS) Delete the entire simulator folder. (Android) Reset app ' +
'state by uninstalling app instead of clearing app data. On ' +
'Android, this will also remove the app after the session is complete.',
nargs: 0,
}],
[['--app-pkg'], {
dest: 'appPackage',
defaultValue: null,
required: false,
deprecatedFor: '--default-capabilities',
example: 'com.example.android.myApp',
help: '[DEPRECATED] - (Android-only) Java package of the Android app you want to run ' +
'(e.g., com.example.android.myApp)',
}],
[['--app-activity'], {
dest: 'appActivity',
defaultValue: null,
required: false,
example: 'MainActivity',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Activity name for the Android activity you want ' +
'to launch from your package (e.g., MainActivity)',
}],
[['--app-wait-package'], {
dest: 'appWaitPackage',
defaultValue: false,
required: false,
example: 'com.example.android.myApp',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Package name for the Android activity you want ' +
'to wait for (e.g., com.example.android.myApp)',
}],
[['--app-wait-activity'], {
dest: 'appWaitActivity',
defaultValue: false,
required: false,
example: 'SplashActivity',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Activity name for the Android activity you want ' +
'to wait for (e.g., SplashActivity)',
}],
[['--device-ready-timeout'], {
dest: 'deviceReadyTimeout',
defaultValue: '5',
required: false,
example: '5',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Timeout in seconds while waiting for device to become ready',
}],
[['--android-coverage'], {
dest: 'androidCoverage',
defaultValue: false,
required: false,
example: 'com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Fully qualified instrumentation class. Passed to -w in ' +
'adb shell am instrument -e coverage true -w ',
}],
[['--avd'], {
dest: 'avd',
defaultValue: null,
required: false,
example: '@default',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Name of the avd to launch',
}],
[['--avd-args'], {
dest: 'avdArgs',
defaultValue: null,
required: false,
example: '-no-snapshot-load',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Additional emulator arguments to launch the avd',
}],
[['--use-keystore'], {
defaultValue: false,
dest: 'useKeystore',
action: 'storeTrue',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) When set the keystore will be used to sign apks.',
}],
[['--keystore-path'], {
defaultValue: path.resolve(process.env.HOME || process.env.USERPROFILE || '', '.android', 'debug.keystore'),
dest: 'keystorePath',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Path to keystore',
}],
[['--keystore-password'], {
defaultValue: 'android',
dest: 'keystorePassword',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Password to keystore',
}],
[['--key-alias'], {
defaultValue: 'androiddebugkey',
dest: 'keyAlias',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Key alias',
}],
[['--key-password'], {
defaultValue: 'android',
dest: 'keyPassword',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Key password',
}],
[['--intent-action'], {
dest: 'intentAction',
defaultValue: 'android.intent.action.MAIN',
required: false,
example: 'android.intent.action.MAIN',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Intent action which will be used to start activity',
}],
[['--intent-category'], {
dest: 'intentCategory',
defaultValue: 'android.intent.category.LAUNCHER',
required: false,
example: 'android.intent.category.APP_CONTACTS',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Intent category which will be used to start activity',
}],
[['--intent-flags'], {
dest: 'intentFlags',
defaultValue: '0x10200000',
required: false,
example: '0x10200000',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Flags that will be used to start activity',
}],
[['--intent-args'], {
dest: 'optionalIntentArguments',
defaultValue: null,
required: false,
example: '0x10200000',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) Additional intent arguments that will be used to ' +
'start activity',
}],
[['--dont-stop-app-on-reset'], {
dest: 'dontStopAppOnReset',
defaultValue: false,
action: 'storeTrue',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (Android-only) When included, refrains from stopping the app before restart',
}],
[['--calendar-format'], {
defaultValue: null,
dest: 'calendarFormat',
required: false,
example: 'gregorian',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (IOS-only) calendar format for the iOS simulator',
}],
[['--native-instruments-lib'], {
defaultValue: false,
dest: 'nativeInstrumentsLib',
action: 'storeTrue',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (IOS-only) IOS has a weird built-in unavoidable ' +
'delay. We patch this in appium. If you do not want it patched, ' +
'pass in this flag.',
nargs: 0,
}],
[['--keep-keychains'], {
defaultValue: false,
dest: 'keepKeyChains',
action: 'storeTrue',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (iOS-only) Whether to keep keychains (Library/Keychains) when reset app between sessions',
nargs: 0,
}],
[['--localizable-strings-dir'], {
required: false,
dest: 'localizableStringsDir',
defaultValue: 'en.lproj',
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (IOS-only) the relative path of the dir where Localizable.strings file resides ',
example: 'en.lproj',
}],
[['--show-ios-log'], {
defaultValue: false,
dest: 'showIOSLog',
action: 'storeTrue',
required: false,
deprecatedFor: '--default-capabilities',
help: '[DEPRECATED] - (IOS-only) if set, the iOS system log will be written to the console',
nargs: 0,
}]
];
function updateParseArgsForDefaultCapabilities (parser) {
// here we want to update the parser.parseArgs() function
// in order to bring together all the args that are actually
// default caps.
// once those deprecated args are actually removed, this
// can also be removed
parser._parseArgs = parser.parseArgs;
parser.parseArgs = function (args) {
let parsedArgs = parser._parseArgs(args);
parsedArgs.defaultCapabilities = parsedArgs.defaultCapabilities || {};
for (let argEntry of deprecatedArgs) {
let arg = argEntry[1].dest;
if (argEntry[1].deprecatedFor === '--default-capabilities') {
if (arg in parsedArgs && parsedArgs[arg] !== argEntry[1].defaultValue) {
parsedArgs.defaultCapabilities[arg] = parsedArgs[arg];
// j s h i n t can't handle complex interpolated strings
let capDict = {[arg]: parsedArgs[arg]};
argEntry[1].deprecatedFor = `--default-capabilities ` +
`'${JSON.stringify(capDict)}'`;
}
}
}
return parsedArgs;
};
}
function getParser () {
let parser = new ArgumentParser({
version: pkgObj.version,
addHelp: true,
description: 'A webdriver-compatible server for use with native and hybrid iOS and Android applications.'
});
let allArgs = _.union(args, deprecatedArgs);
parser.rawArgs = allArgs;
for (let arg of allArgs) {
parser.addArgument(arg[0], arg[1]);
}
updateParseArgsForDefaultCapabilities(parser);
return parser;
}
function getDefaultArgs () {
let defaults = {};
for (let [,arg] of args) {
defaults[arg.dest] = arg.defaultValue;
}
return defaults;
}
export default getParser;
export { getDefaultArgs, getParser };