Skip to content

Commit

Permalink
feat(ios): iOS support (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
sjelin authored Jul 1, 2016
1 parent 88354ca commit aa1b8b7
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 22 deletions.
3 changes: 2 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"selenium": "2.53.0",
"chromedriver": "2.21",
"iedriver": "2.53.1",
"androidsdk": "24.4.1"
"androidsdk": "24.4.1",
"appium": "1.5.3"
},
"cdnUrls": {
"selenium": "https://selenium-release.storage.googleapis.com/",
Expand Down
36 changes: 36 additions & 0 deletions lib/binaries/appium.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as child_process from 'child_process';
import * as rimraf from 'rimraf';
import * as path from 'path';
import {arch, type} from 'os';

import {Binary, OS} from './binary';
import {Config} from '../config';

/**
* The appium binary.
*/
export class Appium extends Binary {
static os = [OS.Windows_NT, OS.Linux, OS.Darwin];
static id = 'appium';
static versionDefault = Config.binaryVersions().appium;
static isDefault = false;
static shortName = ['appium'];

constructor() {
super();
this.name = 'appium';
this.versionCustom = Appium.versionDefault;
this.prefixDefault = 'appium-';
this.suffixDefault = '';
}

id(): string { return Appium.id; }

versionDefault(): string { return Appium.versionDefault; }

executableSuffix(): string { return ''; }

remove(sdkPath: string): void {
rimraf.sync(sdkPath);
}
}
1 change: 1 addition & 0 deletions lib/binaries/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from './binary';
export * from './chrome_driver';
export * from './ie_driver';
export * from './android_sdk';
export * from './appium';
export * from './stand_alone';
11 changes: 11 additions & 0 deletions lib/cmds/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,14 @@ export function android(sdkPath: string, apiLevels: string[], abis: string[],
logger.info('android-sdk: Initialization complete');
}).done();
};

export function iOS(logger: Logger) {
if (os.type() != 'Darwin') {
throw new Error('Must be on a Mac to simulate iOS devices.');
}
try {
fs.statSync('/Applications/Xcode.app');
} catch(e) {
logger.warn('You must install the xcode commandline tools!');
}
}
6 changes: 5 additions & 1 deletion lib/cmds/opts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Config} from '../config';
import {Cli, Option, Options} from '../cli';
import {ChromeDriver, IEDriver, AndroidSDK, StandAlone} from '../binaries';
import {ChromeDriver, IEDriver, AndroidSDK, Appium, StandAlone} from '../binaries';

