@@ -966,4 +966,304 @@ describe('FragmentRefs', () => {
966966 expect ( fragmentHandle . getRootNode ( ) ) . toBe ( fragmentHandle ) ;
967967 } ) ;
968968 } ) ;
969+
970+ describe ( 'compareDocumentPosition' , ( ) => {
971+ function expectPosition ( position , spec ) {
972+ expect ( ( position & Node . DOCUMENT_POSITION_PRECEDING ) !== 0 ) . toBe (
973+ spec . preceding ,
974+ ) ;
975+ expect ( ( position & Node . DOCUMENT_POSITION_FOLLOWING ) !== 0 ) . toBe (
976+ spec . following ,
977+ ) ;
978+ expect ( ( position & Node . DOCUMENT_POSITION_CONTAINS ) !== 0 ) . toBe (
979+ spec . contains ,
980+ ) ;
981+ expect ( ( position & Node . DOCUMENT_POSITION_CONTAINED_BY ) !== 0 ) . toBe (
982+ spec . containedBy ,
983+ ) ;
984+ expect ( ( position & Node . DOCUMENT_POSITION_DISCONNECTED ) !== 0 ) . toBe (
985+ spec . disconnected ,
986+ ) ;
987+ expect (
988+ ( position & Node . DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC ) !== 0 ,
989+ ) . toBe ( spec . implementationSpecific ) ;
990+ }
991+ // @gate enableFragmentRefs
992+ it ( 'returns the relationship between the fragment instance and a given node' , async ( ) => {
993+ const fragmentRef = React . createRef ( ) ;
994+ const beforeRef = React . createRef ( ) ;
995+ const afterRef = React . createRef ( ) ;
996+ const middleChildRef = React . createRef ( ) ;
997+ const firstChildRef = React . createRef ( ) ;
998+ const lastChildRef = React . createRef ( ) ;
999+ const containerRef = React . createRef ( ) ;
1000+ const disconnectedElement = document . createElement ( 'div' ) ;
1001+ const root = ReactDOMClient . createRoot ( container ) ;
1002+
1003+ function Test ( ) {
1004+ return (
1005+ < div ref = { containerRef } >
1006+ < div ref = { beforeRef } />
1007+ < React . Fragment ref = { fragmentRef } >
1008+ < div ref = { firstChildRef } />
1009+ < div ref = { middleChildRef } />
1010+ < div ref = { lastChildRef } />
1011+ </ React . Fragment >
1012+ < div ref = { afterRef } />
1013+ </ div >
1014+ ) ;
1015+ }
1016+
1017+ await act ( ( ) => root . render ( < Test /> ) ) ;
1018+
1019+ // document.body is preceding and contains the fragment
1020+ expectPosition (
1021+ fragmentRef . current . compareDocumentPosition ( document . body ) ,
1022+ {
1023+ preceding : true ,
1024+ following : false ,
1025+ contains : true ,
1026+ containedBy : false ,
1027+ disconnected : false ,
1028+ implementationSpecific : false ,
1029+ } ,
1030+ ) ;
1031+
1032+ // beforeRef is preceding the fragment
1033+ expectPosition (
1034+ fragmentRef . current . compareDocumentPosition ( beforeRef . current ) ,
1035+ {
1036+ preceding : true ,
1037+ following : false ,
1038+ contains : false ,
1039+ containedBy : false ,
1040+ disconnected : false ,
1041+ implementationSpecific : false ,
1042+ } ,
1043+ ) ;
1044+
1045+ // afterRef is following the fragment
1046+ expectPosition (
1047+ fragmentRef . current . compareDocumentPosition ( afterRef . current ) ,
1048+ {
1049+ preceding : false ,
1050+ following : true ,
1051+ contains : false ,
1052+ containedBy : false ,
1053+ disconnected : false ,
1054+ implementationSpecific : false ,
1055+ } ,
1056+ ) ;
1057+
1058+ // firstChildRef is contained by the fragment
1059+ expectPosition (
1060+ fragmentRef . current . compareDocumentPosition ( firstChildRef . current ) ,
1061+ {
1062+ preceding : false ,
1063+ following : false ,
1064+ contains : false ,
1065+ containedBy : true ,
1066+ disconnected : false ,
1067+ implementationSpecific : false ,
1068+ } ,
1069+ ) ;
1070+
1071+ // middleChildRef is contained by the fragment
1072+ expectPosition (
1073+ fragmentRef . current . compareDocumentPosition ( middleChildRef . current ) ,
1074+ {
1075+ preceding : false ,
1076+ following : false ,
1077+ contains : false ,
1078+ containedBy : true ,
1079+ disconnected : false ,
1080+ implementationSpecific : false ,
1081+ } ,
1082+ ) ;
1083+
1084+ // lastChildRef is contained by the fragment
1085+ expectPosition (
1086+ fragmentRef . current . compareDocumentPosition ( lastChildRef . current ) ,
1087+ {
1088+ preceding : false ,
1089+ following : false ,
1090+ contains : false ,
1091+ containedBy : true ,
1092+ disconnected : false ,
1093+ implementationSpecific : false ,
1094+ } ,
1095+ ) ;
1096+
1097+ // containerRef preceds and contains the fragment
1098+ expectPosition (
1099+ fragmentRef . current . compareDocumentPosition ( containerRef . current ) ,
1100+ {
1101+ preceding : true ,
1102+ following : false ,
1103+ contains : true ,
1104+ containedBy : false ,
1105+ disconnected : false ,
1106+ implementationSpecific : false ,
1107+ } ,
1108+ ) ;
1109+
1110+ expectPosition (
1111+ fragmentRef . current . compareDocumentPosition ( disconnectedElement ) ,
1112+ {
1113+ preceding : false ,
1114+ following : true ,
1115+ contains : false ,
1116+ containedBy : false ,
1117+ disconnected : true ,
1118+ implementationSpecific : true ,
1119+ } ,
1120+ ) ;
1121+ } ) ;
1122+
1123+ // @gate enableFragmentRefs
1124+ it ( 'handles fragment instances with one child' , async ( ) => {
1125+ const fragmentRef = React . createRef ( ) ;
1126+ const beforeRef = React . createRef ( ) ;
1127+ const afterRef = React . createRef ( ) ;
1128+ const containerRef = React . createRef ( ) ;
1129+ const onlyChildRef = React . createRef ( ) ;
1130+ const disconnectedElement = document . createElement ( 'div' ) ;
1131+ const root = ReactDOMClient . createRoot ( container ) ;
1132+
1133+ function Test ( ) {
1134+ return (
1135+ < div ref = { containerRef } >
1136+ < div ref = { beforeRef } />
1137+ < React . Fragment ref = { fragmentRef } >
1138+ < div ref = { onlyChildRef } />
1139+ </ React . Fragment >
1140+ < div ref = { afterRef } />
1141+ </ div >
1142+ ) ;
1143+ }
1144+
1145+ await act ( ( ) => root . render ( < Test /> ) ) ;
1146+ expectPosition (
1147+ fragmentRef . current . compareDocumentPosition ( beforeRef . current ) ,
1148+ {
1149+ preceding : true ,
1150+ following : false ,
1151+ contains : false ,
1152+ containedBy : false ,
1153+ disconnected : false ,
1154+ implementationSpecific : false ,
1155+ } ,
1156+ ) ;
1157+ expectPosition (
1158+ fragmentRef . current . compareDocumentPosition ( afterRef . current ) ,
1159+ {
1160+ preceding : false ,
1161+ following : true ,
1162+ contains : false ,
1163+ containedBy : false ,
1164+ disconnected : false ,
1165+ implementationSpecific : false ,
1166+ } ,
1167+ ) ;
1168+ expectPosition (
1169+ fragmentRef . current . compareDocumentPosition ( onlyChildRef . current ) ,
1170+ {
1171+ preceding : false ,
1172+ following : false ,
1173+ contains : false ,
1174+ containedBy : true ,
1175+ disconnected : false ,
1176+ implementationSpecific : false ,
1177+ } ,
1178+ ) ;
1179+ expectPosition (
1180+ fragmentRef . current . compareDocumentPosition ( containerRef . current ) ,
1181+ {
1182+ preceding : true ,
1183+ following : false ,
1184+ contains : true ,
1185+ containedBy : false ,
1186+ disconnected : false ,
1187+ implementationSpecific : false ,
1188+ } ,
1189+ ) ;
1190+ expectPosition (
1191+ fragmentRef . current . compareDocumentPosition ( disconnectedElement ) ,
1192+ {
1193+ preceding : false ,
1194+ following : true ,
1195+ contains : false ,
1196+ containedBy : false ,
1197+ disconnected : true ,
1198+ implementationSpecific : true ,
1199+ } ,
1200+ ) ;
1201+ } ) ;
1202+
1203+ // @gate enableFragmentRefs
1204+ it ( 'returns disconnected and implementation specific for any comparison with empty fragment instances' , async ( ) => {
1205+ const fragmentRef = React . createRef ( ) ;
1206+ const beforeRef = React . createRef ( ) ;
1207+ const afterRef = React . createRef ( ) ;
1208+ const containerRef = React . createRef ( ) ;
1209+ const root = ReactDOMClient . createRoot ( container ) ;
1210+
1211+ function Test ( ) {
1212+ return (
1213+ < div ref = { containerRef } >
1214+ < div ref = { beforeRef } />
1215+ < React . Fragment ref = { fragmentRef } />
1216+ < div ref = { afterRef } />
1217+ </ div >
1218+ ) ;
1219+ }
1220+
1221+ await act ( ( ) => root . render ( < Test /> ) ) ;
1222+
1223+ expectPosition (
1224+ fragmentRef . current . compareDocumentPosition ( document . body ) ,
1225+ {
1226+ preceding : false ,
1227+ following : false ,
1228+ contains : false ,
1229+ containedBy : false ,
1230+ disconnected : true ,
1231+ implementationSpecific : true ,
1232+ } ,
1233+ ) ;
1234+ expectPosition (
1235+ fragmentRef . current . compareDocumentPosition ( beforeRef . current ) ,
1236+ {
1237+ preceding : false ,
1238+ following : false ,
1239+ contains : false ,
1240+ containedBy : false ,
1241+ disconnected : true ,
1242+ implementationSpecific : true ,
1243+ } ,
1244+ ) ;
1245+ expectPosition (
1246+ fragmentRef . current . compareDocumentPosition ( afterRef . current ) ,
1247+ {
1248+ preceding : false ,
1249+ following : false ,
1250+ contains : false ,
1251+ containedBy : false ,
1252+ disconnected : true ,
1253+ implementationSpecific : true ,
1254+ } ,
1255+ ) ;
1256+ expectPosition (
1257+ fragmentRef . current . compareDocumentPosition ( containerRef . current ) ,
1258+ {
1259+ preceding : false ,
1260+ following : false ,
1261+ contains : false ,
1262+ containedBy : false ,
1263+ disconnected : true ,
1264+ implementationSpecific : true ,
1265+ } ,
1266+ ) ;
1267+ } ) ;
1268+ } ) ;
9691269} ) ;
0 commit comments