@@ -341,7 +341,65 @@ class LoadQueryFromStoreTests: XCTestCase, CacheDependentTesting, StoreLoading {
341
341
}
342
342
}
343
343
}
344
-
344
+
345
+ func testLoadingHeroAndFriendsNamesQuery_withOptionalFriendsSelection_withNullFriendListItem( ) throws {
346
+ // given
347
+ class GivenSelectionSet : MockSelectionSet {
348
+ override class var __selections : [ Selection ] { [
349
+ . field( " hero " , Hero . self)
350
+ ] }
351
+ var hero : Hero { __data [ " hero " ] }
352
+
353
+ class Hero : MockSelectionSet {
354
+ override class var __selections : [ Selection ] { [
355
+ . field( " __typename " , String . self) ,
356
+ . field( " name " , String . self) ,
357
+ . field( " friends " , [ Friend? ] ? . self)
358
+ ] }
359
+ var friends : [ Friend ? ] ? { __data [ " friends " ] }
360
+
361
+ class Friend : MockSelectionSet {
362
+ override class var __selections : [ Selection ] { [
363
+ . field( " __typename " , String . self) ,
364
+ . field( " name " , String . self)
365
+ ] }
366
+ var name : String { __data [ " name " ] }
367
+ }
368
+ }
369
+ }
370
+
371
+ mergeRecordsIntoCache ( [
372
+ " QUERY_ROOT " : [ " hero " : CacheReference ( " hero " ) ] ,
373
+ " hero " : [
374
+ " name " : " R2-D2 " ,
375
+ " __typename " : " Droid " ,
376
+ " friends " : [
377
+ CacheReference ( " hero.friends.0 " ) ,
378
+ NSNull ( ) ,
379
+ ]
380
+ ] ,
381
+ " hero.friends.0 " : [ " __typename " : " Human " , " name " : " Luke Skywalker " ] ,
382
+ ] )
383
+
384
+ // when
385
+ let query = MockQuery < GivenSelectionSet > ( )
386
+
387
+ loadFromStore ( operation: query) { result in
388
+ // then
389
+ try XCTAssertSuccessResult ( result) { graphQLResult in
390
+ XCTAssertEqual ( graphQLResult. source, . cache)
391
+ XCTAssertNil ( graphQLResult. errors)
392
+
393
+ let data = try XCTUnwrap ( graphQLResult. data)
394
+ XCTAssertEqual ( data. hero. name, " R2-D2 " )
395
+
396
+ XCTAssertEqual ( data. hero. friends? . count, 2 )
397
+ XCTAssertEqual ( data. hero. friends![ 0 ] !. name, " Luke Skywalker " )
398
+ XCTAssertNil ( data. hero. friends![ 1 ] ) // Null friend at position 2
399
+ }
400
+ }
401
+ }
402
+
345
403
func testLoadingHeroAndFriendsNamesQuery_withOptionalFriendsSelection_withFriendsNotInCache_throwsMissingValueError( ) throws {
346
404
// given
347
405
class GivenSelectionSet : MockSelectionSet {
@@ -494,4 +552,131 @@ class LoadQueryFromStoreTests: XCTestCase, CacheDependentTesting, StoreLoading {
494
552
}
495
553
}
496
554
}
555
+
556
+ @MainActor func testLoadingHeroAndFriendsNamesQuery_withOptionalFriendsSelection_withNullFriendListItem_usingRequestChain( ) throws {
557
+ // given
558
+ struct Types {
559
+ static let Hero = Object ( typename: " Hero " , implementedInterfaces: [ ] )
560
+ static let Friend = Object ( typename: " Friend " , implementedInterfaces: [ ] )
561
+ }
562
+
563
+ MockSchemaMetadata . stub_objectTypeForTypeName ( {
564
+ switch $0 {
565
+ case " Hero " :
566
+ return Types . Hero
567
+ case " Friend " :
568
+ return Types . Friend
569
+ default :
570
+ XCTFail ( )
571
+ return nil
572
+ }
573
+ } )
574
+
575
+ class Hero : MockSelectionSet {
576
+ typealias Schema = MockSchemaMetadata
577
+
578
+ override class var __parentType : any ParentType { Types . Hero }
579
+ override class var __selections : [ Selection ] { [
580
+ . field( " __typename " , String . self) ,
581
+ . field( " name " , String . self) ,
582
+ . field( " friends " , [ Friend? ] ? . self)
583
+ ] }
584
+
585
+ public var name : String ? { __data [ " name " ] }
586
+ public var friends : [ Friend ? ] ? { __data [ " friends " ] }
587
+
588
+ convenience init (
589
+ name: String ? = nil ,
590
+ friends: [ Friend ? ] ? = nil
591
+ ) {
592
+ self . init ( _dataDict: DataDict (
593
+ data: [
594
+ " __typename " : Types . Hero. typename,
595
+ " name " : name,
596
+ " friends " : friends
597
+ ] ,
598
+ fulfilledFragments: [ ObjectIdentifier ( Self . self) ]
599
+ ) )
600
+ }
601
+
602
+ class Friend : MockSelectionSet {
603
+ override class var __selections : [ Selection ] { [
604
+ . field( " __typename " , String . self) ,
605
+ . field( " name " , String . self)
606
+ ] }
607
+ var name : String { __data [ " name " ] }
608
+ }
609
+ }
610
+
611
+ // given
612
+ let client = MockURLSessionClient (
613
+ response: . mock(
614
+ url: TestURL . mockServer. url,
615
+ statusCode: 200 ,
616
+ httpVersion: nil ,
617
+ headerFields: nil
618
+ ) ,
619
+ data: """
620
+ {
621
+ " data " : {
622
+ " __typename " : " Hero " ,
623
+ " name " : " R2-D2 " ,
624
+ " friends " : [
625
+ {
626
+ " __typename " : " Friend " ,
627
+ " name " : " Luke Skywalker "
628
+ },
629
+ null,
630
+ {
631
+ " __typename " : " Friend " ,
632
+ " name " : " Obi-Wan Kenobi "
633
+ }
634
+ ]
635
+ }
636
+ }
637
+ """ . data ( using: . utf8)
638
+ )
639
+
640
+ let requestChain : ( any RequestChain ) ? = InterceptorRequestChain ( interceptors: [
641
+ NetworkFetchInterceptor ( client: client) ,
642
+ JSONResponseParsingInterceptor ( ) ,
643
+ CacheWriteInterceptor ( store: self . store) ,
644
+ ] )
645
+
646
+ let request = JSONRequest (
647
+ operation: MockQuery < Hero > ( ) ,
648
+ graphQLEndpoint: TestURL . mockServer. url,
649
+ clientName: " test-client " ,
650
+ clientVersion: " test-client-version "
651
+ )
652
+
653
+ let expectation = expectation ( description: " Response received " )
654
+
655
+ // when
656
+ requestChain? . kickoff ( request: request) { result in
657
+ defer {
658
+ expectation. fulfill ( )
659
+ }
660
+
661
+ XCTAssertSuccessResult ( result)
662
+ }
663
+
664
+ wait ( for: [ expectation] , timeout: 2 )
665
+
666
+ loadFromStore ( operation: MockQuery < Hero > ( ) ) { result in
667
+ // then
668
+ try XCTAssertSuccessResult ( result) { graphQLResult in
669
+ XCTAssertEqual ( graphQLResult. source, . cache)
670
+ XCTAssertNil ( graphQLResult. errors)
671
+
672
+ let data = try XCTUnwrap ( graphQLResult. data)
673
+ XCTAssertEqual ( data. name, " R2-D2 " )
674
+
675
+ XCTAssertEqual ( data. friends? . count, 3 )
676
+ XCTAssertEqual ( data. friends![ 0 ] !. name, " Luke Skywalker " )
677
+ XCTAssertNil ( data. friends![ 1 ] ) // Null friend at position 2
678
+ XCTAssertEqual ( data. friends![ 2 ] !. name, " Obi-Wan Kenobi " )
679
+ }
680
+ }
681
+ }
497
682
}
0 commit comments