@@ -16,6 +16,7 @@ import * as Fantom from '@react-native/fantom';
1616import * as React from 'react' ;
1717import { createRef } from 'react' ;
1818import { Image } from 'react-native' ;
19+ import * as ImageInjection from 'react-native/Libraries/Image/ImageInjection' ;
1920import accessibilityPropsSuite from 'react-native/src/private/__tests__/utilities/accessibilityPropsSuite' ;
2021import { testIDPropSuite } from 'react-native/src/private/__tests__/utilities/commonPropsSuite' ;
2122import ensureInstance from 'react-native/src/private/__tests__/utilities/ensureInstance' ;
@@ -657,6 +658,275 @@ describe('<Image>', () => {
657658 } ) ;
658659 } ) ;
659660
661+ describe ( 'resolveAssetSource' , ( ) => {
662+ it ( 'resolves a plain source object to itself' , ( ) => {
663+ expect ( Image . resolveAssetSource ( { uri : 'foo-bar.jpg' } ) ) . toEqual ( {
664+ uri : 'foo-bar.jpg' ,
665+ } ) ;
666+ } ) ;
667+ } ) ;
668+
669+ describe ( 'image attached callbacks' , ( ) => {
670+ it ( 'invokes original ref callbacks correctly when using image attached callbacks' , ( ) => {
671+ let imageInstanceFromCallback = null ;
672+ let imageInstanceFromRef1 = null ;
673+ let imageInstanceFromRef2 = null ;
674+
675+ const callback = jest . fn ( ( instance : HostInstance ) => {
676+ imageInstanceFromCallback = instance ;
677+
678+ return ( ) => {
679+ imageInstanceFromCallback = null ;
680+ } ;
681+ } ) ;
682+
683+ ImageInjection . unstable_registerImageAttachedCallback ( callback ) ;
684+
685+ expect ( imageInstanceFromCallback ) . toBe ( null ) ;
686+
687+ const root = Fantom . createRoot ( ) ;
688+
689+ const ref1 = jest . fn ( ) ;
690+ const ref1Setter = ( instance : HostInstance | null ) : void => {
691+ imageInstanceFromRef1 = instance ;
692+ ref1 ( instance ) ;
693+ } ;
694+
695+ Fantom . runTask ( ( ) => {
696+ root . render ( < Image source = { LOGO_SOURCE } ref = { ref1Setter } /> ) ;
697+ } ) ;
698+
699+ expect ( imageInstanceFromCallback ) . not . toBe ( null ) ;
700+ expect ( imageInstanceFromRef1 ) . not . toBe ( null ) ;
701+ expect ( imageInstanceFromCallback ) . toBe ( imageInstanceFromRef1 ) ;
702+ expect ( callback ) . toHaveBeenCalledTimes ( 1 ) ;
703+ expect ( ref1 ) . toHaveBeenCalledTimes ( 1 ) ;
704+
705+ const ref2 = jest . fn ( ) ;
706+ const ref2Setter = ( instance : HostInstance | null ) : void => {
707+ imageInstanceFromRef2 = instance ;
708+ ref2 ( instance ) ;
709+ } ;
710+
711+ Fantom . runTask ( ( ) => {
712+ root . render ( < Image source = { LOGO_SOURCE } ref = { ref2Setter } /> ) ;
713+ } ) ;
714+
715+ expect ( imageInstanceFromCallback ) . not . toBe ( null ) ;
716+ expect ( imageInstanceFromRef1 ) . toBe ( null ) ;
717+ expect ( imageInstanceFromRef2 ) . not . toBe ( null ) ;
718+ expect ( imageInstanceFromCallback ) . toBe ( imageInstanceFromRef2 ) ;
719+ expect ( callback ) . toHaveBeenCalledTimes ( 2 ) ;
720+ expect ( ref1 ) . toHaveBeenCalledTimes ( 2 ) ;
721+ expect ( ref2 ) . toHaveBeenCalledTimes ( 1 ) ;
722+
723+ Fantom . runTask ( ( ) => {
724+ root . render ( < Image source = { LOGO_SOURCE } ref = { ref2Setter } /> ) ;
725+ } ) ;
726+
727+ expect ( callback ) . toHaveBeenCalledTimes ( 2 ) ;
728+ expect ( ref2 ) . toHaveBeenCalledTimes ( 1 ) ;
729+
730+ ImageInjection . unstable_unregisterImageAttachedCallback ( callback ) ;
731+ Fantom . runTask ( ( ) => {
732+ root . render ( < > </ > ) ;
733+ } ) ;
734+ } ) ;
735+
736+ it ( 'calls image attached callbacks (basic)' , ( ) => {
737+ let imageInstanceFromCallback = null ;
738+ let imageInstanceFromRef = null ;
739+
740+ const callback = ( instance : HostInstance ) => {
741+ imageInstanceFromCallback = instance ;
742+
743+ return ( ) => {
744+ imageInstanceFromCallback = null ;
745+ } ;
746+ } ;
747+
748+ ImageInjection . unstable_registerImageAttachedCallback ( callback ) ;
749+
750+ expect ( imageInstanceFromCallback ) . toBe ( null ) ;
751+
752+ const root = Fantom . createRoot ( ) ;
753+
754+ Fantom . runTask ( ( ) => {
755+ root . render (
756+ < Image
757+ source = { LOGO_SOURCE }
758+ ref = { instance => {
759+ imageInstanceFromRef = instance ;
760+ } }
761+ /> ,
762+ ) ;
763+ } ) ;
764+
765+ expect ( imageInstanceFromCallback ) . not . toBe ( null ) ;
766+ expect ( imageInstanceFromRef ) . not . toBe ( null ) ;
767+ expect ( imageInstanceFromCallback ) . toBe ( imageInstanceFromRef ) ;
768+
769+ Fantom . runTask ( ( ) => {
770+ root . render ( < > </ > ) ;
771+ } ) ;
772+
773+ expect ( imageInstanceFromCallback ) . toBe ( null ) ;
774+ expect ( imageInstanceFromRef ) . toBe ( null ) ;
775+
776+ ImageInjection . unstable_unregisterImageAttachedCallback ( callback ) ;
777+
778+ Fantom . runTask ( ( ) => {
779+ root . render (
780+ < Image
781+ source = { LOGO_SOURCE }
782+ ref = { instance => {
783+ imageInstanceFromRef = instance ;
784+ } }
785+ /> ,
786+ ) ;
787+ } ) ;
788+
789+ expect ( imageInstanceFromRef ) . not . toBe ( null ) ;
790+ expect ( imageInstanceFromCallback ) . toBe ( null ) ;
791+
792+ Fantom . runTask ( ( ) => {
793+ root . render ( < > </ > ) ;
794+ } ) ;
795+ } ) ;
796+
797+ it ( 'calls image attached callbacks (multiple callbacks)' , ( ) => {
798+ let imageInstanceFromCallback1 = null ;
799+ let imageInstanceFromCallback2 = null ;
800+ let imageInstanceFromRef = null ;
801+
802+ const callback1 = ( instance : HostInstance ) => {
803+ imageInstanceFromCallback1 = instance ;
804+
805+ return ( ) => {
806+ imageInstanceFromCallback1 = null ;
807+ } ;
808+ } ;
809+ const callback2 = ( instance : HostInstance ) => {
810+ imageInstanceFromCallback2 = instance ;
811+
812+ return ( ) => {
813+ imageInstanceFromCallback2 = null ;
814+ } ;
815+ } ;
816+
817+ ImageInjection . unstable_registerImageAttachedCallback ( callback1 ) ;
818+ ImageInjection . unstable_registerImageAttachedCallback ( callback2 ) ;
819+
820+ expect ( imageInstanceFromCallback1 ) . toBe ( null ) ;
821+ expect ( imageInstanceFromCallback2 ) . toBe ( null ) ;
822+
823+ const root = Fantom . createRoot ( ) ;
824+
825+ Fantom . runTask ( ( ) => {
826+ root . render (
827+ < Image
828+ source = { LOGO_SOURCE }
829+ ref = { instance => {
830+ imageInstanceFromRef = instance ;
831+ } }
832+ /> ,
833+ ) ;
834+ } ) ;
835+
836+ expect ( imageInstanceFromRef ) . not . toBe ( null ) ;
837+ expect ( imageInstanceFromCallback1 ) . not . toBe ( null ) ;
838+ expect ( imageInstanceFromCallback2 ) . not . toBe ( null ) ;
839+ expect ( imageInstanceFromCallback1 ) . toBe ( imageInstanceFromRef ) ;
840+ expect ( imageInstanceFromCallback2 ) . toBe ( imageInstanceFromRef ) ;
841+
842+ Fantom . runTask ( ( ) => {
843+ root . render ( < > </ > ) ;
844+ } ) ;
845+
846+ expect ( imageInstanceFromRef ) . toBe ( null ) ;
847+ expect ( imageInstanceFromCallback1 ) . toBe ( null ) ;
848+ expect ( imageInstanceFromCallback2 ) . toBe ( null ) ;
849+
850+ ImageInjection . unstable_unregisterImageAttachedCallback ( callback1 ) ;
851+ ImageInjection . unstable_unregisterImageAttachedCallback ( callback2 ) ;
852+ } ) ;
853+
854+ it ( 'calls image attached callbacks (multiple images)' , ( ) => {
855+ let imageInstancesFromCallback = new Set < HostInstance > ( ) ;
856+
857+ const callback = ( instance : HostInstance ) => {
858+ imageInstancesFromCallback . add ( instance ) ;
859+
860+ return ( ) => {
861+ imageInstancesFromCallback . delete ( instance ) ;
862+ } ;
863+ } ;
864+
865+ ImageInjection . unstable_registerImageAttachedCallback ( callback ) ;
866+
867+ expect ( imageInstancesFromCallback . size ) . toBe ( 0 ) ;
868+
869+ const root = Fantom . createRoot ( ) ;
870+
871+ let firstInstance ;
872+ let secondInstance ;
873+
874+ const firstImageElement = (
875+ < Image
876+ key = "first-image"
877+ source = { LOGO_SOURCE }
878+ ref = { instance => {
879+ firstInstance = instance ;
880+ } }
881+ />
882+ ) ;
883+
884+ const secondImageElement = (
885+ < Image
886+ key = "second-image"
887+ source = { LOGO_SOURCE }
888+ ref = { instance => {
889+ secondInstance = instance ;
890+ } }
891+ />
892+ ) ;
893+
894+ Fantom . runTask ( ( ) => {
895+ root . render (
896+ < >
897+ { firstImageElement }
898+ { secondImageElement }
899+ </ > ,
900+ ) ;
901+ } ) ;
902+
903+ expect ( firstInstance ) . not . toBe ( null ) ;
904+ expect ( secondInstance ) . not . toBe ( null ) ;
905+ expect ( imageInstancesFromCallback . size ) . toBe ( 2 ) ;
906+ expect ( [ ...imageInstancesFromCallback ] [ 0 ] ) . toBe ( firstInstance ) ;
907+ expect ( [ ...imageInstancesFromCallback ] [ 1 ] ) . toBe ( secondInstance ) ;
908+
909+ Fantom . runTask ( ( ) => {
910+ root . render ( < > { secondImageElement } </ > ) ;
911+ } ) ;
912+
913+ expect ( firstInstance ) . toBe ( null ) ;
914+ expect ( secondInstance ) . not . toBe ( null ) ;
915+ expect ( imageInstancesFromCallback . size ) . toBe ( 1 ) ;
916+ expect ( [ ...imageInstancesFromCallback ] [ 0 ] ) . toBe ( secondInstance ) ;
917+
918+ Fantom . runTask ( ( ) => {
919+ root . render ( < > </ > ) ;
920+ } ) ;
921+
922+ expect ( firstInstance ) . toBe ( null ) ;
923+ expect ( secondInstance ) . toBe ( null ) ;
924+ expect ( imageInstancesFromCallback . size ) . toBe ( 0 ) ;
925+
926+ ImageInjection . unstable_unregisterImageAttachedCallback ( callback ) ;
927+ } ) ;
928+ } ) ;
929+
660930 describe ( 'static methods' , ( ) => {
661931 afterEach ( ( ) => {
662932 NativeFantom . clearAllImages ( ) ;
0 commit comments