export const OUT_DIR = 'out_dir';
export const SELENIUM_PORT = 'seleniumPort';
Expand All @@ -15,10 +15,12 @@ export const IE = 'ie';
export const IE32 = 'ie32';
export const EDGE = 'edge';
export const ANDROID = 'android';
export const IOS = 'ios';
export const VERSIONS_CHROME = 'versions.chrome';
export const VERSIONS_STANDALONE = 'versions.standalone';
export const VERSIONS_IE = 'versions.ie';
export const VERSIONS_ANDROID = 'versions.android';
export const VERSIONS_APPIUM = 'versions.appium';
export const CHROME_LOGS = 'chrome_logs';
export const ANDROID_API_LEVELS = 'android-api-levels';
export const ANDROID_ABIS = 'android-abis';
Expand All @@ -43,9 +45,11 @@ opts[IE] = new Option(IE, 'Install or update ie driver', 'boolean', IEDriver.isD
opts[IE32] = new Option(IE32, 'Install or update 32-bit ie driver', 'boolean', IEDriver.isDefault);
opts[EDGE] = new Option(EDGE, 'Use installed Microsoft Edge driver', 'string', 'C:\\Program Files (x86)\\Microsoft Web Driver\\MicrosoftWebDriver.exe');
opts[ANDROID] = new Option(ANDROID, 'Update/use the android sdk', 'boolean', AndroidSDK.isDefault);
opts[IOS] = new Option(IOS, 'Update the iOS sdk', 'boolean', false);
opts[VERSIONS_CHROME] = new Option(VERSIONS_CHROME, 'Optional chrome driver version', 'string', ChromeDriver.versionDefault);
opts[VERSIONS_ANDROID] = new Option(VERSIONS_ANDROID, 'Optional android sdk version', 'string', AndroidSDK.versionDefault);
opts[VERSIONS_STANDALONE] = new Option(VERSIONS_STANDALONE, 'Optional seleniuim standalone server version', 'string', StandAlone.versionDefault);
opts[VERSIONS_APPIUM] = new Option(VERSIONS_APPIUM, 'Optional appium version', 'string', Appium.versionDefault);
opts[VERSIONS_IE] = new Option(VERSIONS_IE, 'Optional internet explorer driver version', 'string', IEDriver.versionDefault);
opts[CHROME_LOGS] = new Option(CHROME_LOGS, 'File path to chrome logs', 'string', undefined);
opts[ANDROID_API_LEVELS] = new Option(ANDROID_API_LEVELS, 'Which versions of the android API you want to emulate', 'string', AndroidSDK.DEFAULT_API_LEVELS);
Expand Down
20 changes: 15 additions & 5 deletions lib/cmds/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import * as Opt from './';
import {Config} from '../config';
import {FileManager} from '../files';
import {Logger, Options, Program} from '../cli';
import {BinaryMap, Binary, ChromeDriver, IEDriver, AndroidSDK, StandAlone} from '../binaries';
import {BinaryMap, Binary, ChromeDriver, IEDriver, AndroidSDK, Appium, StandAlone} from
'../binaries';

let logger = new Logger('start');
let prog = new Program()
Expand All @@ -23,11 +24,16 @@ let prog = new Program()
.addOption(Opts[Opt.VERSIONS_STANDALONE])
.addOption(Opts[Opt.VERSIONS_CHROME])
.addOption(Opts[Opt.VERSIONS_ANDROID])
.addOption(Opts[Opt.VERSIONS_APPIUM])
.addOption(Opts[Opt.CHROME_LOGS])
.addOption(Opts[Opt.ANDROID])
.addOption(Opts[Opt.AVDS])
.addOption(Opts[Opt.AVD_USE_SNAPSHOTS]);

if (os.type() === 'Darwin') {
prog.addOption(Opts[Opt.IOS]);
}

if (os.type() === 'Windows_NT') {
prog.addOption(Opts[Opt.VERSIONS_IE]);
prog.addOption(Opts[Opt.EDGE]);
Expand Down Expand Up @@ -83,6 +89,7 @@ function start(options: Options) {
binaries[IEDriver.id].versionCustom = options[Opt.VERSIONS_IE].getString();
}
binaries[AndroidSDK.id].versionCustom = options[Opt.VERSIONS_ANDROID].getString();
binaries[Appium.id].versionCustom = options[Opt.VERSIONS_APPIUM].getString();
let downloadedBinaries = FileManager.downloadedBinaries(outputDir);

if (downloadedBinaries[StandAlone.id] == null) {
Expand Down Expand Up @@ -118,11 +125,14 @@ function start(options: Options) {
let avds = options[Opt.AVDS].getString();
startAndroid(outputDir, binaries[AndroidSDK.id], avds.split(','),
options[Opt.AVD_USE_SNAPSHOTS].getBoolean(),
options[Opt.APPIUM_PORT].getString());
startAppium(outputDir, options[Opt.APPIUM_PORT].getString());
options[Opt.AVD_PORT].getString());
} else {
logger.warn('Not starting android because it is not installed');
}
}
if (downloadedBinaries[Appium.id] != null) {
startAppium(outputDir, binaries[Appium.id], options[Opt.APPIUM_PORT].getString());
}

// log the command to launch selenium server
let argsToString = '';
Expand Down Expand Up @@ -204,9 +214,9 @@ function killAndroid() {
// Manage appium process
let appiumProcess: childProcess.ChildProcess;

function startAppium(outputDir: string, port: string) {
function startAppium(outputDir: string, binary: Binary, port: string) {
logger.info('Starting appium server');
appiumProcess = childProcess.spawn(path.join(outputDir, 'appium',
appiumProcess = childProcess.spawn(path.join(outputDir, binary.filename(),
'node_modules', '.bin', 'appium'), port ? ['--port', port] : []);
}

Expand Down
28 changes: 22 additions & 6 deletions lib/cmds/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import * as rimraf from 'rimraf';
import {Opts} from './opts';
import * as Opt from './';
import {Config} from '../config';
import {Binary, ChromeDriver, IEDriver, AndroidSDK, StandAlone} from '../binaries';
import {Binary, ChromeDriver, IEDriver, AndroidSDK, Appium, StandAlone} from '../binaries';
import {FileManager, Downloader} from '../files';
import {Logger, Options, Program} from '../cli';
import {android as initializeAndroid} from './initialize';
import {android as initializeAndroid, iOS as checkIOS} from './initialize';

let logger = new Logger('update');
let prog = new Program()
Expand All @@ -30,13 +30,18 @@ let prog = new Program()
.addOption(Opts[Opt.ANDROID_ABIS])
.addOption(Opts[Opt.ANDROID_ACCEPT_LICENSES]);

if (os.type() === 'Darwin') {
prog.addOption(Opts[Opt.IOS]);
}

if (os.type() === 'Windows_NT') {
prog.addOption(Opts[Opt.IE]).addOption(Opts[Opt.IE32]);
}

prog
.addOption(Opts[Opt.VERSIONS_STANDALONE])
.addOption(Opts[Opt.VERSIONS_CHROME])
.addOption(Opts[Opt.VERSIONS_APPIUM])
.addOption(Opts[Opt.VERSIONS_ANDROID]);

if (os.type() === 'Windows_NT') {
Expand Down Expand Up @@ -69,6 +74,10 @@ function update(options: Options): void {
ie32 = options[Opt.IE32].getBoolean();
}
let android: boolean = options[Opt.ANDROID].getBoolean();
let ios: boolean = false;
if (options[Opt.IOS]) {
ios = options[Opt.IOS].getBoolean();
}
let outputDir = Config.getSeleniumDir();
let android_api_levels: string[] = options[Opt.ANDROID_API_LEVELS].getString().split(',');
let android_abis: string[] = options[Opt.ANDROID_ABIS].getString().split(',');
Expand All @@ -92,6 +101,7 @@ function update(options: Options): void {
binaries[IEDriver.id].versionCustom = options[Opt.VERSIONS_IE].getString();
}
binaries[AndroidSDK.id].versionCustom = options[Opt.VERSIONS_ANDROID].getString();
binaries[Appium.id].versionCustom = options[Opt.VERSIONS_APPIUM].getString();

// if the file has not been completely downloaded, download it
// else if the file has already been downloaded, unzip the file, rename it, and give it permissions
Expand Down Expand Up @@ -129,7 +139,12 @@ function update(options: Options): void {
))), android_api_levels, android_abis, android_accept_licenses,
binaries[AndroidSDK.id].versionCustom, logger);
});
installAppium(outputDir);
}
if (ios) {
checkIOS(logger);
}
if (android || ios) {
installAppium(binaries[Appium.id], outputDir);
}
}

