@@ -15,6 +15,7 @@ import {
1515 pageCheck ,
1616 runLoad ,
1717 runLoadId ,
18+ runOpensExpanded ,
1819 runSpanCount ,
1920 sessionRunLoadsReducer ,
2021 type SessionRunLoadOutcome ,
@@ -1041,6 +1042,124 @@ describe("sessionRunLoadsReducer: what loads when", () => {
10411042 } ) ;
10421043} ) ;
10431044
1045+ describe ( "sessionRunLoadsReducer: new runs" , ( ) => {
1046+ type Action = SessionRunLoadsAction ;
1047+ const run = ( loads : SessionRunLoads , ...actions : Action [ ] ) =>
1048+ actions . reduce < SessionRunLoads > ( sessionRunLoadsReducer , loads ) ;
1049+ const runsChanged = ( withStatus : string [ ] , newestRunId ?: string ) : Action => ( {
1050+ type : "runsChanged" ,
1051+ withStatus,
1052+ newestRunId,
1053+ } ) ;
1054+ const expand = ( id : string , expanded = true ) : Action => ( {
1055+ type : "expanded" ,
1056+ runFriendlyId : id ,
1057+ expanded,
1058+ } ) ;
1059+ const opened = ( ) => run ( createSessionRunLoads ( [ "run_25" ] ) , runsChanged ( [ "run_25" ] , "run_25" ) ) ;
1060+
1061+ it ( "expands a new newest run and loads it" , ( ) => {
1062+ const loads = run ( opened ( ) , runsChanged ( [ "run_25" , "run_26" ] , "run_26" ) ) ;
1063+ expect ( loads . expanded . has ( "run_26" ) ) . toBe ( true ) ;
1064+ expect ( runLoad ( loads , "run_26" ) . state ) . toBe ( "loading" ) ;
1065+ } ) ;
1066+
1067+ it ( "leaves the previous run as it was, expanded or collapsed" , ( ) => {
1068+ const stillOpen = run ( opened ( ) , runsChanged ( [ "run_25" , "run_26" ] , "run_26" ) ) ;
1069+ expect ( stillOpen . expanded . has ( "run_25" ) ) . toBe ( true ) ;
1070+
1071+ const collapsed = run (
1072+ opened ( ) ,
1073+ expand ( "run_25" , false ) ,
1074+ runsChanged ( [ "run_25" , "run_26" ] , "run_26" )
1075+ ) ;
1076+ expect ( collapsed . expanded . has ( "run_25" ) ) . toBe ( false ) ;
1077+ expect ( collapsed . expanded . has ( "run_26" ) ) . toBe ( true ) ;
1078+ } ) ;
1079+
1080+ it ( "expands only the newest of several new runs" , ( ) => {
1081+ const loads = run ( opened ( ) , runsChanged ( [ "run_25" , "run_26" , "run_27" , "run_28" ] , "run_28" ) ) ;
1082+ expect ( [ ...loads . expanded ] . sort ( ) ) . toEqual ( [ "run_25" , "run_28" ] ) ;
1083+ expect ( runLoad ( loads , "run_26" ) . state ) . toBe ( "idle" ) ;
1084+ expect ( runLoad ( loads , "run_27" ) . state ) . toBe ( "idle" ) ;
1085+ } ) ;
1086+
1087+ it ( "expands nothing on the first read or when older runs are added" , ( ) => {
1088+ const first = run ( createSessionRunLoads ( ) , runsChanged ( [ "run_24" , "run_25" ] , "run_25" ) ) ;
1089+ expect ( first . expanded . size ) . toBe ( 0 ) ;
1090+
1091+ const earlier = run ( opened ( ) , runsChanged ( [ "run_5" , "run_6" , "run_25" ] , "run_25" ) ) ;
1092+ expect ( [ ...earlier . expanded ] ) . toEqual ( [ "run_25" ] ) ;
1093+ } ) ;
1094+
1095+ it ( "keeps a new run without a status expanded until it reaches the run store" , ( ) => {
1096+ let loads = run ( opened ( ) , runsChanged ( [ "run_25" ] , "run_26" ) ) ;
1097+ expect ( loads . expanded . has ( "run_26" ) ) . toBe ( true ) ;
1098+ expect ( runLoad ( loads , "run_26" ) . state ) . toBe ( "idle" ) ;
1099+ loads = run ( loads , runsChanged ( [ "run_25" , "run_26" ] , "run_26" ) ) ;
1100+ expect ( runLoad ( loads , "run_26" ) . state ) . toBe ( "loading" ) ;
1101+ } ) ;
1102+
1103+ it ( "starts a new run at the next free slot, ahead of older queued runs" , ( ) => {
1104+ const older = Array . from ( { length : 20 } , ( _ , i ) => `run_${ i + 1 } ` ) ;
1105+ let loads = run ( createSessionRunLoads ( ) , runsChanged ( older , "run_20" ) ) ;
1106+ loads = run ( loads , { type : "expandedMany" , runFriendlyIds : [ ...older ] . reverse ( ) } ) ;
1107+ expect ( loads . queue ) . toHaveLength ( 17 ) ;
1108+
1109+ // The new run reaches the run store a poll after it appears.
1110+ loads = run ( loads , runsChanged ( older , "run_21" ) , runsChanged ( [ ...older , "run_21" ] , "run_21" ) ) ;
1111+ expect ( runLoad ( loads , "run_21" ) . state ) . toBe ( "queued" ) ;
1112+
1113+ const loading = runLoad ( loads , "run_20" ) ;
1114+ if ( loading . state !== "loading" ) throw new Error ( "run_20 isn't loading" ) ;
1115+ loads = run ( loads , {
1116+ type : "settle" ,
1117+ runFriendlyId : "run_20" ,
1118+ loadId : loading . loadId ,
1119+ outcome : { state : "progressive" } ,
1120+ } ) ;
1121+ expect ( runLoad ( loads , "run_21" ) . state ) . toBe ( "loading" ) ;
1122+ } ) ;
1123+
1124+ it ( "doesn't reopen a run the user collapsed if it becomes the newest again" , ( ) => {
1125+ const loads = run (
1126+ opened ( ) ,
1127+ runsChanged ( [ "run_25" , "run_26" ] , "run_26" ) ,
1128+ expand ( "run_26" , false ) ,
1129+ runsChanged ( [ "run_25" , "run_26" ] , "run_25" ) ,
1130+ runsChanged ( [ "run_25" , "run_26" ] , "run_26" )
1131+ ) ;
1132+ expect ( loads . expanded . has ( "run_26" ) ) . toBe ( false ) ;
1133+ } ) ;
1134+
1135+ describe ( "runOpensExpanded" , ( ) => {
1136+ it ( "gives the tree the same answer before and after runsChanged is handled" , ( ) => {
1137+ const before = opened ( ) ;
1138+ const after = run ( before , runsChanged ( [ "run_25" , "run_26" ] , "run_26" ) ) ;
1139+ for ( const loads of [ before , after ] ) {
1140+ expect ( runOpensExpanded ( loads , "run_26" , "run_26" ) ) . toBe ( true ) ;
1141+ expect ( runOpensExpanded ( loads , "run_25" , "run_26" ) ) . toBe ( true ) ;
1142+ }
1143+ } ) ;
1144+
1145+ it ( "opens the starting and deep-linked runs, and nothing else" , ( ) => {
1146+ const loads = run ( createSessionRunLoads ( [ "run_25" ] ) , {
1147+ type : "deepLinked" ,
1148+ runFriendlyId : "run_3" ,
1149+ } ) ;
1150+ expect ( runOpensExpanded ( loads , "run_25" , undefined ) ) . toBe ( true ) ;
1151+ expect ( runOpensExpanded ( loads , "run_3" , undefined ) ) . toBe ( true ) ;
1152+ expect ( runOpensExpanded ( loads , "run_4" , undefined ) ) . toBe ( false ) ;
1153+ // The first read of the newest run isn't a new run.
1154+ expect ( runOpensExpanded ( loads , "run_24" , "run_25" ) ) . toBe ( false ) ;
1155+ } ) ;
1156+
1157+ it ( "doesn't open older runs added by Load earlier" , ( ) => {
1158+ expect ( runOpensExpanded ( opened ( ) , "run_5" , "run_25" ) ) . toBe ( false ) ;
1159+ } ) ;
1160+ } ) ;
1161+ } ) ;
1162+
10441163describe ( "sessionRunLoadsReducer: deep links" , ( ) => {
10451164 const deepLinked = ( id : string ) : SessionRunLoadsAction => ( {
10461165 type : "deepLinked" ,
@@ -1052,22 +1171,23 @@ describe("sessionRunLoadsReducer: deep links", () => {
10521171 newestRunId,
10531172 } ) ;
10541173
1055- it ( "expands the linked run and loads it ahead of the live run" , ( ) => {
1174+ it ( "expands the linked run and loads it with the live run" , ( ) => {
10561175 let loads = sessionRunLoadsReducer ( createSessionRunLoads ( [ "run_50" ] ) , deepLinked ( "run_3" ) ) ;
10571176 expect ( [ ...loads . expanded ] ) . toEqual ( [ "run_3" , "run_50" ] ) ;
10581177
10591178 loads = sessionRunLoadsReducer ( loads , runsChanged ( [ "run_3" , "run_50" ] , "run_50" ) ) ;
1060- expect ( runLoad ( loads , "run_3" ) ) . toEqual ( { state : "loading" , loadId : 1 } ) ;
1061- expect ( runLoad ( loads , "run_50" ) ) . toEqual ( { state : "loading" , loadId : 2 } ) ;
1179+ expect ( runLoad ( loads , "run_3" ) . state ) . toBe ( "loading" ) ;
1180+ expect ( runLoad ( loads , "run_50" ) . state ) . toBe ( "loading" ) ;
10621181 } ) ;
10631182
10641183 it ( "moves a queued linked run to the front" , ( ) => {
10651184 const ids = [ "run_1" , "run_2" , "run_3" , "run_4" , "run_5" ] ;
10661185 let loads = sessionRunLoadsReducer ( createSessionRunLoads ( ids ) , runsChanged ( ids , "run_5" ) ) ;
1067- expect ( loads . queue ) . toEqual ( [ "run_4" , "run_5" ] ) ;
1186+ // The newest run starts first.
1187+ expect ( loads . queue ) . toEqual ( [ "run_3" , "run_4" ] ) ;
10681188
1069- loads = sessionRunLoadsReducer ( loads , deepLinked ( "run_5 " ) ) ;
1070- expect ( loads . queue ) . toEqual ( [ "run_5 " , "run_4 " ] ) ;
1189+ loads = sessionRunLoadsReducer ( loads , deepLinked ( "run_4 " ) ) ;
1190+ expect ( loads . queue ) . toEqual ( [ "run_4 " , "run_3 " ] ) ;
10711191 } ) ;
10721192
10731193 it ( "waits for the linked run to reach the run store" , ( ) => {
0 commit comments