@@ -62,13 +62,15 @@ const fakeExpo = (
6262 const calls : Array < { operation : string ; variables : Record < string , unknown > } > = [ ] ;
6363 let created = 0 ;
6464 let createdName = "" ;
65+ const previews : string [ ] = [ ] ;
6566 let previewFails = options . failPreview ?? false ;
6667 let createFails = options . failCreate ?? false ;
6768 let sessionGated = false ;
6869 const http = HttpClient . make ( ( request ) =>
6970 Effect . gen ( function * ( ) {
7071 const url = new URL ( request . url ) ;
7172 if ( url . origin === "https://preview.test" ) {
73+ previews . push ( `${ url . pathname } ${ url . search } ` ) ;
7274 expect ( request . headers . authorization ) . toBe ( "Bearer preview-token" ) ;
7375 if ( options . previewGate ) {
7476 yield * Deferred . succeed ( options . previewGate . requested , undefined ) ;
@@ -77,7 +79,17 @@ const fakeExpo = (
7779 if ( previewFails ) {
7880 return HttpClientResponse . fromWeb ( request , new Response ( "bad gateway" , { status : 502 } ) ) ;
7981 }
80- return HttpClientResponse . fromWeb ( request , Response . json ( { device : "UDID-1" } ) ) ;
82+ if ( url . pathname . endsWith ( "/api/screenshot" ) ) {
83+ return HttpClientResponse . fromWeb ( request , new Response ( Uint8Array . of ( 137 , 80 , 78 , 71 ) ) ) ;
84+ }
85+ return HttpClientResponse . fromWeb (
86+ request ,
87+ Response . json (
88+ url . pathname === "/vendor/serve-emu/api"
89+ ? { serial : "emulator-5554" }
90+ : { device : "UDID-1" } ,
91+ ) ,
92+ ) ;
8193 }
8294 const body =
8395 request . body . _tag === "Uint8Array"
@@ -195,7 +207,7 @@ const fakeExpo = (
195207 const allowCreate = ( ) => {
196208 createFails = false ;
197209 } ;
198- return { http, named, stopped, allowPreview, allowCreate } ;
210+ return { http, named, stopped, allowPreview, allowCreate, previews } ;
199211} ;
200212
201213const layer = Layer . mergeAll (
@@ -221,7 +233,10 @@ describe("EAS Simulator host", () => {
221233 const host = yield * makeHost ( expo , config ( ) , scope ) ;
222234 const ready = yield * host . ensureReady ( ( ) => Effect . void ) ;
223235 const catalog = ( yield * ready . devices . list ) . devices ;
224- expect ( catalog . map ( ( device ) => [ device . id , device . booted ] ) ) . toEqual ( [ [ "eas-ios" , false ] ] ) ;
236+ expect ( catalog . map ( ( device ) => [ device . id , device . booted ] ) ) . toEqual ( [
237+ [ "eas-ios" , false ] ,
238+ [ "eas-android" , false ] ,
239+ ] ) ;
225240
226241 expect ( yield * ready . devices . boot ( catalog [ 0 ] ! ) ) . toBe ( "session-1" ) ;
227242 expect ( expo . named ( "T3CreateEasSimulatorSession" ) [ 0 ] ?. variables . input ) . toMatchObject ( {
@@ -266,6 +281,55 @@ describe("EAS Simulator host", () => {
266281 } ) . pipe ( Effect . scoped , Effect . provide ( layer ) ) ,
267282 ) ;
268283
284+ it . effect ( "runs an Android session through serve-emu beside an iOS one" , ( ) =>
285+ Effect . gen ( function * ( ) {
286+ const expo = fakeExpo ( ) ;
287+ const scope = yield * Scope . make ( ) ;
288+ const host = yield * makeHost ( expo , config ( ) , scope ) ;
289+ expect ( yield * host . platformAvailability ( "android" ) ) . toEqual ( {
290+ platform : "android" ,
291+ available : true ,
292+ } ) ;
293+ const ready = yield * host . ensureReady ( ( ) => Effect . void ) ;
294+ const [ ios , android ] = ( yield * ready . devices . list ) . devices ;
295+ expect ( yield * ready . devices . boot ( ios ! ) ) . toBe ( "session-1" ) ;
296+ expect ( yield * ready . devices . boot ( android ! ) ) . toBe ( "session-2" ) ;
297+ expect ( expo . named ( "T3CreateEasSimulatorSession" ) [ 1 ] ?. variables . input ) . toMatchObject ( {
298+ platform : "ANDROID" ,
299+ } ) ;
300+ const running = ( yield * ready . devices . list ) . devices . find (
301+ ( device ) => device . id === "session-2" ,
302+ ) ;
303+ expect ( running ) . toMatchObject ( { platform : "android" , booted : true } ) ;
304+
305+ expect ( yield * ready . devices . agentEndpoint ! ( "session-2" ) ) . toMatchObject ( {
306+ agentDeviceId : "emulator-5554" ,
307+ } ) ;
308+ expect ( Array . from ( yield * ready . devices . screenshot ( running ! ) ) ) . toEqual ( [ 137 , 80 , 78 , 71 ] ) ;
309+ expect ( expo . previews . slice ( - 2 ) ) . toEqual ( [
310+ "/vendor/serve-emu/api" ,
311+ "/vendor/serve-emu/api/screenshot?device=emulator-5554" ,
312+ ] ) ;
313+ expect (
314+ yield * ready . upstream ! (
315+ "/vendor/serve-emu/webrtc/offer" ,
316+ new URLSearchParams ( "device=session-2&hostId=eas" ) ,
317+ ) ,
318+ ) . toEqual ( {
319+ url : "https://preview.test/vendor/serve-emu/webrtc/offer?device=emulator-5554&hostId=eas" ,
320+ headers : { authorization : "Bearer preview-token" } ,
321+ protocols : [ "serve-emu.token.preview-token" ] ,
322+ } ) ;
323+ // Each session answers only on its own platform's stream.
324+ expect (
325+ yield * ready . upstream ! ( "/vendor/serve-emu/api" , new URLSearchParams ( "device=session-1" ) ) ,
326+ ) . toBeNull ( ) ;
327+ expect (
328+ yield * ready . upstream ! ( "/vendor/serve-sim/api" , new URLSearchParams ( "device=session-2" ) ) ,
329+ ) . toBeNull ( ) ;
330+ } ) . pipe ( Effect . scoped , Effect . provide ( layer ) ) ,
331+ ) ;
332+
269333 it . effect ( "refuses to start past its session limit" , ( ) =>
270334 Effect . gen ( function * ( ) {
271335 const expo = fakeExpo ( ) ;
@@ -292,6 +356,7 @@ describe("EAS Simulator host", () => {
292356 expect ( yield * ready . devices . boot ( catalogDevice ! ) ) . toBe ( "session-2" ) ;
293357 expect ( ( yield * ready . devices . list ) . devices . map ( ( device ) => device . id ) ) . toEqual ( [
294358 "eas-ios" ,
359+ "eas-android" ,
295360 "session-1" ,
296361 "session-2" ,
297362 ] ) ;
@@ -306,6 +371,7 @@ describe("EAS Simulator host", () => {
306371 expect ( expo . stopped ( ) ) . toEqual ( [ "session-1" ] ) ;
307372 expect ( ( yield * ready . devices . list ) . devices . map ( ( device ) => device . id ) ) . toEqual ( [
308373 "eas-ios" ,
374+ "eas-android" ,
309375 "session-2" ,
310376 ] ) ;
311377 yield * Scope . close ( scope , Exit . void ) ;
@@ -421,7 +487,10 @@ describe("EAS Simulator host", () => {
421487 expect ( refused . message ) . toContain ( "limited to 1 running session" ) ;
422488 stopFails = false ;
423489 yield * ready . devices . list ;
424- expect ( ( yield * ready . devices . list ) . devices . map ( ( device ) => device . id ) ) . toEqual ( [ "eas-ios" ] ) ;
490+ expect ( ( yield * ready . devices . list ) . devices . map ( ( device ) => device . id ) ) . toEqual ( [
491+ "eas-ios" ,
492+ "eas-android" ,
493+ ] ) ;
425494 expect ( expo . stopped ( ) . filter ( ( id ) => id === "session-1" ) . length ) . toBeGreaterThanOrEqual ( 2 ) ;
426495 } ) . pipe ( Effect . scoped , Effect . provide ( layer ) ) ,
427496 ) ;
@@ -438,7 +507,10 @@ describe("EAS Simulator host", () => {
438507 expect ( ( yield * ready . devices . list ) . devices . map ( ( device ) => device . id ) ) . toContain ( "session-1" ) ;
439508 // Expo ended it by itself: the stop keeps failing, but the status says so.
440509 status = "STOPPED" ;
441- expect ( ( yield * ready . devices . list ) . devices . map ( ( device ) => device . id ) ) . toEqual ( [ "eas-ios" ] ) ;
510+ expect ( ( yield * ready . devices . list ) . devices . map ( ( device ) => device . id ) ) . toEqual ( [
511+ "eas-ios" ,
512+ "eas-android" ,
513+ ] ) ;
442514 status = "IN_PROGRESS" ;
443515 expect ( yield * ready . devices . boot ( catalogDevice ! ) ) . toBe ( "session-2" ) ;
444516 } ) . pipe ( Effect . scoped , Effect . provide ( layer ) ) ,
@@ -488,7 +560,10 @@ describe("EAS Simulator host", () => {
488560 expect ( expo . stopped ( ) ) . toEqual ( [ "session-1" ] ) ;
489561 const failure = yield * Fiber . join ( booting ) . pipe ( Effect . flip ) ;
490562 expect ( failure . message ) . toContain ( "was stopped while the session started" ) ;
491- expect ( ( yield * ready . devices . list ) . devices . map ( ( device ) => device . id ) ) . toEqual ( [ "eas-ios" ] ) ;
563+ expect ( ( yield * ready . devices . list ) . devices . map ( ( device ) => device . id ) ) . toEqual ( [
564+ "eas-ios" ,
565+ "eas-android" ,
566+ ] ) ;
492567 } ) . pipe ( Effect . scoped , Effect . provide ( layer ) ) ,
493568 ) ;
494569} ) ;
0 commit comments