Skip to content

Commit

Permalink
Add native endpoints for applications management (appium#614)
Browse files Browse the repository at this point in the history
* Add native endpoints for applications management

* Rename class method to avoid conflicts

* Update unit tests
  • Loading branch information
Mykola Mokhnach authored Jan 30, 2018
1 parent 59089cc commit c2312be
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 76 deletions.
68 changes: 0 additions & 68 deletions lib/commands/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,73 +229,5 @@ commands.pullFile = async function (remotePath) {
return await pullFileFromRealDevice(this.opts.device, remotePath);
};

function extractMandatoryOptions (opts = {}, keys) {
const result = {};
for (const key of keys) {
const value = opts[key];
if (!_.isString(value) || _.isEmpty(value)) {
log.errorAndThrow(`'${key}' is expected to be a valid string. '${value}' is given instead`);
}
result[key] = value;
}
return result;
}

commands.mobileInstallApp = async function (opts = {}) {
const {app} = extractMandatoryOptions(opts, ['app']);
const dstPath = await this.helpers.configureApp(app, '.app');
log.info(`Installing '${dstPath}' to the ${this.isRealDevice() ? 'real device' : 'Simulator'} ` +
`with UDID ${this.opts.device.udid}`);
if (!await fs.exists(dstPath)) {
log.errorAndThrow(`The application at '${dstPath}' does not exist or is not accessible`);
}
try {
await this.opts.device.installApp(dstPath);
log.info(`Installation of '${dstPath}' succeeded`);
} finally {
if (dstPath !== app) {
await fs.rimraf(dstPath);
}
}
};

commands.mobileIsAppInstalled = async function (opts = {}) {
const {bundleId} = extractMandatoryOptions(opts, ['bundleId']);
const installed = await this.opts.device.isAppInstalled(bundleId);
log.info(`App '${bundleId}' is${installed ? '' : ' not'} installed`);
return installed;
};

commands.mobileRemoveApp = async function (opts = {}) {
const {bundleId} = extractMandatoryOptions(opts, ['bundleId']);
log.info(`Uninstalling the application with bundle identifier '${bundleId}' ` +
`from the ${this.isRealDevice() ? 'real device' : 'Simulator'} with UDID ${this.opts.device.udid}`);
await this.opts.device.removeApp(bundleId);
log.info(`Removal of '${bundleId}' succeeded`);
};

commands.mobileLaunchApp = async function (opts = {}) {
const wdaOpts = extractMandatoryOptions(opts, ['bundleId']);
if (opts.arguments) {
wdaOpts.arguments = _.isArray(opts.arguments) ? opts.arguments : [opts.arguments];
}
if (opts.environment) {
wdaOpts.environment = opts.environment;
}
return await this.proxyCommand('/wda/apps/launch', 'POST', wdaOpts);
};

commands.mobileTerminateApp = async function (opts = {}) {
return await this.proxyCommand('/wda/apps/terminate', 'POST', extractMandatoryOptions(opts, ['bundleId']));
};

commands.mobileActivateApp = async function (opts = {}) {
return await this.proxyCommand('/wda/apps/activate', 'POST', extractMandatoryOptions(opts, ['bundleId']));
};

commands.mobileQueryAppState = async function (opts = {}) {
return await this.proxyCommand('/wda/apps/state', 'POST', extractMandatoryOptions(opts, ['bundleId']));
};


export default commands;
99 changes: 99 additions & 0 deletions lib/commands/app-management.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import _ from 'lodash';
import { fs } from 'appium-support';
import log from '../logger';

let commands = {};

function extractMandatoryOptions (opts = {}, keys) {
const result = {};
for (const key of keys) {
const value = opts[key];
if (!_.isString(value) || _.isEmpty(value)) {
log.errorAndThrow(`'${key}' is expected to be a valid string. '${value}' is given instead`);
}
result[key] = value;
}
return result;
}

commands.mobileInstallApp = async function (opts = {}) {
const {app} = extractMandatoryOptions(opts, ['app']);
const dstPath = await this.helpers.configureApp(app, '.app');
log.info(`Installing '${dstPath}' to the ${this.isRealDevice() ? 'real device' : 'Simulator'} ` +
`with UDID ${this.opts.device.udid}`);
if (!await fs.exists(dstPath)) {
log.errorAndThrow(`The application at '${dstPath}' does not exist or is not accessible`);
}
try {
await this.opts.device.installApp(dstPath);
log.info(`Installation of '${dstPath}' succeeded`);
} finally {
if (dstPath !== app) {
await fs.rimraf(dstPath);
}
}
};

commands.mobileIsAppInstalled = async function (opts = {}) {
const {bundleId} = extractMandatoryOptions(opts, ['bundleId']);
const installed = await this.opts.device.isAppInstalled(bundleId);
log.info(`App '${bundleId}' is${installed ? '' : ' not'} installed`);
return installed;
};

commands.mobileRemoveApp = async function (opts = {}) {
const {bundleId} = extractMandatoryOptions(opts, ['bundleId']);
log.info(`Uninstalling the application with bundle identifier '${bundleId}' ` +
`from the ${this.isRealDevice() ? 'real device' : 'Simulator'} with UDID ${this.opts.device.udid}`);
await this.opts.device.removeApp(bundleId);
log.info(`Removal of '${bundleId}' succeeded`);
};

commands.mobileLaunchApp = async function (opts = {}) {
const wdaOpts = extractMandatoryOptions(opts, ['bundleId']);
if (opts.arguments) {
wdaOpts.arguments = _.isArray(opts.arguments) ? opts.arguments : [opts.arguments];
}
if (opts.environment) {
wdaOpts.environment = opts.environment;
}
return await this.proxyCommand('/wda/apps/launch', 'POST', wdaOpts);
};

commands.mobileTerminateApp = async function (opts = {}) {
return await this.proxyCommand('/wda/apps/terminate', 'POST', extractMandatoryOptions(opts, ['bundleId']));
};

commands.mobileActivateApp = async function (opts = {}) {
return await this.proxyCommand('/wda/apps/activate', 'POST', extractMandatoryOptions(opts, ['bundleId']));
};

/**
* Returns the current application state
*
* @param {Object} opts - Options set, which must contain `bundleId` property
* @returns {number} The actual application state code. See
* https://developer.apple.com/documentation/xctest/xcuiapplicationstate?language=objc
* to get the list of possible values.
*/
commands.mobileQueryAppState = async function (opts = {}) {
return await this.proxyCommand('/wda/apps/state', 'POST', extractMandatoryOptions(opts, ['bundleId']));
};

commands.installApp = async function (appPath) {
await this.mobileInstallApp({app: appPath});
};

commands.isAppInstalled = async function (bundleId) {
return await this.mobileIsAppInstalled({bundleId});
};

commands.terminateApp = async function (bundleId) {
return await this.mobileTerminateApp({bundleId});
};

commands.queryAppState = async function (bundleId) {
return await this.mobileQueryAppState({bundleId});
};

export default commands;
2 changes: 1 addition & 1 deletion lib/commands/general.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ commands.getDeviceTime = iosCommands.general.getDeviceTime;
commands.getStrings = iosCommands.general.getStrings;

commands.removeApp = async function (bundleId) {
await this.opts.device.removeApp(bundleId);
return await this.mobileRemoveApp({bundleId});
};

commands.launchApp = iosCommands.general.launchApp;
Expand Down
5 changes: 3 additions & 2 deletions lib/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import fileMovementExtensions from './file-movement';
import screenshotExtensions from './screenshots';
import pasteboardExtensions from './pasteboard';
import locationExtensions from './location';
import recordscreenExtensions from './recordscreen';
import recordScreenExtensions from './recordscreen';
import lockExtensions from './lock';
import appManagementExtensions from './app-management';

let commands = {};

Expand All @@ -26,7 +27,7 @@ Object.assign(commands, actionsCommands, contextCommands, executeExtensions,
generalExtensions, logExtensions, webExtensions, timeoutExtensions,
navigationExtensions, elementExtensions, fileMovementExtensions,
alertExtensions, screenshotExtensions, pasteboardExtensions, locationExtensions,
recordscreenExtensions, lockExtensions
lockExtensions, recordScreenExtensions, appManagementExtensions
);

export default commands;
6 changes: 3 additions & 3 deletions lib/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ class XCUITestDriver extends BaseDriver {
}

if (this.opts.app) {
await this.installApp();
await this.installAUT();
this.logEvent('appInstalled');
}

Expand Down Expand Up @@ -872,7 +872,7 @@ class XCUITestDriver extends BaseDriver {
return true;
}

async installApp () {
async installAUT () {
if (this.isSafari()) {
return;
}
Expand All @@ -883,7 +883,7 @@ class XCUITestDriver extends BaseDriver {
}

if (this.isRealDevice()) {
await installToRealDevice (this.opts.device, this.opts.app, this.opts.bundleId, this.opts.noReset);
await installToRealDevice(this.opts.device, this.opts.app, this.opts.bundleId, this.opts.noReset);
} else {
await installToSimulator(this.opts.device, this.opts.app, this.opts.bundleId, this.opts.noReset);
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"lib": "lib"
},
"dependencies": {
"appium-base-driver": "^2.14.0",
"appium-base-driver": "^2.20.3",
"appium-ios-driver": "^1.30.0",
"appium-ios-simulator": "^2.6.0",
"appium-support": "^2.13.0",
Expand Down
2 changes: 1 addition & 1 deletion test/unit/driver-specs.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('driver commands', function () {
sandbox.stub(d, "startWdaSession", anoop);
sandbox.stub(d, "startWda", anoop);
sandbox.stub(d, "extractBundleId", anoop);
sandbox.stub(d, "installApp", anoop);
sandbox.stub(d, "installAUT", anoop);
sandbox.stub(iosSettings, "setLocale", anoop);
sandbox.stub(iosSettings, "setPreferences", anoop);
sandbox.stub(xcode, "getMaxIOSSDK", async function () {
Expand Down

0 comments on commit c2312be

Please sign in to comment.