Update to new android cordova build

Signed-off-by: Chris Cromer <chris@cromer.cl>
This commit is contained in:
2019-04-09 20:33:36 -04:00
parent 408bf02b89
commit 179caec389
414 changed files with 2292 additions and 69850 deletions

View File

@@ -1,2 +1,4 @@
env:
jasmine: true
jasmine: true
rules:
prefer-promise-reject-errors: off

View File

@@ -1,13 +1,13 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
applicationId "com.example.anis.myapplication"
minSdkVersion 21
targetSdkVersion 23
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
@@ -20,7 +20,7 @@ android {
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
implementation 'com.android.support:appcompat-v7:23.4.0'
}

View File

@@ -84,6 +84,8 @@
<source-file src="src/android/jniLibs/x86/libnative.so" target-dir="libs/x86" />
<source-file src="src/android/DummyPlugin2.java"
target-dir="src/com/appco" />
<source-file src="src/android/DummyPlugin2.java"
target-dir="appco/src" />
<lib-file src="src/android/TestLib.jar" />
</platform>
</plugin>

View File

@@ -1,11 +0,0 @@
var path = require('path');
var AndroidStudio = require('../../bin/templates/cordova/lib/AndroidStudio');
describe('AndroidStudio module', function () {
it('should return true for Android Studio project', function () {
var root = path.join(__dirname, '../fixtures/android_studio_project/');
var isAndStud = AndroidStudio.isAndroidStudioProject(root);
expect(isAndStud).toBe(true);
});
});

View File

