@@ -75,8 +75,8 @@ define(function (require, exports, module) {
7575 // Window management - returns platform-specific window object
7676 // For window spawning tests, we use a helper HTML file
7777 getTestHtmlPath : ( ) => isElectron
78- ? 'spec/Electron -platform-test.html'
79- : 'spec/Tauri -platform-test.html' ,
78+ ? 'spec/native -platform-electron -test.html'
79+ : 'spec/native -platform-tauri -test.html' ,
8080
8181 // Close window by label (uses platform-agnostic Phoenix.app API)
8282 closeWindow : ( windowObj ) => Phoenix . app . closeWindowByLabel ( windowObj . label )
@@ -253,44 +253,32 @@ define(function (require, exports, module) {
253253
254254 let newURL = currentURL . href ;
255255
256- if ( isElectron ) {
257- // For Electron, use the event system (mirrors Tauri)
258- // We need to handle race: event might fire before or after window reference is available
259- let electronWindow = null ;
260- let eventReceived = false ;
256+ // Use unified event API for both platforms
257+ let nativeWindow = null ;
258+ let eventReceived = false ;
261259
262- const tryResolve = ( ) => {
263- if ( electronWindow && eventReceived ) {
264- resolve ( electronWindow ) ;
265- }
266- } ;
267-
268- const unlisten = window . electronAPI . onWindowEvent ( 'PLATFORM_API_WORKING' , ( ) => {
269- unlisten ( ) ;
270- eventReceived = true ;
260+ const tryResolve = ( ) => {
261+ if ( nativeWindow && eventReceived ) {
262+ resolve ( nativeWindow ) ;
263+ }
264+ } ;
265+
266+ const unlisten = Phoenix . app . onWindowEvent ( 'PLATFORM_API_WORKING' , ( ) => {
267+ unlisten ( ) ;
268+ eventReceived = true ;
269+ tryResolve ( ) ;
270+ } ) ;
271+
272+ Phoenix . app . openURLInPhoenixWindow ( newURL )
273+ . then ( win => {
274+ expect ( win . label . startsWith ( "extn-" ) ) . toBeTrue ( ) ;
275+ expect ( win . isNativeWindow ) . toBeTrue ( ) ;
276+ nativeWindow = win ;
271277 tryResolve ( ) ;
278+ } ) . catch ( err => {
279+ unlisten ( ) ;
280+ reject ( err ) ;
272281 } ) ;
273-
274- Phoenix . app . openURLInPhoenixWindow ( newURL )
275- . then ( win => {
276- expect ( win . label . startsWith ( "extn-" ) ) . toBeTrue ( ) ;
277- expect ( win . isNativeWindow ) . toBeTrue ( ) ;
278- electronWindow = win ;
279- tryResolve ( ) ;
280- } ) . catch ( err => {
281- unlisten ( ) ;
282- reject ( err ) ;
283- } ) ;
284- } else {
285- // For Tauri, use the event system
286- Phoenix . app . openURLInPhoenixWindow ( newURL )
287- . then ( tauriWindow => {
288- expect ( tauriWindow . label . startsWith ( "extn-" ) ) . toBeTrue ( ) ;
289- tauriWindow . listen ( 'TAURI_API_WORKING' , function ( ) {
290- resolve ( tauriWindow ) ;
291- } ) ;
292- } ) . catch ( reject ) ;
293- }
294282 } ) ;
295283 }
296284
@@ -318,6 +306,90 @@ define(function (require, exports, module) {
318306 } , 120000 ) ;
319307 } ) ;
320308
309+ describe ( "Inter-window Event API Tests" , function ( ) {
310+ // Note: emitToAllWindows excludes the sender, so we test cross-window communication
311+ // using spawned windows that emit PLATFORM_API_WORKING event
312+
313+ it ( "Should receive events from spawned windows using unified API" , async function ( ) {
314+ let eventReceived = false ;
315+ let receivedPayload = null ;
316+ const unlisten = Phoenix . app . onWindowEvent ( 'PLATFORM_API_WORKING' , ( payload ) => {
317+ eventReceived = true ;
318+ receivedPayload = payload ;
319+ } ) ;
320+
321+ // Small delay for listener registration (Tauri's listen is async)
322+ await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
323+
324+ let currentURL = new URL ( location . href ) ;
325+ let pathParts = currentURL . pathname . split ( '/' ) ;
326+ pathParts [ pathParts . length - 1 ] = platform . getTestHtmlPath ( ) ;
327+ currentURL . pathname = pathParts . join ( '/' ) ;
328+
329+ const win = await Phoenix . app . openURLInPhoenixWindow ( currentURL . href ) ;
330+ expect ( win . label . startsWith ( "extn-" ) ) . toBeTrue ( ) ;
331+
332+ // Wait for the spawned window to emit the event
333+ await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
334+
335+ expect ( eventReceived ) . toBeTrue ( ) ;
336+ expect ( receivedPayload ) . toBeDefined ( ) ;
337+
338+ unlisten ( ) ;
339+ await platform . closeWindow ( win ) ;
340+ } ) ;
341+
342+ it ( "Should unlisten properly and not receive events after unlisten" , async function ( ) {
343+ let callCount = 0 ;
344+ const unlisten = Phoenix . app . onWindowEvent ( 'PLATFORM_API_WORKING' , ( ) => {
345+ callCount ++ ;
346+ } ) ;
347+
348+ // Small delay for listener registration
349+ await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
350+
351+ // Spawn first window - should receive event
352+ let currentURL = new URL ( location . href ) ;
353+ let pathParts = currentURL . pathname . split ( '/' ) ;
354+ pathParts [ pathParts . length - 1 ] = platform . getTestHtmlPath ( ) ;
355+ currentURL . pathname = pathParts . join ( '/' ) ;
356+
357+ const win1 = await Phoenix . app . openURLInPhoenixWindow ( currentURL . href ) ;
358+ await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
359+ expect ( callCount ) . toBeGreaterThanOrEqual ( 1 ) ;
360+ const countAfterFirst = callCount ;
361+
362+ // Unlisten
363+ unlisten ( ) ;
364+ await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
365+
366+ // Spawn second window - should NOT receive event
367+ const win2 = await Phoenix . app . openURLInPhoenixWindow ( currentURL . href ) ;
368+ await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
369+ expect ( callCount ) . toEqual ( countAfterFirst ) ; // Count should not increase
370+
371+ await platform . closeWindow ( win1 ) ;
372+ await platform . closeWindow ( win2 ) ;
373+ } ) ;
374+
375+ it ( "Should not throw when emitting events" , async function ( ) {
376+ // Basic sanity test that emit APIs don't throw
377+ await expectAsync (
378+ Phoenix . app . emitToAllWindows ( 'TEST_EVENT' , { test : true } )
379+ ) . toBeResolved ( ) ;
380+
381+ await expectAsync (
382+ Phoenix . app . emitToWindow ( 'nonexistent-window' , 'TEST_EVENT' , { test : true } )
383+ ) . toBeResolved ( ) ;
384+ } ) ;
385+
386+ it ( "Should return unlisten function from onWindowEvent" , function ( ) {
387+ const unlisten = Phoenix . app . onWindowEvent ( 'TEST_EVENT' , ( ) => { } ) ;
388+ expect ( typeof unlisten ) . toEqual ( 'function' ) ;
389+ unlisten ( ) ; // Should not throw
390+ } ) ;
391+ } ) ;
392+
321393 describe ( "Credentials OTP API Tests" , function ( ) {
322394 const scopeName = "testScope" ;
323395 const trustRing = window . specRunnerTestKernalModeTrust ;
0 commit comments