Expand Down Expand Up @@ -192,15 +207,16 @@ function unzip<T extends Binary>(binary: T, outputDir: string, fileName: string)
}
}

function installAppium(outputDir: string): void {
function installAppium(binary: Binary, outputDir: string): void {
logger.info('appium: installing appium');

let folder = path.join(outputDir, 'appium');
let folder = path.join(outputDir, binary.filename());
try {
rimraf.sync(folder);
} catch(err) {}

fs.mkdirSync(folder);
fs.writeFileSync(path.join(folder, 'package.json'), '{}');
child_process.spawn('npm', ['install', 'appium'], {cwd: folder});
child_process.spawn('npm', ['install', 'appium@' + binary.version()], {cwd:
folder});
}
2 changes: 2 additions & 0 deletions lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface ConfigFile {
chrome?: string;
ie?: string;
android?: string;
appium?: string;
}

/**
Expand Down Expand Up @@ -62,6 +63,7 @@ export class Config {
configVersions.chrome = configFile.webdriverVersions.chromedriver;
configVersions.ie = configFile.webdriverVersions.iedriver;
configVersions.android = configFile.webdriverVersions.androidsdk;
configVersions.appium = configFile.webdriverVersions.appium;
return configVersions;
}

Expand Down
9 changes: 5 additions & 4 deletions lib/files/file_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import * as fs from 'fs';
import * as q from 'q';
import * as rimraf from 'rimraf';

import {Binary, BinaryMap, ChromeDriver, IEDriver, AndroidSDK, StandAlone, OS} from '../binaries';
import {Binary, BinaryMap, ChromeDriver, IEDriver, AndroidSDK, Appium, StandAlone, OS} from
'../binaries';
import {DownloadedBinary} from './downloaded_binary';
import {Downloader} from './downloader';
import {Logger} from '../cli';
Expand Down Expand Up @@ -59,6 +60,9 @@ export class FileManager {
if (FileManager.checkOS_(osType, AndroidSDK)) {
binaries[AndroidSDK.id] = new AndroidSDK();
}
if (FileManager.checkOS_(osType, Appium)) {
binaries[Appium.id] = new Appium();
}
return binaries;
}

Expand Down Expand Up @@ -213,8 +217,5 @@ export class FileManager {
}
}
})
try {
rimraf.sync(path.join(outputDir, 'appium'));
} catch (e) {}
}
}
22 changes: 18 additions & 4 deletions mobile.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ Mobile Browser Support
======================

Support for mobile browsers is provided via [appium](https://github.com/appium/appium). If you
have the Android SDK installed, when you run `webdriver-manager start`, appium will automatically
start on the port specified by `--appium-port`.
have used `webdriver-manager update --android` or `webdriver-manager update --ios`, when you run
`webdriver-manager start`, Appium will automatically start on the port specified by `--appium-port`.


Android SDK
-----------

`webdriver-manager` will not install the android SDK by default. If you want to test on android,
run `webdriver-manager update --android`. This will download the android SDK, appium, and set up
run `webdriver-manager update --android`. This will download the android SDK, Appium, and set up
some virtual android devices for you to run tests against. By default, this will create only an
android device running version 24 on x86-64. If you need a different device, you must use the
`--android-api-levels` and `--android-abis` flags. So you might run a command like this:
Expand All @@ -31,7 +31,7 @@ As a practical matter, if you don't want to manually accept the license agreemen
`--android-accept-licenses`, which will accept them on your behalf.

Once you have installed the Android SDK with the virtual devices you need, use
`webdriver-manager start --android` to boot up appium and begin emulating your android device(s).
`webdriver-manager start --android` to boot up Appium and begin emulating your android device(s).
By default `webdriver-manager` will emulate all available android devices. If you would rather
emulate a specific device, use `--avds`. So you might use:

Expand All @@ -44,3 +44,17 @@ If you would prefer not to emulate any android virtual devices, use `--avds none
If you need to specify the ports used by the android virtual devices, use `--avd_port`. The port
you specify will be used for the console of the first device, and the port one higher will be used
for its ADB. The second device will use the next two ports, and so on.


iOS
---------

When you run `webdriver-manager update --ios`, `webdriver-manager` will install Appium and check
your computer for iOS simulation capabilities. `webdriver-manager` cannot download the xcode
commandline tools for you however, nor can it agree to Apple's user agreement. The xcode
commandline tools come with several virtual devices pre-setup. If you need more, run
`xcrun simctl` for help doing that.

Once you have installed Appium, `webdriver-manager` will launch it automatically when you run
`webdriver-manager start`. Appium will automatically handle starting iOS device emulation as
needed.
Loading

0 comments on commit aa1b8b7

Please sign in to comment.