@@ -32,10 +32,11 @@ var FIXTURES = path.join(__dirname, '../e2e/fixtures');
var FAKE_PROJECT_DIR = path.join(os.tmpdir(), 'plugin-test-project');
describe('addPlugin method', function () {
var api, fail, gradleBuilder, oldClean;
var Api = rewire('../../bin/templates/cordova/Api');
var api, Api, fail, gradleBuilder;
beforeEach(function () {
Api = rewire('../../bin/templates/cordova/Api');
var pluginManager = jasmine.createSpyObj('pluginManager', ['addPlugin']);
pluginManager.addPlugin.and.returnValue(Q());
spyOn(common.PluginManager, 'get').and.returnValue(pluginManager);
@@ -43,8 +44,11 @@ describe('addPlugin method', function () {
var projectSpy = jasmine.createSpyObj('AndroidProject', ['getPackageName', 'write', 'isClean']);
spyOn(AndroidProject, 'getProjectFile').and.returnValue(projectSpy);
oldClean = Api.__get__('Api.prototype.clean');
Api.__set__('Api.prototype.clean', Q);
// Prevent logging to avoid polluting the test reports
Api.__set__('selfEvents.emit', jasmine.createSpy());
api = new Api('android', FAKE_PROJECT_DIR);
fail = jasmine.createSpy('fail');
@@ -52,10 +56,6 @@ describe('addPlugin method', function () {
spyOn(builders, 'getBuilder').and.returnValue(gradleBuilder);
});
afterEach(function () {
Api.__set__('Api.prototype.clean', oldClean);
});
it('Test#001 : should call gradleBuilder.prepBuildFiles for every plugin with frameworks', function (done) {
api.addPlugin(new PluginInfo(path.join(FIXTURES, 'cordova-plugin-fake'))).catch(fail).fin(function () {
expect(fail).not.toHaveBeenCalled();

View File

@@ -17,25 +17,60 @@
under the License.
*/
var android_sdk = require('../../bin/templates/cordova/lib/android_sdk');
var superspawn = require('cordova-common').superspawn;
var fs = require('fs');
var path = require('path');
var Q = require('q');
const superspawn = require('cordova-common').superspawn;
const fs = require('fs');
const path = require('path');
const rewire = require('rewire');
describe('android_sdk', function () {
describe('list_targets_with_android', function () {
it('should invoke `android` with the `list target` command and _not_ the `list targets` command, as the plural form is not supported in some Android SDK Tools versions', function () {
var deferred = Q.defer();
spyOn(superspawn, 'spawn').and.returnValue(deferred.promise);
describe('android_sdk', () => {
let android_sdk;
beforeEach(() => {
android_sdk = rewire('../../bin/templates/cordova/lib/android_sdk');
});
describe('sort_by_largest_numerical_suffix', () => {
it('should return the newest version first', () => {
const ids = ['android-24', 'android-19', 'android-27', 'android-23'];
const sortedIds = ['android-27', 'android-24', 'android-23', 'android-19'];
expect(ids.sort(android_sdk.__get__('sort_by_largest_numerical_suffix'))).toEqual(sortedIds);
});
it('should return 0 (no sort) if one of the versions has no number', () => {
const ids = ['android-27', 'android-P'];
expect(android_sdk.__get__('sort_by_largest_numerical_suffix')(ids[0], ids[1])).toBe(0);
});
});
describe('print_newest_available_sdk_target', () => {
it('should log the newest version', () => {
const sortedIds = ['android-27', 'android-24', 'android-23', 'android-19'];
const logSpy = jasmine.createSpy('log');
spyOn(android_sdk, 'list_targets').and.returnValue(Promise.resolve(sortedIds));
spyOn(sortedIds, 'sort');
android_sdk.__set__({ console: { log: logSpy } });
return android_sdk.print_newest_available_sdk_target().then(() => {
expect(sortedIds.sort).toHaveBeenCalledWith(android_sdk.__get__('sort_by_largest_numerical_suffix'));
expect(logSpy).toHaveBeenCalledWith(sortedIds[0]);
});
});
});
describe('list_targets_with_android', () => {
it('should invoke `android` with the `list target` command and _not_ the `list targets` command, as the plural form is not supported in some Android SDK Tools versions', () => {
spyOn(superspawn, 'spawn').and.returnValue(new Promise(() => {}, () => {}));
android_sdk.list_targets_with_android();
expect(superspawn.spawn).toHaveBeenCalledWith('android', ['list', 'target']);
});
it('should parse and return results from `android list targets` command', function (done) {
var deferred = Q.defer();
spyOn(superspawn, 'spawn').and.returnValue(deferred.promise);
deferred.resolve(fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.2-android_list_targets.txt'), 'utf-8'));
return android_sdk.list_targets_with_android().then(function (list) {
it('should parse and return results from `android list targets` command', () => {
const testTargets = fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.2-android_list_targets.txt'), 'utf-8');
spyOn(superspawn, 'spawn').and.returnValue(Promise.resolve(testTargets));
return android_sdk.list_targets_with_android().then(list => {
[ 'Google Inc.:Google APIs:23',
'Google Inc.:Google APIs:22',
'Google Inc.:Google APIs:21',
@@ -46,79 +81,74 @@ describe('android_sdk', function () {
'android-MNC',
'android-22',
'android-21',
'android-20' ].forEach(function (target) { expect(list).toContain(target); });
}).fail(function (err) {
console.log(err);
expect(err).toBeUndefined();
}).fin(function () {
done();
'android-20' ].forEach((target) => expect(list).toContain(target));
});
});
});
describe('list_targets_with_avdmanager', function () {
it('should parse and return results from `avdmanager list target` command', function (done) {
var deferred = Q.defer();
spyOn(superspawn, 'spawn').and.returnValue(deferred.promise);
deferred.resolve(fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.3-avdmanager_list_target.txt'), 'utf-8'));
return android_sdk.list_targets_with_avdmanager().then(function (list) {
describe('list_targets_with_avdmanager', () => {
it('should parse and return results from `avdmanager list target` command', () => {
const testTargets = fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.3-avdmanager_list_target.txt'), 'utf-8');
spyOn(superspawn, 'spawn').and.returnValue(Promise.resolve(testTargets));
return android_sdk.list_targets_with_avdmanager().then(list => {
expect(list).toContain('android-25');
}).fail(function (err) {
console.log(err);
expect(err).toBeUndefined();
}).fin(function () {
done();
});
});
});
describe('list_targets', function () {
it('should parse Android SDK installed target information with `avdmanager` command first', function () {
var deferred = Q.defer();
var avdmanager_spy = spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(deferred.promise);
describe('list_targets', () => {
it('should parse Android SDK installed target information with `avdmanager` command first', () => {
const avdmanager_spy = spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(new Promise(() => {}, () => {}));
android_sdk.list_targets();
expect(avdmanager_spy).toHaveBeenCalled();
});
it('should parse Android SDK installed target information with `android` command if list_targets_with_avdmanager fails with ENOENT', function (done) {
var deferred = Q.defer();
spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(deferred.promise);
deferred.reject({
code: 'ENOENT'
});
var twoferred = Q.defer();
twoferred.resolve(['target1']);
var avdmanager_spy = spyOn(android_sdk, 'list_targets_with_android').and.returnValue(twoferred.promise);
return android_sdk.list_targets().then(function (targets) {
it('should parse Android SDK installed target information with `android` command if list_targets_with_avdmanager fails with ENOENT', () => {
spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(Promise.reject({ code: 'ENOENT' }));
const avdmanager_spy = spyOn(android_sdk, 'list_targets_with_android').and.returnValue(Promise.resolve(['target1']));
return android_sdk.list_targets().then(targets => {
expect(avdmanager_spy).toHaveBeenCalled();
expect(targets[0]).toEqual('target1');
done();
});
});
it('should parse Android SDK installed target information with `android` command if list_targets_with_avdmanager fails with not-recognized error (Windows)', function (done) {
var deferred = Q.defer();
spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(deferred.promise);
deferred.reject({
it('should parse Android SDK installed target information with `android` command if list_targets_with_avdmanager fails with not-recognized error (Windows)', () => {
spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(Promise.reject({
code: 1,
stderr: "'avdmanager' is not recognized as an internal or external commmand,\r\noperable program or batch file.\r\n"
});
var twoferred = Q.defer();
twoferred.resolve(['target1']);
var avdmanager_spy = spyOn(android_sdk, 'list_targets_with_android').and.returnValue(twoferred.promise);
return android_sdk.list_targets().then(function (targets) {
}));
const avdmanager_spy = spyOn(android_sdk, 'list_targets_with_android').and.returnValue(Promise.resolve(['target1']));
return android_sdk.list_targets().then(targets => {
expect(avdmanager_spy).toHaveBeenCalled();
expect(targets[0]).toEqual('target1');
done();
});
});
it('should throw an error if no Android targets were found.', function (done) {
var deferred = Q.defer();
spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(deferred.promise);
deferred.resolve([]);
return android_sdk.list_targets().then(function (targets) {
done.fail();
}).catch(function (err) {
expect(err).toBeDefined();
expect(err.message).toContain('No android targets (SDKs) installed!');
done();
});
it('should throw an error if `avdmanager` command fails with an unknown error', () => {
const errorMsg = 'Some random error';
spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(Promise.reject(errorMsg));
return android_sdk.list_targets().then(
() => fail('Unexpectedly resolved'),
err => {
expect(err).toBe(errorMsg);
}
);
});
it('should throw an error if no Android targets were found.', () => {
spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(Promise.resolve([]));
return android_sdk.list_targets().then(
() => fail('Unexpectedly resolved'),
err => {
expect(err).toBeDefined();
expect(err.message).toContain('No android targets (SDKs) installed!');
}
);
});
});
});

View File

@@ -1,28 +0,0 @@
var Gradle_builder = require('../../../bin/templates/cordova/lib/builders/GradleBuilder.js');
var fs = require('fs');
var Q = require('q');
var superspawn = require('cordova-common').superspawn;
var builder;
describe('Gradle Builder', function () {
beforeEach(function () {
spyOn(fs, 'existsSync').and.returnValue(true);
builder = new Gradle_builder('/root');
var deferred = Q.defer();
spyOn(superspawn, 'spawn').and.returnValue(deferred.promise);
});
describe('runGradleWrapper method', function () {
it('should run the provided gradle command if a gradle wrapper does not already exist', function () {
fs.existsSync.and.returnValue(false);
builder.runGradleWrapper('/my/sweet/gradle');
expect(superspawn.spawn).toHaveBeenCalledWith('/my/sweet/gradle', jasmine.any(Array), jasmine.any(Object));
});
it('should do nothing if a gradle wrapper exists in the project directory', function () {
fs.existsSync.and.returnValue(true);
builder.runGradleWrapper('/my/sweet/gradle');
expect(superspawn.spawn).not.toHaveBeenCalledWith('/my/sweet/gradle', jasmine.any(Array), jasmine.any(Object));
});
});
});

View File

@@ -195,7 +195,7 @@ describe('create', function () {
});
it('should use the activityName provided via options parameter, if exists', function (done) {
config_mock.android_activityName.and.returnValue(undefined);
create.create(project_path, config_mock, {activityName: 'AwesomeActivity'}, events_mock).then(function () {
create.create(project_path, config_mock, { activityName: 'AwesomeActivity' }, events_mock).then(function () {
expect(Manifest_mock.prototype.setName).toHaveBeenCalledWith('AwesomeActivity');
}).fail(fail).done(done);
});
@@ -217,7 +217,7 @@ describe('create', function () {
});
describe('happy path', function () {
it('should copy project templates from a specified custom template', function (done) {
create.create(project_path, config_mock, {customTemplate: '/template/path'}, events_mock).then(function () {
create.create(project_path, config_mock, { customTemplate: '/template/path' }, events_mock).then(function () {
expect(shell.cp).toHaveBeenCalledWith('-r', path.join('/template/path', 'assets'), app_path);
expect(shell.cp).toHaveBeenCalledWith('-r', path.join('/template/path', 'res'), app_path);
expect(shell.cp).toHaveBeenCalledWith(path.join('/template/path', 'gitignore'), path.join(project_path, '.gitignore'));
@@ -274,7 +274,7 @@ describe('create', function () {
});
it('should prepare build files', function (done) {
create.create(project_path, config_mock, {}, events_mock).then(function () {
expect(create.prepBuildFiles).toHaveBeenCalledWith(project_path, 'studio');
expect(create.prepBuildFiles).toHaveBeenCalledWith(project_path);
}).fail(fail).done(done);
});
});

View File

@@ -17,45 +17,50 @@
under the License.
*/
var emu = require('../../bin/templates/cordova/lib/emulator');
var check_reqs = require('../../bin/templates/cordova/lib/check_reqs');
var superspawn = require('cordova-common').superspawn;
var Q = require('q');
var fs = require('fs');
var path = require('path');
var shelljs = require('shelljs');
const fs = require('fs');
const path = require('path');
const rewire = require('rewire');
const shelljs = require('shelljs');
describe('emulator', function () {
describe('list_images_using_avdmanager', function () {
it('should properly parse details of SDK Tools 25.3.1 `avdmanager` output', function (done) {
var deferred = Q.defer();
spyOn(superspawn, 'spawn').and.returnValue(deferred.promise);
deferred.resolve(fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.3-avdmanager_list_avd.txt'), 'utf-8'));
return emu.list_images_using_avdmanager().then(function (list) {
const CordovaError = require('cordova-common').CordovaError;
const check_reqs = require('../../bin/templates/cordova/lib/check_reqs');
const superspawn = require('cordova-common').superspawn;
describe('emulator', () => {
const EMULATOR_LIST = ['emulator-5555', 'emulator-5556', 'emulator-5557'];
let emu;
beforeEach(() => {
emu = rewire('../../bin/templates/cordova/lib/emulator');
});
describe('list_images_using_avdmanager', () => {
it('should properly parse details of SDK Tools 25.3.1 `avdmanager` output', () => {
const avdList = fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.3-avdmanager_list_avd.txt'), 'utf-8');
spyOn(superspawn, 'spawn').and.returnValue(Promise.resolve(avdList));
return emu.list_images_using_avdmanager().then(list => {
expect(list).toBeDefined();
expect(list[0].name).toEqual('nexus5-5.1');
expect(list[0].target).toEqual('Android 5.1 (API level 22)');
expect(list[1].device).toEqual('pixel (Google)');
expect(list[2].abi).toEqual('default/x86_64');
}).fail(function (err) {
expect(err).toBeUndefined();
}).fin(function () {
done();
});
});
});
describe('list_images_using_android', function () {
it('should invoke `android` with the `list avd` command and _not_ the `list avds` command, as the plural form is not supported in some Android SDK Tools versions', function () {
var deferred = Q.defer();
spyOn(superspawn, 'spawn').and.returnValue(deferred.promise);
describe('list_images_using_android', () => {
it('should invoke `android` with the `list avd` command and _not_ the `list avds` command, as the plural form is not supported in some Android SDK Tools versions', () => {
spyOn(superspawn, 'spawn').and.returnValue(new Promise(() => {}, () => {}));
emu.list_images_using_android();
expect(superspawn.spawn).toHaveBeenCalledWith('android', ['list', 'avd']);
});
it('should properly parse details of SDK Tools pre-25.3.1 `android list avd` output', function (done) {
var deferred = Q.defer();
spyOn(superspawn, 'spawn').and.returnValue(deferred.promise);
deferred.resolve(fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.2-android_list_avd.txt'), 'utf-8'));
return emu.list_images_using_android().then(function (list) {
it('should properly parse details of SDK Tools pre-25.3.1 `android list avd` output', () => {
const avdList = fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.2-android_list_avd.txt'), 'utf-8');
spyOn(superspawn, 'spawn').and.returnValue(Promise.resolve(avdList));
return emu.list_images_using_android().then(list => {
expect(list).toBeDefined();
expect(list[0].name).toEqual('QWR');
expect(list[0].device).toEqual('Nexus 5 (Google)');
@@ -63,68 +68,38 @@ describe('emulator', function () {
expect(list[0].target).toEqual('Android 7.1.1 (API level 25)');
expect(list[0].abi).toEqual('google_apis/x86_64');
expect(list[0].skin).toEqual('1080x1920');
}).fail(function (err) {
expect(err).toBeUndefined();
}).fin(function () {
done();
});
});
});
describe('list_images', function () {
beforeEach(function () {
spyOn(fs, 'realpathSync').and.callFake(function (cmd) {
return cmd;
});
describe('list_images', () => {
beforeEach(() => {
spyOn(fs, 'realpathSync').and.callFake(cmd => cmd);
});
it('should try to parse AVD information using `avdmanager` first', function (done) {
spyOn(shelljs, 'which').and.callFake(function (cmd) {
if (cmd === 'avdmanager') {
return true;
} else {
return false;
}
});
var deferred = Q.defer();
var avdmanager_spy = spyOn(emu, 'list_images_using_avdmanager').and.returnValue(deferred.promise);
deferred.resolve([]);
emu.list_images().then(function () {
it('should try to parse AVD information using `avdmanager` first', () => {
spyOn(shelljs, 'which').and.callFake(cmd => cmd === 'avdmanager');
const avdmanager_spy = spyOn(emu, 'list_images_using_avdmanager').and.returnValue(Promise.resolve([]));
return emu.list_images().then(() => {
expect(avdmanager_spy).toHaveBeenCalled();
}).fail(function (err) {
expect(err).toBeUndefined();
}).fin(function () {
done();
});
});
it('should delegate to `android` if `avdmanager` cant be found and `android` can', function (done) {
spyOn(shelljs, 'which').and.callFake(function (cmd) {
if (cmd === 'avdmanager') {
return false;
} else {
return true;
}
});
var deferred = Q.defer();
var android_spy = spyOn(emu, 'list_images_using_android').and.returnValue(deferred.promise);
deferred.resolve([]);
emu.list_images().then(function () {
it('should delegate to `android` if `avdmanager` cant be found and `android` can', () => {
spyOn(shelljs, 'which').and.callFake(cmd => cmd !== 'avdmanager');
const android_spy = spyOn(emu, 'list_images_using_android').and.returnValue(Promise.resolve([]));
return emu.list_images().then(() => {
expect(android_spy).toHaveBeenCalled();
}).fail(function (err) {
expect(err).toBeUndefined();
}).fin(function () {
done();
});
});
it('should correct api level information and fill in the blanks about api level if exists', function (done) {
spyOn(shelljs, 'which').and.callFake(function (cmd) {
if (cmd === 'avdmanager') {
return true;
} else {
return false;
}
});
var deferred = Q.defer();
spyOn(emu, 'list_images_using_avdmanager').and.returnValue(deferred.promise);
deferred.resolve([
it('should correct api level information and fill in the blanks about api level if exists', () => {
spyOn(shelljs, 'which').and.callFake(cmd => cmd === 'avdmanager');
spyOn(emu, 'list_images_using_avdmanager').and.returnValue(Promise.resolve([
{
name: 'Pixel_7.0',
device: 'pixel (Google)',
@@ -138,87 +113,576 @@ describe('emulator', function () {
abi: 'google_apis/x86',
target: 'Android API 26'
}
]);
emu.list_images().then(function (avds) {
]));
return emu.list_images().then(avds => {
expect(avds[1].target).toContain('Android 8');
expect(avds[1].target).toContain('API level 26');
}).fail(function (err) {
expect(err).toBeUndefined();
}).fin(function () {
done();
});
});
it('should throw an error if neither `avdmanager` nor `android` are able to be found', function (done) {
it('should throw an error if neither `avdmanager` nor `android` are able to be found', () => {
spyOn(shelljs, 'which').and.returnValue(false);
return emu.list_images().catch(function (err) {
expect(err).toBeDefined();
expect(err.message).toContain('Could not find either `android` or `avdmanager`');
done();
});
return emu.list_images().then(
() => fail('Unexpectedly resolved'),
err => {
expect(err).toBeDefined();
expect(err.message).toContain('Could not find either `android` or `avdmanager`');
}
);
});
});
describe('best_image', function () {
var avds_promise;
var target_mock;
beforeEach(function () {
avds_promise = Q.defer();
spyOn(emu, 'list_images').and.returnValue(avds_promise.promise);
describe('best_image', () => {
let target_mock;
beforeEach(() => {
spyOn(emu, 'list_images');
target_mock = spyOn(check_reqs, 'get_target').and.returnValue('android-26');
});
it('should return undefined if there are no defined AVDs', function (done) {
avds_promise.resolve([]);
emu.best_image().then(function (best_avd) {
it('should return undefined if there are no defined AVDs', () => {
emu.list_images.and.returnValue(Promise.resolve([]));
return emu.best_image().then(best_avd => {
expect(best_avd).toBeUndefined();
}).fail(function (err) {
expect(err).toBeUndefined();
}).fin(done);
});
});
it('should return the first available image if there is no available target information for existing AVDs', function (done) {
var fake_avd = { name: 'MyFakeAVD' };
var second_fake_avd = { name: 'AnotherAVD' };
avds_promise.resolve([fake_avd, second_fake_avd]);
emu.best_image().then(function (best_avd) {
it('should return the first available image if there is no available target information for existing AVDs', () => {
const fake_avd = { name: 'MyFakeAVD' };
const second_fake_avd = { name: 'AnotherAVD' };
emu.list_images.and.returnValue(Promise.resolve([fake_avd, second_fake_avd]));
return emu.best_image().then(best_avd => {
expect(best_avd).toBe(fake_avd);
}).fail(function (err) {
expect(err).toBeUndefined();
}).fin(done);
});
});
it('should return the first AVD for the API level that matches the project target', function (done) {
it('should return the first AVD for the API level that matches the project target', () => {
target_mock.and.returnValue('android-25');
var fake_avd = { name: 'MyFakeAVD', target: 'Android 7.0 (API level 24)' };
var second_fake_avd = { name: 'AnotherAVD', target: 'Android 7.1 (API level 25)' };
var third_fake_avd = { name: 'AVDThree', target: 'Android 8.0 (API level 26)' };
avds_promise.resolve([fake_avd, second_fake_avd, third_fake_avd]);
emu.best_image().then(function (best_avd) {
const fake_avd = { name: 'MyFakeAVD', target: 'Android 7.0 (API level 24)' };
const second_fake_avd = { name: 'AnotherAVD', target: 'Android 7.1 (API level 25)' };
const third_fake_avd = { name: 'AVDThree', target: 'Android 8.0 (API level 26)' };
emu.list_images.and.returnValue(Promise.resolve([fake_avd, second_fake_avd, third_fake_avd]));
return emu.best_image().then(best_avd => {
expect(best_avd).toBe(second_fake_avd);
}).fail(function (err) {
expect(err).toBeUndefined();
}).fin(done);
});
});
it('should return the AVD with API level that is closest to the project target API level, without going over', function (done) {
it('should return the AVD with API level that is closest to the project target API level, without going over', () => {
target_mock.and.returnValue('android-26');
var fake_avd = { name: 'MyFakeAVD', target: 'Android 7.0 (API level 24)' };
var second_fake_avd = { name: 'AnotherAVD', target: 'Android 7.1 (API level 25)' };
var third_fake_avd = { name: 'AVDThree', target: 'Android 99.0 (API level 134)' };
avds_promise.resolve([fake_avd, second_fake_avd, third_fake_avd]);
emu.best_image().then(function (best_avd) {
const fake_avd = { name: 'MyFakeAVD', target: 'Android 7.0 (API level 24)' };
const second_fake_avd = { name: 'AnotherAVD', target: 'Android 7.1 (API level 25)' };
const third_fake_avd = { name: 'AVDThree', target: 'Android 99.0 (API level 134)' };
emu.list_images.and.returnValue(Promise.resolve([fake_avd, second_fake_avd, third_fake_avd]));
return emu.best_image().then(best_avd => {
expect(best_avd).toBe(second_fake_avd);
}).fail(function (err) {
expect(err).toBeUndefined();
}).fin(done);
});
});
it('should not try to compare API levels when an AVD definition is missing API level info', function (done) {
avds_promise.resolve([ { name: 'Samsung_S8_API_26',
it('should not try to compare API levels when an AVD definition is missing API level info', () => {
emu.list_images.and.returnValue(Promise.resolve([{
name: 'Samsung_S8_API_26',
device: 'Samsung S8+ (User)',
path: '/Users/daviesd/.android/avd/Samsung_S8_API_26.avd',
abi: 'google_apis/x86',
target: 'Android 8.0'
}]);
emu.best_image().then(function (best_avd) {
}]));
return emu.best_image().then(best_avd => {
expect(best_avd).toBeDefined();
}).fail(function (err) {
expect(err).toBeUndefined();
}).fin(done);
});
});
});
describe('list_started', () => {
it('should call adb devices with the emulators flag', () => {
const AdbSpy = jasmine.createSpyObj('Adb', ['devices']);
AdbSpy.devices.and.returnValue(Promise.resolve());
emu.__set__('Adb', AdbSpy);
return emu.list_started().then(() => {
expect(AdbSpy.devices).toHaveBeenCalledWith({ emulators: true });
});
});
});
describe('get_available_port', () => {
let emus;
beforeEach(() => {
emus = [];
spyOn(emu, 'list_started').and.returnValue(Promise.resolve(emus));
});
it('should find the closest available port below 5584 for the emulator', () => {
const lowestUsedPort = 5565;
for (let i = 5584; i >= lowestUsedPort; i--) {
emus.push(`emulator-${i}`);
}
return emu.get_available_port().then(port => {
expect(port).toBe(lowestUsedPort - 1);
});
});
it('should throw an error if no port is available between 5554 and 5584', () => {
for (let i = 5584; i >= 5554; i--) {
emus.push(`emulator-${i}`);
}
return emu.get_available_port().then(
() => fail('Unexpectedly resolved'),
err => {
expect(err).toEqual(jasmine.any(CordovaError));
}
);
});
});
describe('start', () => {
const port = 5555;
let emulator;
let AdbSpy;
let checkReqsSpy;
let childProcessSpy;
let shellJsSpy;
beforeEach(() => {
emulator = {
name: 'Samsung_S8_API_26',
device: 'Samsung S8+ (User)',
path: '/Users/daviesd/.android/avd/Samsung_S8_API_26.avd',
abi: 'google_apis/x86',
target: 'Android 8.0'
};
AdbSpy = jasmine.createSpyObj('Adb', ['shell']);
AdbSpy.shell.and.returnValue(Promise.resolve());
emu.__set__('Adb', AdbSpy);
checkReqsSpy = jasmine.createSpyObj('create_reqs', ['getAbsoluteAndroidCmd']);
emu.__set__('check_reqs', checkReqsSpy);
childProcessSpy = jasmine.createSpyObj('child_process', ['spawn']);
childProcessSpy.spawn.and.returnValue(jasmine.createSpyObj('spawnFns', ['unref']));
emu.__set__('child_process', childProcessSpy);
spyOn(emu, 'get_available_port').and.returnValue(Promise.resolve(port));
spyOn(emu, 'wait_for_emulator').and.returnValue(Promise.resolve('randomname'));
spyOn(emu, 'wait_for_boot').and.returnValue(Promise.resolve());
// Prevent pollution of the test logs
const proc = emu.__get__('process');
spyOn(proc.stdout, 'write').and.stub();
shellJsSpy = jasmine.createSpyObj('shelljs', ['which']);
shellJsSpy.which.and.returnValue('/dev/android-sdk/tools');
emu.__set__('shelljs', shellJsSpy);
});
it('should find an emulator if an id is not specified', () => {
spyOn(emu, 'best_image').and.returnValue(Promise.resolve(emulator));
return emu.start().then(() => {
// This is the earliest part in the code where we can hook in and check
// the emulator that has been selected.
const spawnArgs = childProcessSpy.spawn.calls.argsFor(0);
expect(spawnArgs[1]).toContain(emulator.name);
});
});
it('should use the specified emulator', () => {
spyOn(emu, 'best_image');
return emu.start(emulator.name).then(() => {
expect(emu.best_image).not.toHaveBeenCalled();
const spawnArgs = childProcessSpy.spawn.calls.argsFor(0);
expect(spawnArgs[1]).toContain(emulator.name);
});
});
it('should throw an error if no emulator is specified and no default is found', () => {
spyOn(emu, 'best_image').and.returnValue(Promise.resolve());
return emu.start().then(
() => fail('Unexpectedly resolved'),
err => {
expect(err).toEqual(jasmine.any(CordovaError));
}
);
});
it('should unlock the screen after the emulator has booted', () => {
emu.wait_for_emulator.and.returnValue(Promise.resolve(emulator.name));
emu.wait_for_boot.and.returnValue(Promise.resolve(true));
return emu.start(emulator.name).then(() => {
expect(emu.wait_for_emulator).toHaveBeenCalledBefore(AdbSpy.shell);
expect(emu.wait_for_boot).toHaveBeenCalledBefore(AdbSpy.shell);
expect(AdbSpy.shell).toHaveBeenCalledWith(emulator.name, 'input keyevent 82');
});
});
it('should resolve with the emulator id after the emulator has started', () => {
emu.wait_for_emulator.and.returnValue(Promise.resolve(emulator.name));
emu.wait_for_boot.and.returnValue(Promise.resolve(true));
return emu.start(emulator.name).then(emulatorId => {
expect(emulatorId).toBe(emulator.name);
});
});
it('should resolve with null if starting the emulator times out', () => {
emu.wait_for_emulator.and.returnValue(Promise.resolve(emulator.name));
emu.wait_for_boot.and.returnValue(Promise.resolve(false));
return emu.start(emulator.name).then(emulatorId => {
expect(emulatorId).toBe(null);
});
});
});
describe('wait_for_emulator', () => {
const port = 5656;
const expectedEmulatorId = `emulator-${port}`;
let AdbSpy;
beforeEach(() => {
AdbSpy = jasmine.createSpyObj('Adb', ['shell']);
AdbSpy.shell.and.returnValue(Promise.resolve());
emu.__set__('Adb', AdbSpy);
spyOn(emu, 'wait_for_emulator').and.callThrough();
});
it('should resolve with the emulator id if the emulator has completed boot', () => {
AdbSpy.shell.and.callFake((emulatorId, shellArgs) => {
expect(emulatorId).toBe(expectedEmulatorId);
expect(shellArgs).toContain('getprop dev.bootcomplete');
return Promise.resolve('1'); // 1 means boot is complete
});
return emu.wait_for_emulator(port).then(emulatorId => {
expect(emulatorId).toBe(expectedEmulatorId);
});
});
it('should call itself again if the emulator is not ready', () => {
AdbSpy.shell.and.returnValues(
Promise.resolve('0'),
Promise.resolve('0'),
Promise.resolve('1')
);
return emu.wait_for_emulator(port).then(() => {
expect(emu.wait_for_emulator).toHaveBeenCalledTimes(3);
});
});
it('should call itself again if shell fails for a known reason', () => {
AdbSpy.shell.and.returnValues(
Promise.reject({ message: 'device not found' }),
Promise.reject({ message: 'device offline' }),
Promise.reject({ message: 'device still connecting' }),
Promise.resolve('1')
);
return emu.wait_for_emulator(port).then(() => {
expect(emu.wait_for_emulator).toHaveBeenCalledTimes(4);
});
});
it('should throw an error if shell fails for an unknown reason', () => {
const errorMessage = { message: 'Some unknown error' };
AdbSpy.shell.and.returnValue(Promise.reject(errorMessage));
return emu.wait_for_emulator(port).then(
() => fail('Unexpectedly resolved'),
err => {
expect(err).toBe(errorMessage);
}
);
});
});
describe('wait_for_boot', () => {
const port = 5656;
const emulatorId = `emulator-${port}`;
const psOutput = `
root 1 0 8504 1512 SyS_epoll_ 00000000 S /init
u0_a1 2044 1350 1423452 47256 SyS_epoll_ 00000000 S android.process.acore
u0_a51 2963 1350 1417724 37492 SyS_epoll_ 00000000 S com.google.process.gapps
`;
let AdbSpy;
beforeEach(() => {
// If we use Jasmine's fake clock, we need to re-require the target module,
// or else it will not work.
jasmine.clock().install();
emu = rewire('../../bin/templates/cordova/lib/emulator');
AdbSpy = jasmine.createSpyObj('Adb', ['shell']);
emu.__set__('Adb', AdbSpy);
spyOn(emu, 'wait_for_boot').and.callThrough();
// Stop the logs from being polluted
const proc = emu.__get__('process');
spyOn(proc.stdout, 'write').and.stub();
});
afterEach(() => {
jasmine.clock().uninstall();
});
it('should resolve with true if the system has booted', () => {
AdbSpy.shell.and.callFake((emuId, shellArgs) => {
expect(emuId).toBe(emulatorId);
expect(shellArgs).toContain('ps');
return Promise.resolve(psOutput);
});
return emu.wait_for_boot(emulatorId).then(isReady => {
expect(isReady).toBe(true);
});
});
it('should should check boot status at regular intervals until ready', () => {
const retryInterval = emu.__get__('CHECK_BOOTED_INTERVAL');
const RETRIES = 10;
let shellPromise = Promise.resolve('');
AdbSpy.shell.and.returnValue(shellPromise);
const waitPromise = emu.wait_for_boot(emulatorId);
let attempts = 0;
function tickTimer () {
shellPromise.then(() => {
if (attempts + 1 === RETRIES) {
AdbSpy.shell.and.returnValue(Promise.resolve(psOutput));
jasmine.clock().tick(retryInterval);
} else {
attempts++;
shellPromise = Promise.resolve('');
AdbSpy.shell.and.returnValue(shellPromise);
jasmine.clock().tick(retryInterval);
tickTimer();
}
});
}
tickTimer();
// After all the retries and eventual success, this is called
return waitPromise.then(isReady => {
expect(isReady).toBe(true);
expect(emu.wait_for_boot).toHaveBeenCalledTimes(RETRIES + 1);
});
});
it('should should check boot status at regular intervals until timeout', () => {
const retryInterval = emu.__get__('CHECK_BOOTED_INTERVAL');
const TIMEOUT = 9000;
const expectedRetries = Math.floor(TIMEOUT / retryInterval);
let shellPromise = Promise.resolve('');
AdbSpy.shell.and.returnValue(shellPromise);
const waitPromise = emu.wait_for_boot(emulatorId, TIMEOUT);
let attempts = 0;
function tickTimer () {
shellPromise.then(() => {
attempts++;
shellPromise = Promise.resolve('');
AdbSpy.shell.and.returnValue(shellPromise);
jasmine.clock().tick(retryInterval);
if (attempts < expectedRetries) {
tickTimer();
}
});
}
tickTimer();
// After all the retries and eventual success, this is called
return waitPromise.then(isReady => {
expect(isReady).toBe(false);
expect(emu.wait_for_boot).toHaveBeenCalledTimes(expectedRetries + 1);
});
});
});
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 });
});
});
});
describe('install', () => {
let AndroidManifestSpy;
let AndroidManifestFns;
let AndroidManifestGetActivitySpy;
let AdbSpy;
let buildSpy;
let childProcessSpy;
let target;
beforeEach(() => {
target = { target: EMULATOR_LIST[1], arch: 'arm7', isEmulator: true };
buildSpy = jasmine.createSpyObj('build', ['findBestApkForArchitecture']);
emu.__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);
emu.__set__('AndroidManifest', AndroidManifestSpy);
AdbSpy = jasmine.createSpyObj('Adb', ['shell', 'start', 'uninstall']);
AdbSpy.shell.and.returnValue(Promise.resolve());
AdbSpy.start.and.returnValue(Promise.resolve());
AdbSpy.uninstall.and.returnValue(Promise.resolve());
emu.__set__('Adb', AdbSpy);
childProcessSpy = jasmine.createSpyObj('child_process', ['exec']);
childProcessSpy.exec.and.callFake((cmd, opts, callback) => callback());
emu.__set__('child_process', childProcessSpy);
});
it('should get the full target object if only id is specified', () => {
const targetId = target.target;
spyOn(emu, 'resolveTarget').and.returnValue(Promise.resolve(target));
return emu.install(targetId, {}).then(() => {
expect(emu.resolveTarget).toHaveBeenCalledWith(targetId);
});
});
it('should install to the passed target', () => {
return emu.install(target, {}).then(() => {
const execCmd = childProcessSpy.exec.calls.argsFor(0)[0];
expect(execCmd).toContain(`-s ${target.target} install`);
});
});
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 emu.install(target, buildResults).then(() => {
expect(buildSpy.findBestApkForArchitecture).toHaveBeenCalledWith(buildResults, target.arch);
const execCmd = childProcessSpy.exec.calls.argsFor(0)[0];
expect(execCmd).toMatch(new RegExp(`install.*${apkPath}`));
});
});
it('should uninstall and reinstall app if failure is due to different certificates', () => {
let execAlreadyCalled;
childProcessSpy.exec.and.callFake((cmd, opts, callback) => {
if (!execAlreadyCalled) {
execAlreadyCalled = true;
callback(null, 'Failure: INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES');
} else {
callback();
}
});
return emu.install(target, {}).then(() => {
expect(childProcessSpy.exec).toHaveBeenCalledTimes(2);
expect(AdbSpy.uninstall).toHaveBeenCalled();
});
});
it('should throw any error not caused by different certificates', () => {
const errorMsg = 'Failure: Failed to install';
childProcessSpy.exec.and.callFake((cmd, opts, callback) => {
callback(null, errorMsg);
});
return emu.install(target, {}).then(
() => fail('Unexpectedly resolved'),
err => {
expect(err).toEqual(jasmine.any(CordovaError));
expect(err.message).toContain(errorMsg);
}
);
});
it('should unlock the screen on device', () => {
return emu.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 emu.install(target, {}).then(() => {
expect(AdbSpy.start).toHaveBeenCalledWith(target.target, `${packageId}/.${activityName}`);
});
});
});
});

View File

@@ -61,14 +61,14 @@ describe('android project handler', function () {
describe('of <lib-file> elements', function () {
it('Test#001 : should copy files for Android Studio projects', function () {
android['lib-file'].install(valid_libs[0], dummyPluginInfo, dummyProject, {android_studio: true});
android['lib-file'].install(valid_libs[0], dummyPluginInfo, dummyProject);
expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin, 'src/android/TestLib.jar', temp, path.join('app', 'libs', 'TestLib.jar'), false);
});
});
describe('of <resource-file> elements', function () {
it('Test#002 : should copy files to the correct location on an Android Studio project', function () {
android['resource-file'].install(valid_resources[0], dummyPluginInfo, dummyProject, {android_studio: true});
android['resource-file'].install(valid_resources[0], dummyPluginInfo, dummyProject);
expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin, 'android-resource.xml', temp, path.join('app', 'src', 'main', 'res', 'xml', 'dummy.xml'), false);
});
});
@@ -81,13 +81,7 @@ describe('android project handler', function () {
it('Test#003 : should copy stuff from one location to another by calling common.copyFile', function () {
android['source-file'].install(valid_source[0], dummyPluginInfo, dummyProject);
expect(copyFileSpy)
.toHaveBeenCalledWith(dummyplugin, 'src/android/DummyPlugin.java', temp, path.join('src/com/phonegap/plugins/dummyplugin/DummyPlugin.java'), false);
});
it('Test#004 : should install source files to the right location for Android Studio projects', function () {
android['source-file'].install(valid_source[0], dummyPluginInfo, dummyProject, {android_studio: true});
expect(copyFileSpy)
.toHaveBeenCalledWith(dummyplugin, 'src/android/DummyPlugin.java', temp, path.join('app/src/main/java/com/phonegap/plugins/dummyplugin/DummyPlugin.java'), false);
.toHaveBeenCalledWith(dummyplugin, 'src/android/DummyPlugin.java', temp, path.join('app', 'src', 'main', 'java', 'com', 'phonegap', 'plugins', 'dummyplugin', 'DummyPlugin.java'), false);
});
it('Test#005 : should throw if source file cannot be found', function () {
@@ -99,7 +93,7 @@ describe('android project handler', function () {
it('Test#006 : should throw if target file already exists', function () {
// write out a file
var target = path.resolve(temp, 'src/com/phonegap/plugins/dummyplugin');
let target = path.resolve(temp, 'app', 'src', 'main', 'java', 'com', 'phonegap', 'plugins', 'dummyplugin');
shell.mkdir('-p', target);
target = path.join(target, 'DummyPlugin.java');
fs.writeFileSync(target, 'some bs', 'utf-8');
@@ -111,70 +105,76 @@ describe('android project handler', function () {
// TODO: renumber these tests and other tests below
it('Test#00a6 : should allow installing sources with new app target-dir scheme', function () {
android['source-file'].install(valid_source[1], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[1], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy)
.toHaveBeenCalledWith(dummyplugin, 'src/android/DummyPlugin2.java', temp, path.join('app/src/main/src/com/phonegap/plugins/dummyplugin/DummyPlugin2.java'), false);
});
it('Test#006b : should allow installing jar lib file from sources with new app target-dir scheme', function () {
android['source-file'].install(valid_source[2], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[2], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy)
.toHaveBeenCalledWith(dummyplugin, 'src/android/TestLib.jar', temp, path.join('app/libs/TestLib.jar'), false);
});
it('Test#006c : should allow installing aar lib file from sources with new app target-dir scheme', function () {
android['source-file'].install(valid_source[3], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[3], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy)
.toHaveBeenCalledWith(dummyplugin, 'src/android/TestAar.aar', temp, path.join('app/libs/TestAar.aar'), false);
});
it('Test#006d : should allow installing xml file from sources with old target-dir scheme', function () {
android['source-file'].install(valid_source[4], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[4], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin,
'src/android/mysettings.xml', temp,
path.join('app/src/main/res/xml/mysettings.xml'), false);
});
it('Test#006e : should allow installing file with other extension from sources with old target-dir scheme', function () {
android['source-file'].install(valid_source[5], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[5], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin,
'src/android/other.extension', temp,
path.join('app/src/main/res/values/other.extension'), false);
});
it('Test#006f : should allow installing aidl file from sources with old target-dir scheme (GH-547)', function () {
android['source-file'].install(valid_source[6], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[6], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin,
'src/android/myapi.aidl', temp,
path.join('app/src/main/aidl/com/mytest/myapi.aidl'), false);
});
it('Test#006g : should allow installing aar lib file from sources with old target-dir scheme (GH-547)', function () {
android['source-file'].install(valid_source[7], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[7], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin,
'src/android/testaar2.aar', temp,
path.join('app/libs/testaar2.aar'), false);
});
it('Test#006h : should allow installing jar lib file from sources with old target-dir scheme (GH-547)', function () {
android['source-file'].install(valid_source[8], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[8], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin,
'src/android/testjar2.jar', temp,
path.join('app/libs/testjar2.jar'), false);
});
it('Test#006i : should allow installing .so lib file from sources with old target-dir scheme (GH-547)', function () {
android['source-file'].install(valid_source[9], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[9], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin,
'src/android/jniLibs/x86/libnative.so', temp,
path.join('app/src/main/jniLibs/x86/libnative.so'), false);
});
it('Test#006j : should allow installing sources with target-dir that includes "app"', function () {
android['source-file'].install(valid_source[10], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[10], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy)
.toHaveBeenCalledWith(dummyplugin, 'src/android/DummyPlugin2.java', temp, path.join('app/src/main/java/com/appco/DummyPlugin2.java'), false);
});
it('Test#006k : should allow installing sources with target-dir that includes "app" in its first directory', function () {
android['source-file'].install(valid_source[11], dummyPluginInfo, dummyProject, { android_studio: true });
expect(copyFileSpy)
.toHaveBeenCalledWith(dummyplugin, 'src/android/DummyPlugin2.java', temp, path.join('app/src/main/java/appco/src/DummyPlugin2.java'), false);
});
});
describe('of <framework> elements', function () {
@@ -202,19 +202,19 @@ describe('android project handler', function () {
});
it('Test#008 : should install framework without "parent" attribute into project root', function () {
var framework = {src: 'plugin-lib'};
var framework = { src: 'plugin-lib' };
android.framework.install(framework, dummyPluginInfo, dummyProject);
expect(dummyProject.addSystemLibrary).toHaveBeenCalledWith(dummyProject.projectDir, someString);
});
it('Test#009 : should install framework with "parent" attribute into parent framework dir', function () {
var childFramework = {src: 'plugin-lib2', parent: 'plugin-lib'};
var childFramework = { src: 'plugin-lib2', parent: 'plugin-lib' };
android.framework.install(childFramework, dummyPluginInfo, dummyProject);
expect(dummyProject.addSystemLibrary).toHaveBeenCalledWith(path.resolve(dummyProject.projectDir, childFramework.parent), someString);
});
it('Test#010 : should not copy anything if "custom" attribute is not set', function () {
var framework = {src: 'plugin-lib'};
var framework = { src: 'plugin-lib' };
var cpSpy = spyOn(shell, 'cp');
android.framework.install(framework, dummyPluginInfo, dummyProject);
expect(dummyProject.addSystemLibrary).toHaveBeenCalledWith(someString, framework.src);
@@ -222,14 +222,14 @@ describe('android project handler', function () {
});
it('Test#011 : should copy framework sources if "custom" attribute is set', function () {
var framework = {src: 'plugin-lib', custom: true};
var framework = { src: 'plugin-lib', custom: true };
android.framework.install(framework, dummyPluginInfo, dummyProject);
expect(dummyProject.addSubProject).toHaveBeenCalledWith(dummyProject.projectDir, someString);
expect(copyNewFileSpy).toHaveBeenCalledWith(dummyPluginInfo.dir, framework.src, dummyProject.projectDir, someString, false);
});
it('Test#012 : should install gradleReference using project.addGradleReference', function () {
var framework = {src: 'plugin-lib', custom: true, type: 'gradleReference'};
var framework = { src: 'plugin-lib', custom: true, type: 'gradleReference' };
android.framework.install(framework, dummyPluginInfo, dummyProject);
expect(copyNewFileSpy).toHaveBeenCalledWith(dummyPluginInfo.dir, framework.src, dummyProject.projectDir, someString, false);
expect(dummyProject.addGradleReference).toHaveBeenCalledWith(dummyProject.projectDir, someString);
@@ -237,7 +237,7 @@ describe('android project handler', function () {
});
describe('of <js-module> elements', function () {
var jsModule = {src: 'www/dummyplugin.js'};
var jsModule = { src: 'www/dummyplugin.js' };
var wwwDest, platformWwwDest;
beforeEach(function () {
@@ -247,7 +247,7 @@ describe('android project handler', function () {
});
it('Test#013 : should put module to both www and platform_www when options.usePlatformWww flag is specified', function () {
android['js-module'].install(jsModule, dummyPluginInfo, dummyProject, {usePlatformWww: true});
android['js-module'].install(jsModule, dummyPluginInfo, dummyProject, { usePlatformWww: true });
expect(fs.writeFileSync).toHaveBeenCalledWith(wwwDest, jasmine.any(String), 'utf-8');
expect(fs.writeFileSync).toHaveBeenCalledWith(platformWwwDest, jasmine.any(String), 'utf-8');
});
@@ -260,7 +260,7 @@ describe('android project handler', function () {
});
describe('of <asset> elements', function () {
var asset = {src: 'www/dummyPlugin.js', target: 'foo/dummy.js'};
var asset = { src: 'www/dummyPlugin.js', target: 'foo/dummy.js' };
var wwwDest; /* eslint no-unused-vars: "off" */
var platformWwwDest; /* eslint no-unused-vars: "off" */
@@ -270,7 +270,7 @@ describe('android project handler', function () {
});
it('Test#015 : should put asset to both www and platform_www when options.usePlatformWww flag is specified', function () {
android.asset.install(asset, dummyPluginInfo, dummyProject, {usePlatformWww: true});
android.asset.install(asset, dummyPluginInfo, dummyProject, { usePlatformWww: true });
expect(copyFileSpy).toHaveBeenCalledWith(dummyPluginInfo.dir, asset.src, dummyProject.www, asset.target);
expect(copyFileSpy).toHaveBeenCalledWith(dummyPluginInfo.dir, asset.src, dummyProject.platformWww, asset.target);
});
@@ -310,84 +310,84 @@ describe('android project handler', function () {
describe('of <lib-file> elements', function () {
it('Test#017 : should remove jar files for Android Studio projects', function () {
android['lib-file'].install(valid_libs[0], dummyPluginInfo, dummyProject, {android_studio: true});
android['lib-file'].uninstall(valid_libs[0], dummyPluginInfo, dummyProject, {android_studio: true});
android['lib-file'].install(valid_libs[0], dummyPluginInfo, dummyProject);
android['lib-file'].uninstall(valid_libs[0], dummyPluginInfo, dummyProject);
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/libs/TestLib.jar'));
});
});
describe('of <resource-file> elements', function () {
it('Test#018 : should remove files for Android Studio projects', function () {
android['resource-file'].install(valid_resources[0], dummyPluginInfo, dummyProject, {android_studio: true});
android['resource-file'].uninstall(valid_resources[0], dummyPluginInfo, dummyProject, {android_studio: true});
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/src/main/res/xml/dummy.xml'));
android['resource-file'].install(valid_resources[0], dummyPluginInfo, dummyProject);
android['resource-file'].uninstall(valid_resources[0], dummyPluginInfo, dummyProject);
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app', 'src', 'main', 'res', 'xml', 'dummy.xml'));
});
});
describe('of <source-file> elements', function () {
it('Test#019 : should remove stuff by calling common.deleteJava for Android Studio projects', function () {
android['source-file'].install(valid_source[0], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[0], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[0], dummyPluginInfo, dummyProject);
android['source-file'].uninstall(valid_source[0], dummyPluginInfo, dummyProject);
expect(deleteJavaSpy).toHaveBeenCalledWith(temp, path.join('app/src/main/java/com/phonegap/plugins/dummyplugin/DummyPlugin.java'));
});
it('Test#019a : should remove stuff by calling common.deleteJava for Android Studio projects, with specific app target-dir', function () {
android['source-file'].install(valid_source[1], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[1], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[1], dummyPluginInfo, dummyProject, { android_studio: true });
android['source-file'].uninstall(valid_source[1], dummyPluginInfo, dummyProject, { android_studio: true });
expect(deleteJavaSpy).toHaveBeenCalledWith(temp, path.join('app/src/main/src/com/phonegap/plugins/dummyplugin/DummyPlugin2.java'));
});
it('Test#019b : should remove stuff by calling common.removeFile for Android Studio projects, of jar with new app target-dir scheme', function () {
android['source-file'].install(valid_source[2], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[2], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[2], dummyPluginInfo, dummyProject, { android_studio: true });
android['source-file'].uninstall(valid_source[2], dummyPluginInfo, dummyProject, { android_studio: true });
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/libs/TestLib.jar'));
});
it('Test#019c : should remove stuff by calling common.removeFile for Android Studio projects, of aar with new app target-dir scheme', function () {
android['source-file'].install(valid_source[3], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[3], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[3], dummyPluginInfo, dummyProject, { android_studio: true });
android['source-file'].uninstall(valid_source[3], dummyPluginInfo, dummyProject, { android_studio: true });
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/libs/TestAar.aar'));
});
it('Test#019d : should remove stuff by calling common.removeFile for Android Studio projects, of xml with old target-dir scheme', function () {
android['source-file'].install(valid_source[4], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[4], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[4], dummyPluginInfo, dummyProject, { android_studio: true });
android['source-file'].uninstall(valid_source[4], dummyPluginInfo, dummyProject, { android_studio: true });
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/src/main/res/xml/mysettings.xml'));
});
it('Test#019e : should remove stuff by calling common.removeFile for Android Studio projects, of file with other extension with old target-dir scheme', function () {
android['source-file'].install(valid_source[5], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[5], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[5], dummyPluginInfo, dummyProject, { android_studio: true });
android['source-file'].uninstall(valid_source[5], dummyPluginInfo, dummyProject, { android_studio: true });
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/src/main/res/values/other.extension'));
});
it('Test#019f : should remove stuff by calling common.removeFile for Android Studio projects, of aidl with old target-dir scheme (GH-547)', function () {
android['source-file'].install(valid_source[6], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[6], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[6], dummyPluginInfo, dummyProject, { android_studio: true });
android['source-file'].uninstall(valid_source[6], dummyPluginInfo, dummyProject, { android_studio: true });
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/src/main/aidl/com/mytest/myapi.aidl'));
});
it('Test#019g : should remove stuff by calling common.removeFile for Android Studio projects, of aar with old target-dir scheme (GH-547)', function () {
android['source-file'].install(valid_source[7], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[7], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[7], dummyPluginInfo, dummyProject, { android_studio: true });
android['source-file'].uninstall(valid_source[7], dummyPluginInfo, dummyProject, { android_studio: true });
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/libs/testaar2.aar'));
});
it('Test#019h : should remove stuff by calling common.removeFile for Android Studio projects, of jar with old target-dir scheme (GH-547)', function () {
android['source-file'].install(valid_source[8], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[8], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[8], dummyPluginInfo, dummyProject, { android_studio: true });
android['source-file'].uninstall(valid_source[8], dummyPluginInfo, dummyProject, { android_studio: true });
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/libs/testjar2.jar'));
});
it('Test#019i : should remove stuff by calling common.removeFile for Android Studio projects, of .so lib file with old target-dir scheme (GH-547)', function () {
android['source-file'].install(valid_source[9], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[9], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[9], dummyPluginInfo, dummyProject, { android_studio: true });
android['source-file'].uninstall(valid_source[9], dummyPluginInfo, dummyProject, { android_studio: true });
expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/src/main/jniLibs/x86/libnative.so'));
});
it('Test#019j : should remove stuff by calling common.deleteJava for Android Studio projects, with target-dir that includes "app"', function () {
android['source-file'].install(valid_source[10], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].uninstall(valid_source[10], dummyPluginInfo, dummyProject, {android_studio: true});
android['source-file'].install(valid_source[10], dummyPluginInfo, dummyProject, { android_studio: true });
android['source-file'].uninstall(valid_source[10], dummyPluginInfo, dummyProject, { android_studio: true });
expect(deleteJavaSpy).toHaveBeenCalledWith(temp, path.join('app/src/main/java/com/appco/DummyPlugin2.java'));
});
});
@@ -409,26 +409,26 @@ describe('android project handler', function () {
});
it('Test#021 : should uninstall framework without "parent" attribute into project root', function () {
var framework = {src: 'plugin-lib'};
var framework = { src: 'plugin-lib' };
android.framework.uninstall(framework, dummyPluginInfo, dummyProject);
expect(dummyProject.removeSystemLibrary).toHaveBeenCalledWith(dummyProject.projectDir, someString);
});
it('Test#022 : should uninstall framework with "parent" attribute into parent framework dir', function () {
var childFramework = {src: 'plugin-lib2', parent: 'plugin-lib'};
var childFramework = { src: 'plugin-lib2', parent: 'plugin-lib' };
android.framework.uninstall(childFramework, dummyPluginInfo, dummyProject);
expect(dummyProject.removeSystemLibrary).toHaveBeenCalledWith(path.resolve(dummyProject.projectDir, childFramework.parent), someString);
});
it('Test#023 : should remove framework sources if "custom" attribute is set', function () {
var framework = {src: 'plugin-lib', custom: true};
var framework = { src: 'plugin-lib', custom: true };
android.framework.uninstall(framework, dummyPluginInfo, dummyProject);
expect(dummyProject.removeSubProject).toHaveBeenCalledWith(dummyProject.projectDir, someString);
expect(removeFileSpy).toHaveBeenCalledWith(dummyProject.projectDir, someString);
});
it('Test#24 : should install gradleReference using project.removeGradleReference', function () {
var framework = {src: 'plugin-lib', custom: true, type: 'gradleReference'};
var framework = { src: 'plugin-lib', custom: true, type: 'gradleReference' };
android.framework.uninstall(framework, dummyPluginInfo, dummyProject);
expect(removeFileSpy).toHaveBeenCalledWith(dummyProject.projectDir, someString);
expect(dummyProject.removeGradleReference).toHaveBeenCalledWith(dummyProject.projectDir, someString);
@@ -436,7 +436,7 @@ describe('android project handler', function () {
});
describe('of <js-module> elements', function () {
var jsModule = {src: 'www/dummyPlugin.js'};
var jsModule = { src: 'www/dummyPlugin.js' };
var wwwDest;
var platformWwwDest;
@@ -454,7 +454,7 @@ describe('android project handler', function () {
});
it('Test#025 : should put module to both www and platform_www when options.usePlatformWww flag is specified', function () {
android['js-module'].uninstall(jsModule, dummyPluginInfo, dummyProject, {usePlatformWww: true});
android['js-module'].uninstall(jsModule, dummyPluginInfo, dummyProject, { usePlatformWww: true });
expect(shell.rm).toHaveBeenCalledWith('-Rf', wwwDest);
expect(shell.rm).toHaveBeenCalledWith('-Rf', platformWwwDest);
});
@@ -467,7 +467,7 @@ describe('android project handler', function () {
});
describe('of <asset> elements', function () {
var asset = {src: 'www/dummyPlugin.js', target: 'foo/dummy.js'};
var asset = { src: 'www/dummyPlugin.js', target: 'foo/dummy.js' };
var wwwDest, platformWwwDest;
beforeEach(function () {
@@ -484,7 +484,7 @@ describe('android project handler', function () {
});
it('Test#027 : should put module to both www and platform_www when options.usePlatformWww flag is specified', function () {
android.asset.uninstall(asset, dummyPluginInfo, dummyProject, {usePlatformWww: true});
android.asset.uninstall(asset, dummyPluginInfo, dummyProject, { usePlatformWww: true });
expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), wwwDest);
expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), platformWwwDest);
});

View File

@@ -17,22 +17,195 @@
under the License.
*/
var rewire = require('rewire');
var run = rewire('../../bin/templates/cordova/lib/run');
var getInstallTarget = run.__get__('getInstallTarget');
const rewire = require('rewire');
describe('run', function () {
describe('getInstallTarget', function () {
var targetOpts = { target: 'emu' };
var deviceOpts = { device: true };
var emulatorOpts = { emulator: true };
var emptyOpts = {};
describe('run', () => {
let run;
it('Test#001 : should select correct target based on the run opts', function () {
beforeEach(() => {
run = rewire('../../bin/templates/cordova/lib/run');
});
describe('getInstallTarget', () => {
const targetOpts = { target: 'emu' };
const deviceOpts = { device: true };
const emulatorOpts = { emulator: true };
const emptyOpts = {};
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();
});
});
describe('run method', () => {
let deviceSpyObj;
let emulatorSpyObj;
let eventsSpyObj;
let getInstallTargetSpy;
beforeEach(() => {
deviceSpyObj = jasmine.createSpyObj('deviceSpy', ['install', 'list', 'resolveTarget']);
emulatorSpyObj = jasmine.createSpyObj('emulatorSpy', ['install', 'list_images', 'list_started', 'resolveTarget', 'start', 'wait_for_boot']);
eventsSpyObj = jasmine.createSpyObj('eventsSpy', ['emit']);
getInstallTargetSpy = jasmine.createSpy('getInstallTargetSpy');
run.__set__({
device: deviceSpyObj,
emulator: emulatorSpyObj,
events: eventsSpyObj,
getInstallTarget: getInstallTargetSpy
});
});
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));
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).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(deviceSpyObj.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(emulatorSpyObj.install).toHaveBeenCalledWith(emulatorTarget, { apkPaths: [], buildType: 'debug' });
});
});
});
describe('help', () => {
it('should print out usage and help', () => {
const logSpy = jasmine.createSpy();
const procStub = { exit: _ => null, cwd: _ => '', argv: ['', ''] };
run.__set__({ console: { log: logSpy }, process: procStub });
run.help();
expect(logSpy).toHaveBeenCalledWith(jasmine.stringMatching(/^Usage:/));
});
});
});