@@ -15,24 +15,24 @@ export interface IPlatform {
1515 * Gets the Cordova specific platform name. (e.g. "android" for the Android platform).
1616 */
1717 getCordovaName ( ) : string ;
18-
18+
1919 /**
2020 * Gets the server url used for testing.
2121 */
2222 getServerUrl ( ) : string ;
23-
23+
2424 /**
2525 * Gets the root of the platform www folder used for creating update packages.
2626 */
2727 getPlatformWwwPath ( projectDirectory : string ) : string ;
28-
28+
2929 /**
3030 * Gets an optional IEmulatorManager for platforms for which "cordova run --nobuild" rebuilds the application for this platform anyway.
3131 * IOS needs special handling here, since ios-sim touches the app every time and changes the app timestamp.
3232 * This challenges the tests since we rely on the app timestamp in our logic for finding out if the application was updated through the app store.
3333 */
3434 getEmulatorManager ( ) : IEmulatorManager ;
35-
35+
3636 /**
3737 * Gets the default deployment key.
3838 */
@@ -47,32 +47,32 @@ export interface IEmulatorManager {
4747 * Boots the target emulator.
4848 */
4949 bootEmulator ( restartEmulators : boolean ) : Q . Promise < string > ;
50-
50+
5151 /**
5252 * Launches an already installed application by app id.
5353 */
5454 launchInstalledApplication ( appId : string ) : Q . Promise < string > ;
55-
55+
5656 /**
5757 * Ends a running application given its app id.
5858 */
5959 endRunningApplication ( appId : string ) : Q . Promise < string > ;
60-
60+
6161 /**
6262 * Restarts an already installed application by app id.
6363 */
6464 restartApplication ( appId : string ) : Q . Promise < string > ;
65-
65+
6666 /**
6767 * Navigates away from the current app, waits for a delay (defaults to 1 second), then navigates to the specified app.
6868 */
6969 resumeApplication ( appId : string , delayBeforeResumingMs : number ) : Q . Promise < string > ;
70-
70+
7171 /**
7272 * Prepares the emulator for a test.
7373 */
7474 prepareEmulatorForTest ( appId : string ) : Q . Promise < string > ;
75-
75+
7676 /**
7777 * Uninstalls the app from the emulator.
7878 */
@@ -86,7 +86,7 @@ export class Android implements IPlatform {
8686 private static instance : Android ;
8787 private emulatorManager : IEmulatorManager ;
8888 private serverUrl : string ;
89-
89+
9090 constructor ( emulatorManager : IEmulatorManager ) {
9191 this . emulatorManager = emulatorManager ;
9292 }
@@ -102,7 +102,7 @@ export class Android implements IPlatform {
102102 public getCordovaName ( ) : string {
103103 return "android" ;
104104 }
105-
105+
106106 /**
107107 * Gets the server url used for testing.
108108 */
@@ -112,7 +112,7 @@ export class Android implements IPlatform {
112112 }
113113
114114 public getPlatformWwwPath ( projectDirectory : string ) : string {
115- return path . join ( projectDirectory , "platforms/android/assets/www" ) ;
115+ return path . join ( projectDirectory , "platforms/android/app/src/main/ assets/www" ) ;
116116 }
117117
118118 public getEmulatorManager ( ) : IEmulatorManager {
@@ -147,7 +147,7 @@ export class IOS implements IPlatform {
147147 public getCordovaName ( ) : string {
148148 return "ios" ;
149149 }
150-
150+
151151 /**
152152 * Gets the server url used for testing.
153153 */
@@ -177,7 +177,7 @@ function bootEmulatorInternal(platformName: string, restartEmulators: boolean, t
177177 checkEmulator : ( ) => Q . Promise < string > , startEmulator : ( targetEmulator : string ) => Q . Promise < string > , killEmulator : ( ) => Q . Promise < string > ) : Q . Promise < string > {
178178 var deferred = Q . defer < string > ( ) ;
179179 console . log ( "Setting up " + platformName + " emulator." ) ;
180-
180+
181181 function onEmulatorReady ( ) : Q . Promise < string > {
182182 console . log ( platformName + " emulator is ready!" ) ;
183183 deferred . resolve ( undefined ) ;
@@ -187,7 +187,7 @@ function bootEmulatorInternal(platformName: string, restartEmulators: boolean, t
187187 // Called to check if the emulator for the platform is initialized.
188188 function checkEmulatorReady ( ) : Q . Promise < string > {
189189 var checkDeferred = Q . defer < string > ( ) ;
190-
190+
191191 console . log ( "Checking if " + platformName + " emulator is ready yet..." ) ;
192192 // Dummy command that succeeds if emulator is ready and fails otherwise.
193193 checkEmulator ( )
@@ -197,10 +197,10 @@ function bootEmulatorInternal(platformName: string, restartEmulators: boolean, t
197197 console . log ( platformName + " emulator is not ready yet!" ) ;
198198 checkDeferred . reject ( error ) ;
199199 } ) ;
200-
200+
201201 return checkDeferred . promise ;
202202 }
203-
203+
204204 var emulatorReadyAttempts = 0 ;
205205 // Loops checks to see if the emulator is ready and eventually fails after surpassing emulatorMaxReadyAttempts.
206206 function checkEmulatorReadyLooper ( ) : Q . Promise < string > {
@@ -212,17 +212,17 @@ function bootEmulatorInternal(platformName: string, restartEmulators: boolean, t
212212 looperDeferred . resolve ( undefined ) ;
213213 }
214214 setTimeout ( ( ) => {
215- checkEmulatorReady ( )
216- . then ( ( ) => {
217- looperDeferred . resolve ( undefined ) ;
218- onEmulatorReady ( ) ;
219- } , ( ) => {
220- return checkEmulatorReadyLooper ( ) . then ( ( ) => { looperDeferred . resolve ( undefined ) ; } , ( ) => { looperDeferred . reject ( undefined ) ; } ) ;
221- } ) ;
222- } , emulatorReadyCheckDelayMs ) ;
215+ checkEmulatorReady ( )
216+ . then ( ( ) => {
217+ looperDeferred . resolve ( undefined ) ;
218+ onEmulatorReady ( ) ;
219+ } , ( ) => {
220+ return checkEmulatorReadyLooper ( ) . then ( ( ) => { looperDeferred . resolve ( undefined ) ; } , ( ) => { looperDeferred . reject ( undefined ) ; } ) ;
221+ } ) ;
222+ } , emulatorReadyCheckDelayMs ) ;
223223 return looperDeferred . promise ;
224224 }
225-
225+
226226 // Starts and loops the emulator.
227227 function startEmulatorAndLoop ( ) : Q . Promise < string > {
228228 console . log ( "Booting " + platformName + " emulator named " + targetEmulator + "." ) ;
@@ -236,7 +236,7 @@ function bootEmulatorInternal(platformName: string, restartEmulators: boolean, t
236236 } else {
237237 promise = checkEmulatorReady ( ) . then ( onEmulatorReady , startEmulatorAndLoop ) ;
238238 }
239-
239+
240240 return deferred . promise ;
241241}
242242
@@ -257,20 +257,20 @@ export class IOSEmulatorManager implements IEmulatorManager {
257257 function killIOSEmulator ( ) : Q . Promise < string > {
258258 return tu . TestUtil . getProcessOutput ( "killall Simulator" ) ;
259259 }
260-
260+
261261 return tu . TestUtil . readIOSEmulator ( )
262262 . then ( ( iOSEmulatorName : string ) => {
263263 return bootEmulatorInternal ( "iOS" , restartEmulators , iOSEmulatorName , checkIOSEmulator , startIOSEmulator , killIOSEmulator ) ;
264264 } ) ;
265265 }
266-
266+
267267 /**
268268 * Launches an already installed application by app id.
269269 */
270270 launchInstalledApplication ( appId : string ) : Q . Promise < string > {
271271 return tu . TestUtil . getProcessOutput ( "xcrun simctl launch booted " + appId , undefined ) ;
272272 }
273-
273+
274274 /**
275275 * Ends a running application given its app id.
276276 */
@@ -295,7 +295,7 @@ export class IOSEmulatorManager implements IEmulatorManager {
295295 return Q . resolve ( error ) ;
296296 } ) ;
297297 }
298-
298+
299299 /**
300300 * Restarts an already installed application by app id.
301301 */
@@ -307,13 +307,13 @@ export class IOSEmulatorManager implements IEmulatorManager {
307307 } )
308308 . then ( ( ) => this . launchInstalledApplication ( appId ) ) ;
309309 }
310-
310+
311311 /**
312312 * Navigates away from the current app, waits for a delay (defaults to 1 second), then navigates to the specified app.
313313 */
314314 resumeApplication ( appId : string , delayBeforeResumingMs : number = 1000 ) : Q . Promise < string > {
315315 // open a default iOS app (for example, camera)
316- return this . launchInstalledApplication ( "com.apple.camera " )
316+ return this . launchInstalledApplication ( "com.apple.Preferences " )
317317 . then < void > ( ( ) => {
318318 console . log ( "Waiting for " + delayBeforeResumingMs + "ms before resuming the test application." ) ;
319319 return Q . delay ( delayBeforeResumingMs ) ;
@@ -323,14 +323,14 @@ export class IOSEmulatorManager implements IEmulatorManager {
323323 return this . launchInstalledApplication ( appId ) ;
324324 } ) ;
325325 }
326-
326+
327327 /**
328328 * Prepares the emulator for a test.
329329 */
330330 prepareEmulatorForTest ( appId : string ) : Q . Promise < string > {
331331 return this . endRunningApplication ( appId ) ;
332332 }
333-
333+
334334 /**
335335 * Uninstalls the app from the emulator.
336336 */
@@ -349,30 +349,42 @@ export class AndroidEmulatorManager implements IEmulatorManager {
349349 // List all of the packages on the device.
350350 return tu . TestUtil . getProcessOutput ( "adb shell pm list packages" ) ;
351351 }
352+
352353 function startAndroidEmulator ( androidEmulatorName : string ) : Q . Promise < string > {
353- return tu . TestUtil . getProcessOutput ( "emulator @" + androidEmulatorName ) ;
354+ const androidEmulatorCommand = `emulator @${ androidEmulatorName } ` ;
355+ let osSpecificCommand = "" ;
356+ if ( process . platform === "darwin" ) {
357+ osSpecificCommand = `${ androidEmulatorCommand } &` ;
358+ } else {
359+ osSpecificCommand = `START /B ${ androidEmulatorCommand } ` ;
360+ }
361+ return tu . TestUtil . getProcessOutput ( osSpecificCommand , { timeout : 5000 } , false ) ;
354362 }
363+
355364 function killAndroidEmulator ( ) : Q . Promise < string > {
356365 return tu . TestUtil . getProcessOutput ( "adb emu kill" ) ;
357366 }
358-
359- return bootEmulatorInternal ( "Android" , restartEmulators , tu . TestUtil . readAndroidEmulator ( ) , checkAndroidEmulator , startAndroidEmulator , killAndroidEmulator ) ;
367+
368+ return tu . TestUtil . readAndroidEmulator ( )
369+ . then ( ( AndroidEmulatorName : string ) => {
370+ return bootEmulatorInternal ( "Android" , restartEmulators , AndroidEmulatorName , checkAndroidEmulator , startAndroidEmulator , killAndroidEmulator ) ;
371+ } ) ;
360372 }
361-
373+
362374 /**
363375 * Launches an already installed application by app id.
364376 */
365377 launchInstalledApplication ( appId : string ) : Q . Promise < string > {
366378 return ProjectManager . ProjectManager . execChildProcess ( "adb shell monkey -p " + appId + " -c android.intent.category.LAUNCHER 1" ) ;
367379 }
368-
380+
369381 /**
370382 * Ends a running application given its app id.
371383 */
372384 endRunningApplication ( appId : string ) : Q . Promise < string > {
373385 return ProjectManager . ProjectManager . execChildProcess ( "adb shell am force-stop " + appId ) ;
374386 }
375-
387+
376388 /**
377389 * Restarts an already installed application by app id.
378390 */
@@ -383,10 +395,10 @@ export class AndroidEmulatorManager implements IEmulatorManager {
383395 return Q . delay ( 1000 ) ;
384396 } )
385397 . then < string > ( ( ) => {
386- return this . launchInstalledApplication ( appId ) ;
387- } ) ;
398+ return this . launchInstalledApplication ( appId ) ;
399+ } ) ;
388400 }
389-
401+
390402 /**
391403 * Navigates away from the current app, waits for a delay (defaults to 1 second), then navigates to the specified app.
392404 */
@@ -402,20 +414,20 @@ export class AndroidEmulatorManager implements IEmulatorManager {
402414 return this . launchInstalledApplication ( appId ) ;
403415 } ) ;
404416 }
405-
417+
406418 /**
407419 * Prepares the emulator for a test.
408420 */
409421 prepareEmulatorForTest ( appId : string ) : Q . Promise < string > {
410422 return this . endRunningApplication ( appId )
411- . then ( ( ) => { return ProjectManager . ProjectManager . execChildProcess ( "adb shell pm clear " + appId ) ; } ) ;
423+ . then ( ( ) => { return commandWithCheckAppExistence ( "adb shell pm clear" , appId ) ; } ) ;
412424 }
413-
425+
414426 /**
415427 * Uninstalls the app from the emulator.
416428 */
417429 uninstallApplication ( appId : string ) : Q . Promise < string > {
418- return ProjectManager . ProjectManager . execChildProcess ( "adb uninstall " + appId ) ;
430+ return commandWithCheckAppExistence ( "adb uninstall" , appId ) ;
419431 }
420432}
421433
@@ -441,7 +453,7 @@ export class PlatformResolver {
441453 return undefined ;
442454 }
443455 }
444-
456+
445457 return platforms ;
446458 }
447459
@@ -454,9 +466,22 @@ export class PlatformResolver {
454466 return this . supportedPlatforms [ i ] ;
455467 }
456468 }
457-
469+
458470 // we could not find this platform in the list of platforms, so abort
459471 console . error ( "Unsupported platform: " + cordovaPlatformName ) ;
460472 return undefined ;
461473 }
462- }
474+ }
475+
476+ function commandWithCheckAppExistence ( command : string , appId : string ) {
477+ return ProjectManager . ProjectManager . execChildProcess ( "adb shell pm list packages" )
478+ . then ( ( output ) => {
479+ return output . includes ( appId ) ;
480+ } ) . then ( ( isAppExist ) => {
481+ if ( isAppExist ) {
482+ return ProjectManager . ProjectManager . execChildProcess ( `${ command } ${ appId } ` ) . then ( function ( ) { return null ; } ) ;
483+ }
484+ console . log ( `Command "${ command } " is skipped because the application has not yet been installed` ) ;
485+ return null ;
486+ } ) ;
487+ }
0 commit comments