forked from github/cordova-android
Merge pull request #462 from Menardi/device_tests
Device: Add unit tests and remove Q
This commit is contained in:
commit
bd2ad99402
7
bin/templates/cordova/lib/device.js
vendored
7
bin/templates/cordova/lib/device.js
vendored
@ -19,7 +19,6 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Q = require('q');
|
|
||||||
var build = require('./build');
|
var build = require('./build');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var Adb = require('./Adb');
|
var Adb = require('./Adb');
|
||||||
@ -53,13 +52,13 @@ module.exports.list = function (lookHarder) {
|
|||||||
module.exports.resolveTarget = function (target) {
|
module.exports.resolveTarget = function (target) {
|
||||||
return this.list(true).then(function (device_list) {
|
return this.list(true).then(function (device_list) {
|
||||||
if (!device_list || !device_list.length) {
|
if (!device_list || !device_list.length) {
|
||||||
return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
|
return Promise.reject(new CordovaError('Failed to deploy to device, no devices found.'));
|
||||||
}
|
}
|
||||||
// default device
|
// default device
|
||||||
target = target || device_list[0];
|
target = target || device_list[0];
|
||||||
|
|
||||||
if (device_list.indexOf(target) < 0) {
|
if (device_list.indexOf(target) < 0) {
|
||||||
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
|
return Promise.reject(new CordovaError('ERROR: Unable to find target \'' + target + '\'.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return build.detectArchitecture(target).then(function (arch) {
|
return build.detectArchitecture(target).then(function (arch) {
|
||||||
@ -74,7 +73,7 @@ module.exports.resolveTarget = function (target) {
|
|||||||
* Returns a promise.
|
* Returns a promise.
|
||||||
*/
|
*/
|
||||||
module.exports.install = function (target, buildResults) {
|
module.exports.install = function (target, buildResults) {
|
||||||
return Q().then(function () {
|
return Promise.resolve().then(function () {
|
||||||
if (target && typeof target === 'object') {
|
if (target && typeof target === 'object') {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ if (args.length > 2) {
|
|||||||
var install_target;
|
var install_target;
|
||||||
if (args[2].substring(0, 9) === '--target=') {
|
if (args[2].substring(0, 9) === '--target=') {
|
||||||
install_target = args[2].substring(9, args[2].length);
|
install_target = args[2].substring(9, args[2].length);
|
||||||
device.install(install_target).done(null, function (err) {
|
device.install(install_target).catch(function (err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error('ERROR: ' + err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
@ -35,7 +35,7 @@ if (args.length > 2) {
|
|||||||
process.exit(2);
|
process.exit(2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
device.install().done(null, function (err) {
|
device.install().catch(function (err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error('ERROR: ' + err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
|
@ -23,7 +23,7 @@ var devices = require('./device');
|
|||||||
|
|
||||||
// Usage support for when args are given
|
// Usage support for when args are given
|
||||||
require('./check_reqs').check_android().then(function () {
|
require('./check_reqs').check_android().then(function () {
|
||||||
devices.list().done(function (device_list) {
|
devices.list().then(function (device_list) {
|
||||||
device_list && device_list.forEach(function (dev) {
|
device_list && device_list.forEach(function (dev) {
|
||||||
console.log(dev);
|
console.log(dev);
|
||||||
});
|
});
|
||||||
|
233
spec/unit/device.spec.js
Normal file
233
spec/unit/device.spec.js
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
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 the list from adb devices', () => {
|
||||||
|
AdbSpy.devices.and.returnValue(Promise.resolve(DEVICE_LIST));
|
||||||
|
|
||||||
|
return device.list().then(list => {
|
||||||
|
expect(list).toEqual(DEVICE_LIST);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should kill adb and try to get devices again if none are found the first time, and `lookHarder` is set', () => {
|
||||||
|
const spawnSpy = jasmine.createSpy('spawn').and.returnValue(Promise.resolve());
|
||||||
|
device.__set__('spawn', spawnSpy);
|
||||||
|
AdbSpy.devices.and.returnValues(Promise.resolve([]), Promise.resolve(DEVICE_LIST));
|
||||||
|
|
||||||
|
return device.list(true).then(list => {
|
||||||
|
expect(spawnSpy).toHaveBeenCalledWith('killall', ['adb']);
|
||||||
|
expect(list).toBe(DEVICE_LIST);
|
||||||
|
expect(AdbSpy.devices).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the empty list if killing adb fails', () => {
|
||||||
|
const emptyDevices = [];
|
||||||
|
const spawnSpy = jasmine.createSpy('spawn').and.returnValue(Promise.reject());
|
||||||
|
device.__set__('spawn', spawnSpy);
|
||||||
|
AdbSpy.devices.and.returnValues(Promise.resolve(emptyDevices));
|
||||||
|
|
||||||
|
return device.list(true).then(list => {
|
||||||
|
expect(spawnSpy).toHaveBeenCalledWith('killall', ['adb']);
|
||||||
|
expect(list).toBe(emptyDevices);
|
||||||
|
expect(AdbSpy.devices).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('install', () => {
|
||||||
|
let AndroidManifestSpy;
|
||||||
|
let AndroidManifestFns;
|
||||||
|
let AndroidManifestGetActivitySpy;
|
||||||
|
let buildSpy;
|
||||||
|
let target;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
target = { target: DEVICE_LIST[0], arch: 'arm7', isEmulator: false };
|
||||||
|
|
||||||
|
buildSpy = jasmine.createSpyObj('build', ['findBestApkForArchitecture']);
|
||||||
|
device.__set__('build', buildSpy);
|
||||||
|
|
||||||
|
AndroidManifestFns = jasmine.createSpyObj('AndroidManifestFns', ['getPackageId', 'getActivity']);
|
||||||
|
AndroidManifestGetActivitySpy = jasmine.createSpyObj('getActivity', ['getName']);
|
||||||
|
AndroidManifestFns.getActivity.and.returnValue(AndroidManifestGetActivitySpy);
|
||||||
|
AndroidManifestSpy = jasmine.createSpy('AndroidManifest').and.returnValue(AndroidManifestFns);
|
||||||
|
device.__set__('AndroidManifest', AndroidManifestSpy);
|
||||||
|
|
||||||
|
AdbSpy.install.and.returnValue(Promise.resolve());
|
||||||
|
AdbSpy.shell.and.returnValue(Promise.resolve());
|
||||||
|
AdbSpy.start.and.returnValue(Promise.resolve());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the full target object if only id is specified', () => {
|
||||||
|
const targetId = DEVICE_LIST[0];
|
||||||
|
spyOn(device, 'resolveTarget').and.returnValue(Promise.resolve(target));
|
||||||
|
|
||||||
|
return device.install(targetId).then(() => {
|
||||||
|
expect(device.resolveTarget).toHaveBeenCalledWith(targetId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should install to the passed target', () => {
|
||||||
|
return device.install(target).then(() => {
|
||||||
|
expect(AdbSpy.install).toHaveBeenCalledWith(target.target, undefined, jasmine.anything());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should install the correct apk based on the architecture and build results', () => {
|
||||||
|
const buildResults = {
|
||||||
|
apkPaths: 'path/to/apks',
|
||||||
|
buildType: 'debug',
|
||||||
|
buildMethod: 'foo'
|
||||||
|
};
|
||||||
|
|
||||||
|
const apkPath = 'my/apk/path/app.apk';
|
||||||
|
buildSpy.findBestApkForArchitecture.and.returnValue(apkPath);
|
||||||
|
|
||||||
|
return device.install(target, buildResults).then(() => {
|
||||||
|
expect(buildSpy.findBestApkForArchitecture).toHaveBeenCalledWith(buildResults, target.arch);
|
||||||
|
expect(AdbSpy.install).toHaveBeenCalledWith(jasmine.anything(), apkPath, jasmine.anything());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should uninstall and reinstall app if failure is due to different certificates', () => {
|
||||||
|
AdbSpy.install.and.returnValues(
|
||||||
|
Promise.reject('Failed to install: INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES'),
|
||||||
|
Promise.resolve()
|
||||||
|
);
|
||||||
|
|
||||||
|
AdbSpy.uninstall.and.callFake(() => {
|
||||||
|
expect(AdbSpy.install).toHaveBeenCalledTimes(1);
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
return device.install(target).then(() => {
|
||||||
|
expect(AdbSpy.install).toHaveBeenCalledTimes(2);
|
||||||
|
expect(AdbSpy.uninstall).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw any error not caused by different certificates', () => {
|
||||||
|
const errorMsg = new CordovaError('Failed to install');
|
||||||
|
AdbSpy.install.and.returnValues(Promise.reject(errorMsg));
|
||||||
|
|
||||||
|
return device.install(target).then(
|
||||||
|
() => fail('Unexpectedly resolved'),
|
||||||
|
err => {
|
||||||
|
expect(err).toBe(errorMsg);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should unlock the screen on device', () => {
|
||||||
|
return device.install(target).then(() => {
|
||||||
|
expect(AdbSpy.shell).toHaveBeenCalledWith(target.target, 'input keyevent 82');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should start the newly installed app on the device', () => {
|
||||||
|
const packageId = 'unittestapp';
|
||||||
|
const activityName = 'TestActivity';
|
||||||
|
AndroidManifestFns.getPackageId.and.returnValue(packageId);
|
||||||
|
AndroidManifestGetActivitySpy.getName.and.returnValue(activityName);
|
||||||
|
|
||||||
|
return device.install(target).then(() => {
|
||||||
|
expect(AdbSpy.start).toHaveBeenCalledWith(target.target, `${packageId}/.${activityName}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user