@@ -357,6 +357,173 @@ struct NTLWebViewTests {
357
357
}
358
358
}
359
359
360
+ // MARK: - Generic Call Bridge Tests
361
+
362
+ @Test ( " Generic call bridge with string return " )
363
+ func genericCallBridgeWithStringReturn( ) async {
364
+ await MainActor . run {
365
+ let webView = NTLWebView ( )
366
+
367
+ var result : String ?
368
+ var error : Error ?
369
+
370
+ webView. callBridge ( method: " testStringMethod " , args: [ ] ) { ( response: Result < String , Error > ) in
371
+ switch response {
372
+ case . success( let value) :
373
+ result = value
374
+ case . failure( let err) :
375
+ error = err
376
+ }
377
+ }
378
+
379
+ // Simulate a successful JS return by directly calling handleReturnValueFromJS
380
+ let mockResponse : JSONValue = . dictionary( [
381
+ " id " : . number( 1 ) ,
382
+ " data " : . string( " Hello from JavaScript! " ) ,
383
+ " complete " : . bool( true )
384
+ ] )
385
+ webView. handleReturnValueFromJS ( mockResponse)
386
+
387
+ // Verify the successful type conversion
388
+ #expect( result == " Hello from JavaScript! " )
389
+ #expect( error == nil )
390
+ }
391
+ }
392
+
393
+ @Test ( " Generic call bridge with custom struct " )
394
+ func genericCallBridgeWithCustomStruct( ) async {
395
+ await MainActor . run {
396
+ let webView = NTLWebView ( )
397
+
398
+ struct TestUser : Codable , Equatable {
399
+ let name : String
400
+ let age : Int
401
+ }
402
+
403
+ var result : TestUser ?
404
+ var error : Error ?
405
+
406
+ webView. callBridge ( method: " testUserMethod " , args: [ ] ) { ( response: Result < TestUser , Error > ) in
407
+ switch response {
408
+ case . success( let value) :
409
+ result = value
410
+ case . failure( let err) :
411
+ error = err
412
+ }
413
+ }
414
+
415
+ // Simulate a successful JS return with user data
416
+ let mockResponse : JSONValue = . dictionary( [
417
+ " id " : . number( 1 ) ,
418
+ " data " : . dictionary( [
419
+ " name " : . string( " Alice Johnson " ) ,
420
+ " age " : . number( 28 )
421
+ ] ) ,
422
+ " complete " : . bool( true )
423
+ ] )
424
+ webView. handleReturnValueFromJS ( mockResponse)
425
+
426
+ // Verify the successful type conversion
427
+ let expectedUser = TestUser ( name: " Alice Johnson " , age: 28 )
428
+ #expect( result == expectedUser)
429
+ #expect( error == nil )
430
+ }
431
+ }
432
+
433
+ @Test ( " Generic call bridge with array return " )
434
+ func genericCallBridgeWithArrayReturn( ) async {
435
+ await MainActor . run {
436
+ let webView = NTLWebView ( )
437
+
438
+ struct TestItem : Codable , Equatable {
439
+ let id : Int
440
+ let title : String
441
+ }
442
+
443
+ var result : [ TestItem ] ?
444
+ var error : Error ?
445
+
446
+ webView. callBridge ( method: " testArrayMethod " , args: [ ] ) { ( response: Result < [ TestItem ] , Error > ) in
447
+ switch response {
448
+ case . success( let value) :
449
+ result = value
450
+ case . failure( let err) :
451
+ error = err
452
+ }
453
+ }
454
+
455
+ // Simulate a successful JS return with array data
456
+ let mockResponse : JSONValue = . dictionary( [
457
+ " id " : . number( 1 ) ,
458
+ " data " : . array( [
459
+ . dictionary( [ " id " : . number( 1 ) , " title " : . string( " First Item " ) ] ) ,
460
+ . dictionary( [ " id " : . number( 2 ) , " title " : . string( " Second Item " ) ] ) ,
461
+ . dictionary( [ " id " : . number( 3 ) , " title " : . string( " Third Item " ) ] )
462
+ ] ) ,
463
+ " complete " : . bool( true )
464
+ ] )
465
+ webView. handleReturnValueFromJS ( mockResponse)
466
+
467
+ // Verify the successful type conversion
468
+ let expectedItems = [
469
+ TestItem ( id: 1 , title: " First Item " ) ,
470
+ TestItem ( id: 2 , title: " Second Item " ) ,
471
+ TestItem ( id: 3 , title: " Third Item " )
472
+ ]
473
+ #expect( result == expectedItems)
474
+ #expect( error == nil )
475
+ }
476
+ }
477
+
478
+ @Test ( " Generic call bridge with type conversion failure " )
479
+ func genericCallBridgeWithTypeConversionFailure( ) async {
480
+ await MainActor . run {
481
+ let webView = NTLWebView ( )
482
+
483
+ struct StrictUser : Codable , Equatable {
484
+ let name : String
485
+ let age : Int
486
+ let email : String // Required field
487
+ }
488
+
489
+ var result : StrictUser ?
490
+ var error : Error ?
491
+
492
+ webView. callBridge ( method: " testIncompleteUserMethod " , args: [ ] ) { ( response: Result < StrictUser , Error > ) in
493
+ switch response {
494
+ case . success( let value) :
495
+ result = value
496
+ case . failure( let err) :
497
+ error = err
498
+ }
499
+ }
500
+
501
+ // Simulate JS return with incomplete data (missing required 'email' field)
502
+ let mockResponse : JSONValue = . dictionary( [
503
+ " id " : . number( 1 ) ,
504
+ " data " : . dictionary( [
505
+ " name " : . string( " Bob Smith " ) ,
506
+ " age " : . number( 35 )
507
+ // Missing 'email' field which is required
508
+ ] ) ,
509
+ " complete " : . bool( true )
510
+ ] )
511
+ webView. handleReturnValueFromJS ( mockResponse)
512
+
513
+ // Verify the type conversion failed as expected
514
+ #expect( result == nil )
515
+ #expect( error != nil )
516
+
517
+ // Verify it's a type conversion error
518
+ #expect( error is NTLBridgeError )
519
+ if case . typeConversionFailed = error as? NTLBridgeError {
520
+ // Expected error type
521
+ } else {
522
+ #expect( false ) // Unexpected error type
523
+ }
524
+ }
525
+ }
526
+
360
527
// MARK: - Navigation Tests
361
528
362
529
@Test ( " Load request triggers cleanup " )
0 commit comments