This is an automated email from the ASF dual-hosted git repository.
erisu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cordova-android.git
The following commit(s) were added to refs/heads/master by this push:
new c04ea9b refactor: unify target resolution for devices & emulators
(#1101)
c04ea9b is described below
commit c04ea9b1c0bfaf79409de73adcfdaffc5997b8de
Author: Raphael von der GrĂ¼n <[email protected]>
AuthorDate: Fri Apr 9 08:37:56 2021 +0200
refactor: unify target resolution for devices & emulators (#1101)
* refactor: unify target resolution for devices & emulators
* fix: use unified target methods in platform-centric bins
---
bin/templates/cordova/lib/device.js | 48 -------
bin/templates/cordova/lib/emulator.js | 19 ---
bin/templates/cordova/lib/install-device | 10 +-
bin/templates/cordova/lib/install-emulator | 10 +-
bin/templates/cordova/lib/list-devices | 12 +-
bin/templates/cordova/lib/run.js | 78 ++++--------
bin/templates/cordova/lib/target.js | 86 ++++++++++++-
spec/unit/device.spec.js | 106 ----------------
spec/unit/emulator.spec.js | 47 -------
spec/unit/run.spec.js | 192 ++++------------------------
spec/unit/target.spec.js | 195 ++++++++++++++++++++++++++++-
11 files changed, 338 insertions(+), 465 deletions(-)
diff --git a/bin/templates/cordova/lib/device.js
b/bin/templates/cordova/lib/device.js
deleted file mode 100644
index 1ea4cdc..0000000
--- a/bin/templates/cordova/lib/device.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
-*/
-
-var build = require('./build');
-var Adb = require('./Adb');
-var CordovaError = require('cordova-common').CordovaError;
-
-/**
- * Returns a promise for the list of the device ID's found
- */
-module.exports.list = async () => {
- return (await Adb.devices())
- .filter(id => !id.startsWith('emulator-'));
-};
-
-module.exports.resolveTarget = function (target) {
- return this.list().then(function (device_list) {
- if (!device_list || !device_list.length) {
- return Promise.reject(new CordovaError('Failed to deploy to
device, no devices found.'));
- }
- // default device
- target = target || device_list[0];
-
- if (device_list.indexOf(target) < 0) {
- return Promise.reject(new CordovaError('ERROR: Unable to find
target \'' + target + '\'.'));
- }
-
- return build.detectArchitecture(target).then(function (arch) {
- return { target: target, arch: arch, isEmulator: false };
- });
- });
-};
diff --git a/bin/templates/cordova/lib/emulator.js
b/bin/templates/cordova/lib/emulator.js
index 7c9ee41..7a5fbd1 100644
--- a/bin/templates/cordova/lib/emulator.js
+++ b/bin/templates/cordova/lib/emulator.js
@@ -20,7 +20,6 @@
const execa = require('execa');
const fs = require('fs-extra');
var android_versions = require('android-versions');
-var build = require('./build');
var path = require('path');
var Adb = require('./Adb');
var events = require('cordova-common').events;
@@ -349,21 +348,3 @@ module.exports.wait_for_boot = function (emulator_id,
time_remaining) {
}
});
};
-
-module.exports.resolveTarget = function (target) {
- return this.list_started().then(function (emulator_list) {
- if (emulator_list.length < 1) {
- return Promise.reject(new CordovaError('No running Android
emulators found, please start an emulator before deploying your project.'));
- }
-
- // default emulator
- target = target || emulator_list[0];
- if (emulator_list.indexOf(target) < 0) {
- return Promise.reject(new CordovaError('Unable to find target \''
+ target + '\'. Failed to deploy to emulator.'));
- }
-
- return build.detectArchitecture(target).then(function (arch) {
- return { target: target, arch: arch, isEmulator: true };
- });
- });
-};
diff --git a/bin/templates/cordova/lib/install-device
b/bin/templates/cordova/lib/install-device
index 2d5a8b1..1340a4d 100755
--- a/bin/templates/cordova/lib/install-device
+++ b/bin/templates/cordova/lib/install-device
@@ -19,21 +19,21 @@
under the License.
*/
-const { install } = require('./target');
-var device = require('./device');
+const { resolve, install } = require('./target');
+
var args = process.argv;
+const targetSpec = { type: 'device' };
if (args.length > 2) {
- var install_target;
if (args[2].substring(0, 9) === '--target=') {
- install_target = args[2].substring(9, args[2].length);
+ targetSpec.id = args[2].substring(9, args[2].length);
} else {
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
process.exit(2);
}
}
-device.resolveTarget(install_target).then(install).catch(err => {
+resolve(targetSpec).then(install).catch(err => {
console.error('ERROR: ' + err);
process.exit(2);
});
diff --git a/bin/templates/cordova/lib/install-emulator
b/bin/templates/cordova/lib/install-emulator
index d67997e..f73cd05 100755
--- a/bin/templates/cordova/lib/install-emulator
+++ b/bin/templates/cordova/lib/install-emulator
@@ -19,21 +19,21 @@
under the License.
*/
-const { install } = require('./target');
-var emulator = require('./emulator');
+const { resolve, install } = require('./target');
+
var args = process.argv;
+const targetSpec = { type: 'emulator' };
-var install_target;
if (args.length > 2) {
if (args[2].substring(0, 9) === '--target=') {
- install_target = args[2].substring(9, args[2].length);
+ targetSpec.id = args[2].substring(9, args[2].length);
} else {
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
process.exit(2);
}
}
-emulator.resolveTarget(install_target).then(install).catch(err => {
+resolve(targetSpec).then(install).catch(err => {
console.error('ERROR: ' + err);
process.exit(2);
});
diff --git a/bin/templates/cordova/lib/list-devices
b/bin/templates/cordova/lib/list-devices
index 339c665..ed8e111 100755
--- a/bin/templates/cordova/lib/list-devices
+++ b/bin/templates/cordova/lib/list-devices
@@ -19,14 +19,16 @@
under the License.
*/
-var devices = require('./device');
+const { list } = require('./target');
// Usage support for when args are given
require('./check_reqs').check_android().then(function () {
- devices.list().then(function (device_list) {
- device_list && device_list.forEach(function (dev) {
- console.log(dev);
- });
+ list().then(targets => {
+ const deviceIds = targets
+ .filter(({ type }) => type === 'device')
+ .map(({ id }) => id);
+
+ console.log(deviceIds.join('\n'));
}, function (err) {
console.error('ERROR: ' + err);
process.exit(2);
diff --git a/bin/templates/cordova/lib/run.js b/bin/templates/cordova/lib/run.js
index 05ff775..1741659 100644
--- a/bin/templates/cordova/lib/run.js
+++ b/bin/templates/cordova/lib/run.js
@@ -19,22 +19,30 @@
var path = require('path');
var emulator = require('./emulator');
-var device = require('./device');
const target = require('./target');
var PackageType = require('./PackageType');
-const { CordovaError, events } = require('cordova-common');
+const { events } = require('cordova-common');
-function getInstallTarget (runOptions) {
- var install_target;
+/**
+ * Builds a target spec from a runOptions object
+ *
+ * @param {{target?: string, device?: boolean, emulator?: boolean}} runOptions
+ * @return {target.TargetSpec}
+ */
+function buildTargetSpec (runOptions) {
+ const spec = {};
if (runOptions.target) {
- install_target = runOptions.target;
+ spec.id = runOptions.target;
} else if (runOptions.device) {
- install_target = '--device';
+ spec.type = 'device';
} else if (runOptions.emulator) {
- install_target = '--emulator';
+ spec.type = 'emulator';
}
+ return spec;
+}
- return install_target;
+function formatResolvedTarget ({ id, type }) {
+ return `${type} ${id}`;
}
/**
@@ -51,55 +59,11 @@ module.exports.run = function (runOptions) {
runOptions = runOptions || {};
var self = this;
- var install_target = getInstallTarget(runOptions);
+ const spec = buildTargetSpec(runOptions);
+
+ return target.resolve(spec).then(function (resolvedTarget) {
+ events.emit('log', `Deploying to
${formatResolvedTarget(resolvedTarget)}`);
- return Promise.resolve().then(function () {
- if (!install_target) {
- // no target given, deploy to device if available, otherwise use
the emulator.
- return device.list().then(function (device_list) {
- if (device_list.length > 0) {
- events.emit('warn', 'No target specified, deploying to
device \'' + device_list[0] + '\'.');
- install_target = device_list[0];
- } else {
- events.emit('warn', 'No target specified and no devices
found, deploying to emulator');
- install_target = '--emulator';
- }
- });
- }
- }).then(function () {
- if (install_target === '--device') {
- return device.resolveTarget(null);
- } else if (install_target === '--emulator') {
- // Give preference to any already started emulators. Else, start
one.
- return emulator.list_started().then(function (started) {
- return started && started.length > 0 ? started[0] :
emulator.start();
- }).then(function (emulatorId) {
- return emulator.resolveTarget(emulatorId);
- });
- }
- // They specified a specific device/emulator ID.
- return device.list().then(function (devices) {
- if (devices.indexOf(install_target) > -1) {
- return device.resolveTarget(install_target);
- }
- return emulator.list_started().then(function (started_emulators) {
- if (started_emulators.indexOf(install_target) > -1) {
- return emulator.resolveTarget(install_target);
- }
- return emulator.list_images().then(function (avds) {
- // if target emulator isn't started, then start it.
- for (var avd in avds) {
- if (avds[avd].name === install_target) {
- return
emulator.start(install_target).then(function (emulatorId) {
- return emulator.resolveTarget(emulatorId);
- });
- }
- }
- return Promise.reject(new CordovaError(`Target
'${install_target}' not found, unable to run project`));
- });
- });
- });
- }).then(function (resolvedTarget) {
return new Promise((resolve) => {
const buildOptions =
require('./build').parseBuildOptions(runOptions, null, self.root);
@@ -112,7 +76,7 @@ module.exports.run = function (runOptions) {
resolve(self._builder.fetchBuildResults(buildOptions.buildType,
buildOptions.arch));
}).then(async function (buildResults) {
- if (resolvedTarget && resolvedTarget.isEmulator) {
+ if (resolvedTarget.type === 'emulator') {
await emulator.wait_for_boot(resolvedTarget.id);
}
diff --git a/bin/templates/cordova/lib/target.js
b/bin/templates/cordova/lib/target.js
index 1494144..ea03640 100644
--- a/bin/templates/cordova/lib/target.js
+++ b/bin/templates/cordova/lib/target.js
@@ -18,17 +18,97 @@
*/
const path = require('path');
+const { inspect } = require('util');
const Adb = require('./Adb');
const build = require('./build');
+const emulator = require('./emulator');
const AndroidManifest = require('./AndroidManifest');
+const { compareBy } = require('./utils');
const { retryPromise } = require('./retry');
-const { events } = require('cordova-common');
+const { events, CordovaError } = require('cordova-common');
const INSTALL_COMMAND_TIMEOUT = 5 * 60 * 1000;
const NUM_INSTALL_RETRIES = 3;
const EXEC_KILL_SIGNAL = 'SIGKILL';
-exports.install = async function ({ target, arch, isEmulator }, buildResults) {
+/**
+ * @typedef { 'device' | 'emulator' } TargetType
+ * @typedef { { id: string, type: TargetType } } Target
+ * @typedef { { id?: string, type?: TargetType } } TargetSpec
+ */
+
+/**
+ * Returns a list of available targets (connected devices & started emulators)
+ *
+ * @return {Promise<Target[]>}
+ */
+exports.list = async () => {
+ return (await Adb.devices())
+ .map(id => ({
+ id,
+ type: id.startsWith('emulator-') ? 'emulator' : 'device'
+ }));
+};
+
+/**
+ * @param {TargetSpec?} spec
+ * @return {Promise<Target>}
+ */
+async function resolveToOnlineTarget (spec = {}) {
+ const targetList = await exports.list();
+ if (targetList.length === 0) return null;
+
+ // Sort by type: devices first, then emulators.
+ targetList.sort(compareBy(t => t.type));
+
+ // Find first matching target for spec. {} matches any target.
+ return targetList.find(target =>
+ Object.keys(spec).every(k => spec[k] === target[k])
+ ) || null;
+}
+
+async function isEmulatorName (name) {
+ const emus = await emulator.list_images();
+ return emus.some(avd => avd.name === name);
+}
+
+/**
+ * @param {TargetSpec?} spec
+ * @return {Promise<Target>}
+ */
+async function resolveToOfflineEmulator (spec = {}) {
+ if (spec.type === 'device') return null;
+ if (spec.id && !(await isEmulatorName(spec.id))) return null;
+
+ // try to start an emulator with name spec.id
+ // if spec.id is undefined, picks best match regarding target API
+ const emulatorId = await emulator.start(spec.id);
+
+ return { id: emulatorId, type: 'emulator' };
+}
+
+/**
+ * @param {TargetSpec?} spec
+ * @return {Promise<Target & {arch: string}>}
+ */
+exports.resolve = async (spec = {}) => {
+ events.emit('verbose', `Trying to find target matching ${inspect(spec)}`);
+
+ const resolvedTarget =
+ (await resolveToOnlineTarget(spec)) ||
+ (await resolveToOfflineEmulator(spec));
+
+ if (!resolvedTarget) {
+ throw new CordovaError(`Could not find target matching
${inspect(spec)}`);
+ }
+
+ return {
+ ...resolvedTarget,
+ arch: await build.detectArchitecture(resolvedTarget.id)
+ };
+};
+
+exports.install = async function ({ id: target, arch, type }, buildResults) {
const apk_path = build.findBestApkForArchitecture(buildResults, arch);
const manifest = new AndroidManifest(path.join(__dirname,
'../../app/src/main/AndroidManifest.xml'));
const pkgName = manifest.getPackageId();
@@ -56,7 +136,7 @@ exports.install = async function ({ target, arch, isEmulator
}, buildResults) {
}
}
- if (isEmulator) {
+ if (type === 'emulator') {
// Work around sporadic emulator hangs:
http://issues.apache.org/jira/browse/CB-9119
await retryPromise(NUM_INSTALL_RETRIES, () => doInstall({
timeout: INSTALL_COMMAND_TIMEOUT,
diff --git a/spec/unit/device.spec.js b/spec/unit/device.spec.js
deleted file mode 100644
index 499bb63..0000000
--- a/spec/unit/device.spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
-*/
-
-const rewire = require('rewire');
-
-const CordovaError = require('cordova-common').CordovaError;
-
-describe('device', () => {
- const DEVICE_LIST = ['device1', 'device2', 'device3'];
- let AdbSpy;
- let device;
-
- beforeEach(() => {
- device = rewire('../../bin/templates/cordova/lib/device');
- AdbSpy = jasmine.createSpyObj('Adb', ['devices', 'install', 'shell',
'start', 'uninstall']);
- device.__set__('Adb', AdbSpy);
- });
-
- describe('list', () => {
- it('should return a list of all connected devices', () => {
- AdbSpy.devices.and.resolveTo(['emulator-5556',
'123a76565509e124']);
-
- return device.list().then(list => {
- expect(list).toEqual(['123a76565509e124']);
- });
- });
- });
-
- describe('resolveTarget', () => {
- let buildSpy;
-
- beforeEach(() => {
- buildSpy = jasmine.createSpyObj('build', ['detectArchitecture']);
- buildSpy.detectArchitecture.and.returnValue(Promise.resolve());
- device.__set__('build', buildSpy);
-
- spyOn(device,
'list').and.returnValue(Promise.resolve(DEVICE_LIST));
- });
-
- it('should select the first device to be the target if none is
specified', () => {
- return device.resolveTarget().then(deviceInfo => {
- expect(deviceInfo.target).toBe(DEVICE_LIST[0]);
- });
- });
-
- it('should use the given target instead of the default', () => {
- return device.resolveTarget(DEVICE_LIST[2]).then(deviceInfo => {
- expect(deviceInfo.target).toBe(DEVICE_LIST[2]);
- });
- });
-
- it('should set emulator to false', () => {
- return device.resolveTarget().then(deviceInfo => {
- expect(deviceInfo.isEmulator).toBe(false);
- });
- });
-
- it('should throw an error if there are no devices', () => {
- device.list.and.returnValue(Promise.resolve([]));
-
- return device.resolveTarget().then(
- () => fail('Unexpectedly resolved'),
- err => {
- expect(err).toEqual(jasmine.any(CordovaError));
- }
- );
- });
-
- it('should throw an error if the specified target does not exist', ()
=> {
- return device.resolveTarget('nonexistent-target').then(
- () => fail('Unexpectedly resolved'),
- err => {
- expect(err).toEqual(jasmine.any(CordovaError));
- }
- );
- });
-
- it('should detect the architecture and return it with the device
info', () => {
- const target = DEVICE_LIST[1];
- const arch = 'unittestarch';
-
- buildSpy.detectArchitecture.and.returnValue(Promise.resolve(arch));
-
- return device.resolveTarget(target).then(deviceInfo => {
-
expect(buildSpy.detectArchitecture).toHaveBeenCalledWith(target);
- expect(deviceInfo.arch).toBe(arch);
- });
- });
- });
-});
diff --git a/spec/unit/emulator.spec.js b/spec/unit/emulator.spec.js
index c15eaee..3507926 100644
--- a/spec/unit/emulator.spec.js
+++ b/spec/unit/emulator.spec.js
@@ -26,7 +26,6 @@ const CordovaError = require('cordova-common').CordovaError;
const check_reqs = require('../../bin/templates/cordova/lib/check_reqs');
describe('emulator', () => {
- const EMULATOR_LIST = ['emulator-5555', 'emulator-5556', 'emulator-5557'];
let emu;
beforeEach(() => {
@@ -529,50 +528,4 @@ describe('emulator', () => {
});
});
});
-
- describe('resolveTarget', () => {
- const arch = 'arm7-test';
-
- beforeEach(() => {
- const buildSpy = jasmine.createSpyObj('build',
['detectArchitecture']);
- buildSpy.detectArchitecture.and.returnValue(Promise.resolve(arch));
- emu.__set__('build', buildSpy);
-
- spyOn(emu,
'list_started').and.returnValue(Promise.resolve(EMULATOR_LIST));
- });
-
- it('should throw an error if there are no running emulators', () => {
- emu.list_started.and.returnValue(Promise.resolve([]));
-
- return emu.resolveTarget().then(
- () => fail('Unexpectedly resolved'),
- err => {
- expect(err).toEqual(jasmine.any(CordovaError));
- }
- );
- });
-
- it('should throw an error if the requested emulator is not running',
() => {
- const targetEmulator = 'unstarted-emu';
-
- return emu.resolveTarget(targetEmulator).then(
- () => fail('Unexpectedly resolved'),
- err => {
- expect(err.message).toContain(targetEmulator);
- }
- );
- });
-
- it('should return info on the first running emulator if none is
specified', () => {
- return emu.resolveTarget().then(emulatorInfo => {
- expect(emulatorInfo.target).toBe(EMULATOR_LIST[0]);
- });
- });
-
- it('should return the emulator info', () => {
- return emu.resolveTarget(EMULATOR_LIST[1]).then(emulatorInfo => {
- expect(emulatorInfo).toEqual({ target: EMULATOR_LIST[1], arch,
isEmulator: true });
- });
- });
- });
});
diff --git a/spec/unit/run.spec.js b/spec/unit/run.spec.js
index 287905a..e780e68 100644
--- a/spec/unit/run.spec.js
+++ b/spec/unit/run.spec.js
@@ -25,45 +25,38 @@ describe('run', () => {
beforeEach(() => {
run = rewire('../../bin/templates/cordova/lib/run');
+ run.__set__({
+ events: jasmine.createSpyObj('eventsSpy', ['emit'])
+ });
});
- describe('getInstallTarget', () => {
- const targetOpts = { target: 'emu' };
- const deviceOpts = { device: true };
- const emulatorOpts = { emulator: true };
- const emptyOpts = {};
-
+ describe('buildTargetSpec', () => {
it('Test#001 : should select correct target based on the run opts', ()
=> {
- const getInstallTarget = run.__get__('getInstallTarget');
- expect(getInstallTarget(targetOpts)).toBe('emu');
- expect(getInstallTarget(deviceOpts)).toBe('--device');
- expect(getInstallTarget(emulatorOpts)).toBe('--emulator');
- expect(getInstallTarget(emptyOpts)).toBeUndefined();
+ const buildTargetSpec = run.__get__('buildTargetSpec');
+
+ expect(buildTargetSpec({ target: 'emu' })).toEqual({ id: 'emu' });
+ expect(buildTargetSpec({ device: true })).toEqual({ type: 'device'
});
+ expect(buildTargetSpec({ emulator: true })).toEqual({ type:
'emulator' });
+ expect(buildTargetSpec({})).toEqual({});
});
});
describe('run method', () => {
- let deviceSpyObj;
- let emulatorSpyObj;
- let targetSpyObj;
- let eventsSpyObj;
- let getInstallTargetSpy;
+ let targetSpyObj, emulatorSpyObj, resolvedTarget;
beforeEach(() => {
- deviceSpyObj = jasmine.createSpyObj('deviceSpy', ['list',
'resolveTarget']);
- emulatorSpyObj = jasmine.createSpyObj('emulatorSpy',
['list_images', 'list_started', 'resolveTarget', 'start', 'wait_for_boot']);
- eventsSpyObj = jasmine.createSpyObj('eventsSpy', ['emit']);
- getInstallTargetSpy = jasmine.createSpy('getInstallTargetSpy');
+ resolvedTarget = { id: 'dev1', type: 'device', arch: 'atari' };
- targetSpyObj = jasmine.createSpyObj('target', ['install']);
+ targetSpyObj = jasmine.createSpyObj('deviceSpy', ['resolve',
'install']);
+ targetSpyObj.resolve.and.resolveTo(resolvedTarget);
targetSpyObj.install.and.resolveTo();
+ emulatorSpyObj = jasmine.createSpyObj('emulatorSpy',
['wait_for_boot']);
+ emulatorSpyObj.wait_for_boot.and.resolveTo();
+
run.__set__({
- device: deviceSpyObj,
- emulator: emulatorSpyObj,
target: targetSpyObj,
- events: eventsSpyObj,
- getInstallTarget: getInstallTargetSpy
+ emulator: emulatorSpyObj
});
// run needs `this` to behave like an Api instance
@@ -72,152 +65,19 @@ describe('run', () => {
});
});
- it('should run on default device when no target arguments are
specified', () => {
- const deviceList = ['testDevice1', 'testDevice2'];
-
- getInstallTargetSpy.and.returnValue(null);
- deviceSpyObj.list.and.returnValue(Promise.resolve(deviceList));
-
- return run.run().then(() => {
-
expect(deviceSpyObj.resolveTarget).toHaveBeenCalledWith(deviceList[0]);
- });
- });
-
- it('should run on emulator when no target arguments are specified, and
no devices are found', () => {
- const deviceList = [];
-
- getInstallTargetSpy.and.returnValue(null);
- deviceSpyObj.list.and.returnValue(Promise.resolve(deviceList));
- emulatorSpyObj.list_started.and.returnValue(Promise.resolve([]));
-
- return run.run().then(() => {
- expect(emulatorSpyObj.list_started).toHaveBeenCalled();
- });
- });
-
- it('should run on default device when device is requested, but none
specified', () => {
- getInstallTargetSpy.and.returnValue('--device');
-
- return run.run().then(() => {
- // Default device is selected by calling
device.resolveTarget(null)
- expect(deviceSpyObj.resolveTarget).toHaveBeenCalledWith(null);
- });
- });
-
- it('should run on a running emulator if one exists', () => {
- const emulatorList = ['emulator1', 'emulator2'];
-
- getInstallTargetSpy.and.returnValue('--emulator');
-
emulatorSpyObj.list_started.and.returnValue(Promise.resolve(emulatorList));
-
- return run.run().then(() => {
-
expect(emulatorSpyObj.resolveTarget).toHaveBeenCalledWith(emulatorList[0]);
- });
- });
-
- it('should start an emulator and run on that if none is running', ()
=> {
- const emulatorList = [];
- const defaultEmulator = 'default-emu';
-
- getInstallTargetSpy.and.returnValue('--emulator');
-
emulatorSpyObj.list_started.and.returnValue(Promise.resolve(emulatorList));
-
emulatorSpyObj.start.and.returnValue(Promise.resolve(defaultEmulator));
-
+ it('should install on target after build', () => {
return run.run().then(() => {
-
expect(emulatorSpyObj.resolveTarget).toHaveBeenCalledWith(defaultEmulator);
- });
- });
-
- it('should run on a named device if it is specified', () => {
- const deviceList = ['device1', 'device2', 'device3'];
- getInstallTargetSpy.and.returnValue(deviceList[1]);
-
- deviceSpyObj.list.and.returnValue(Promise.resolve(deviceList));
-
- return run.run().then(() => {
-
expect(deviceSpyObj.resolveTarget).toHaveBeenCalledWith(deviceList[1]);
- });
- });
-
- it('should run on a named emulator if it is specified', () => {
- const startedEmulatorList = ['emu1', 'emu2', 'emu3'];
- getInstallTargetSpy.and.returnValue(startedEmulatorList[2]);
-
- deviceSpyObj.list.and.returnValue(Promise.resolve([]));
-
emulatorSpyObj.list_started.and.returnValue(Promise.resolve(startedEmulatorList));
-
- return run.run().then(() => {
-
expect(emulatorSpyObj.resolveTarget).toHaveBeenCalledWith(startedEmulatorList[2]);
- });
- });
-
- it('should start named emulator and then run on it if it is
specified', () => {
- const emulatorList = [
- { name: 'emu1', id: 1 },
- { name: 'emu2', id: 2 },
- { name: 'emu3', id: 3 }
- ];
- getInstallTargetSpy.and.returnValue(emulatorList[2].name);
-
- deviceSpyObj.list.and.returnValue(Promise.resolve([]));
- emulatorSpyObj.list_started.and.returnValue(Promise.resolve([]));
-
emulatorSpyObj.list_images.and.returnValue(Promise.resolve(emulatorList));
-
emulatorSpyObj.start.and.returnValue(Promise.resolve(emulatorList[2].id));
-
- return run.run().then(() => {
-
expect(emulatorSpyObj.start).toHaveBeenCalledWith(emulatorList[2].name);
-
expect(emulatorSpyObj.resolveTarget).toHaveBeenCalledWith(emulatorList[2].id);
- });
- });
-
- it('should throw an error if target is specified but does not exist',
() => {
- const emulatorList = [{ name: 'emu1', id: 1 }];
- const deviceList = ['device1'];
- const target = 'nonexistentdevice';
- getInstallTargetSpy.and.returnValue(target);
-
- deviceSpyObj.list.and.returnValue(Promise.resolve(deviceList));
- emulatorSpyObj.list_started.and.returnValue(Promise.resolve([]));
-
emulatorSpyObj.list_images.and.returnValue(Promise.resolve(emulatorList));
-
- return run.run().then(
- () => fail('Expected error to be thrown'),
- err => expect(err.message).toContain(target)
- );
- });
-
- it('should install on device after build', () => {
- const deviceTarget = { target: 'device1', isEmulator: false };
- getInstallTargetSpy.and.returnValue('--device');
- deviceSpyObj.resolveTarget.and.returnValue(deviceTarget);
-
- return run.run().then(() => {
-
expect(targetSpyObj.install).toHaveBeenCalledWith(deviceTarget, { apkPaths: [],
buildType: 'debug' });
- });
- });
-
- it('should install on emulator after build', () => {
- const emulatorTarget = { target: 'emu1', isEmulator: true };
- getInstallTargetSpy.and.returnValue('--emulator');
-
emulatorSpyObj.list_started.and.returnValue(Promise.resolve([emulatorTarget.target]));
- emulatorSpyObj.resolveTarget.and.returnValue(emulatorTarget);
- emulatorSpyObj.wait_for_boot.and.returnValue(Promise.resolve());
-
- return run.run().then(() => {
-
expect(targetSpyObj.install).toHaveBeenCalledWith(emulatorTarget, { apkPaths:
[], buildType: 'debug' });
+ expect(targetSpyObj.install).toHaveBeenCalledWith(
+ resolvedTarget,
+ { apkPaths: [], buildType: 'debug' }
+ );
});
});
it('should fail with the error message if --packageType=bundle setting
is used', () => {
- const deviceList = ['testDevice1', 'testDevice2'];
- getInstallTargetSpy.and.returnValue(null);
-
- deviceSpyObj.list.and.returnValue(Promise.resolve(deviceList));
-
- return run.run({ argv: ['--packageType=bundle'] }).then(
- () => fail('Expected error to be thrown'),
- err => expect(err).toContain('Package type "bundle" is not
supported during cordova run.')
- );
+ targetSpyObj.resolve.and.resolveTo(resolvedTarget);
+ return expectAsync(run.run({ argv: ['--packageType=bundle'] }))
+ .toBeRejectedWith(jasmine.stringMatching(/Package type
"bundle" is not supported/));
});
});
diff --git a/spec/unit/target.spec.js b/spec/unit/target.spec.js
index 345cda1..0e0fcc6 100644
--- a/spec/unit/target.spec.js
+++ b/spec/unit/target.spec.js
@@ -27,6 +27,193 @@ describe('target', () => {
target = rewire('../../bin/templates/cordova/lib/target');
});
+ describe('list', () => {
+ it('should return available targets from Adb.devices', () => {
+ const AdbSpy = jasmine.createSpyObj('Adb', ['devices']);
+ AdbSpy.devices.and.resolveTo(['emulator-5556',
'123a76565509e124']);
+ target.__set__('Adb', AdbSpy);
+
+ return target.list().then(emus => {
+ expect(emus).toEqual([
+ { id: 'emulator-5556', type: 'emulator' },
+ { id: '123a76565509e124', type: 'device' }
+ ]);
+ });
+ });
+ });
+
+ describe('resolveToOnlineTarget', () => {
+ let resolveToOnlineTarget, emus, devs;
+
+ beforeEach(() => {
+ resolveToOnlineTarget = target.__get__('resolveToOnlineTarget');
+
+ emus = [
+ { id: 'emu1', type: 'emulator' },
+ { id: 'emu2', type: 'emulator' }
+ ];
+ devs = [
+ { id: 'dev1', type: 'device' },
+ { id: 'dev2', type: 'device' }
+ ];
+
+ spyOn(target, 'list').and.returnValue([...emus, ...devs]);
+ });
+
+ it('should return first device when no target arguments are
specified', async () => {
+ return resolveToOnlineTarget().then(result => {
+ expect(result.id).toBe('dev1');
+ });
+ });
+
+ it('should return first emulator when no target arguments are
specified and no devices are found', async () => {
+ target.list.and.resolveTo(emus);
+ return resolveToOnlineTarget().then(result => {
+ expect(result.id).toBe('emu1');
+ });
+ });
+
+ it('should return first device when type device is specified', async
() => {
+ return resolveToOnlineTarget({ type: 'device' }).then(result => {
+ expect(result.id).toBe('dev1');
+ });
+ });
+
+ it('should return first running emulator when type emulator is
specified', async () => {
+ return resolveToOnlineTarget({ type: 'emulator' }).then(result => {
+ expect(result.id).toBe('emu1');
+ });
+ });
+
+ it('should return a device that matches given ID', async () => {
+ return resolveToOnlineTarget({ id: 'dev2' }).then(result => {
+ expect(result.id).toBe('dev2');
+ });
+ });
+
+ it('should return a running emulator that matches given ID', async ()
=> {
+ return resolveToOnlineTarget({ id: 'emu2' }).then(result => {
+ expect(result.id).toBe('emu2');
+ });
+ });
+
+ it('should return null if there are no online targets', async () => {
+ target.list.and.resolveTo([]);
+ return expectAsync(resolveToOnlineTarget())
+ .toBeResolvedTo(null);
+ });
+
+ it('should return null if no target matches given ID', async () => {
+ return expectAsync(resolveToOnlineTarget({ id: 'foo' }))
+ .toBeResolvedTo(null);
+ });
+
+ it('should return null if no target matches given type', async () => {
+ target.list.and.resolveTo(devs);
+ return expectAsync(resolveToOnlineTarget({ type: 'emulator' }))
+ .toBeResolvedTo(null);
+ });
+ });
+
+ describe('resolveToOfflineEmulator', () => {
+ const emuId = 'emulator-5554';
+ let resolveToOfflineEmulator, emulatorSpyObj;
+
+ beforeEach(() => {
+ resolveToOfflineEmulator =
target.__get__('resolveToOfflineEmulator');
+
+ emulatorSpyObj = jasmine.createSpyObj('emulatorSpy', ['start']);
+ emulatorSpyObj.start.and.resolveTo(emuId);
+
+ target.__set__({
+ emulator: emulatorSpyObj,
+ isEmulatorName: name => name.startsWith('emu')
+ });
+ });
+
+ it('should start an emulator and run on that if none is running', ()
=> {
+ return resolveToOfflineEmulator().then(result => {
+ expect(result).toEqual({ id: emuId, type: 'emulator' });
+ expect(emulatorSpyObj.start).toHaveBeenCalled();
+ });
+ });
+
+ it('should start named emulator and then run on it if it is
specified', () => {
+ return resolveToOfflineEmulator({ id: 'emu3' }).then(result => {
+ expect(result).toEqual({ id: emuId, type: 'emulator' });
+ expect(emulatorSpyObj.start).toHaveBeenCalledWith('emu3');
+ });
+ });
+
+ it('should return null if given ID is not an avd name', () => {
+ return resolveToOfflineEmulator({ id: 'dev1' }).then(result => {
+ expect(result).toBe(null);
+ expect(emulatorSpyObj.start).not.toHaveBeenCalled();
+ });
+ });
+
+ it('should return null if given type is not emulator', () => {
+ return resolveToOfflineEmulator({ type: 'device' }).then(result =>
{
+ expect(result).toBe(null);
+ expect(emulatorSpyObj.start).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('resolve', () => {
+ let resolveToOnlineTarget, resolveToOfflineEmulator;
+
+ beforeEach(() => {
+ resolveToOnlineTarget = jasmine.createSpy('resolveToOnlineTarget')
+ .and.resolveTo(null);
+
+ resolveToOfflineEmulator =
jasmine.createSpy('resolveToOfflineEmulator')
+ .and.resolveTo(null);
+
+ target.__set__({
+ resolveToOnlineTarget,
+ resolveToOfflineEmulator,
+ build: { detectArchitecture: id => id + '-arch' }
+ });
+ });
+
+ it('should delegate to resolveToOnlineTarget', () => {
+ const spec = { type: 'device' };
+ resolveToOnlineTarget.and.resolveTo({ id: 'dev1', type: 'device'
});
+
+ return target.resolve(spec).then(result => {
+ expect(result.id).toBe('dev1');
+ expect(resolveToOnlineTarget).toHaveBeenCalledWith(spec);
+ expect(resolveToOfflineEmulator).not.toHaveBeenCalled();
+ });
+ });
+
+ it('should delegate to resolveToOfflineEmulator if
resolveToOnlineTarget fails', () => {
+ const spec = { type: 'emulator' };
+ resolveToOfflineEmulator.and.resolveTo({ id: 'emu1', type:
'emulator' });
+
+ return target.resolve(spec).then(result => {
+ expect(result.id).toBe('emu1');
+ expect(resolveToOnlineTarget).toHaveBeenCalledWith(spec);
+ expect(resolveToOfflineEmulator).toHaveBeenCalledWith(spec);
+ });
+ });
+
+ it('should add the target arch', () => {
+ const spec = { type: 'device' };
+ resolveToOnlineTarget.and.resolveTo({ id: 'dev1', type: 'device'
});
+
+ return target.resolve(spec).then(result => {
+ expect(result.arch).toBe('dev1-arch');
+ });
+ });
+
+ it('should throw an error if target cannot be resolved', () => {
+ return expectAsync(target.resolve())
+ .toBeRejectedWithError(/Could not find target matching/);
+ });
+ });
+
describe('install', () => {
let AndroidManifestSpy;
let AndroidManifestFns;
@@ -36,7 +223,7 @@ describe('target', () => {
let installTarget;
beforeEach(() => {
- installTarget = { target: 'emulator-5556', isEmulator: true, arch:
'atari' };
+ installTarget = { id: 'emulator-5556', type: 'emulator', arch:
'atari' };
buildSpy = jasmine.createSpyObj('build',
['findBestApkForArchitecture']);
target.__set__('build', buildSpy);
@@ -60,7 +247,7 @@ describe('target', () => {
it('should install to the passed target', () => {
return target.install(installTarget, {}).then(() => {
-
expect(AdbSpy.install.calls.argsFor(0)[0]).toBe(installTarget.target);
+
expect(AdbSpy.install.calls.argsFor(0)[0]).toBe(installTarget.id);
});
});
@@ -108,7 +295,7 @@ describe('target', () => {
it('should unlock the screen on device', () => {
return target.install(installTarget, {}).then(() => {
-
expect(AdbSpy.shell).toHaveBeenCalledWith(installTarget.target, 'input keyevent
82');
+ expect(AdbSpy.shell).toHaveBeenCalledWith(installTarget.id,
'input keyevent 82');
});
});
@@ -119,7 +306,7 @@ describe('target', () => {
AndroidManifestGetActivitySpy.getName.and.returnValue(activityName);
return target.install(installTarget, {}).then(() => {
-
expect(AdbSpy.start).toHaveBeenCalledWith(installTarget.target,
`${packageId}/.${activityName}`);
+ expect(AdbSpy.start).toHaveBeenCalledWith(installTarget.id,
`${packageId}/.${activityName}`);
});
});
});
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]