@@ -63,21 +63,6 @@ describe('ReactDOMForm', () => {
6363 textCache = new Map ( ) ;
6464 } ) ;
6565
66- function resolveText ( text ) {
67- const record = textCache . get ( text ) ;
68- if ( record === undefined ) {
69- const newRecord = {
70- status : 'resolved' ,
71- value : text ,
72- } ;
73- textCache . set ( text , newRecord ) ;
74- } else if ( record . status === 'pending' ) {
75- const thenable = record . value ;
76- record . status = 'resolved' ;
77- record . value = text ;
78- thenable . pings . forEach ( t => t ( ) ) ;
79- }
80- }
8166 function resolveText ( text ) {
8267 const record = textCache . get ( text ) ;
8368 if ( record === undefined ) {
@@ -997,19 +982,20 @@ describe('ReactDOMForm', () => {
997982
998983 let dispatch ;
999984 function App ( ) {
1000- const [ state , _dispatch ] = useFormState ( action , 0 ) ;
985+ const [ state , _dispatch , isPending ] = useFormState ( action , 0 ) ;
1001986 dispatch = _dispatch ;
1002- return < Text text = { state } /> ;
987+ const pending = isPending ? 'Pending ' : '' ;
988+ return < Text text = { pending + state } /> ;
1003989 }
1004990
1005991 const root = ReactDOMClient . createRoot ( container ) ;
1006992 await act ( ( ) => root . render ( < App /> ) ) ;
1007- assertLog ( [ 0 ] ) ;
993+ assertLog ( [ '0' ] ) ;
1008994 expect ( container . textContent ) . toBe ( '0' ) ;
1009995
1010996 await act ( ( ) => dispatch ( 'increment' ) ) ;
1011- assertLog ( [ 'Async action started [1]' ] ) ;
1012- expect ( container . textContent ) . toBe ( '0' ) ;
997+ assertLog ( [ 'Async action started [1]' , 'Pending 0' ] ) ;
998+ expect ( container . textContent ) . toBe ( 'Pending 0' ) ;
1013999
10141000 // Dispatch a few more actions. None of these will start until the previous
10151001 // one finishes.
@@ -1031,7 +1017,7 @@ describe('ReactDOMForm', () => {
10311017 await act ( ( ) => resolveText ( 'Wait [4]' ) ) ;
10321018
10331019 // Finally the last action finishes and we can render the result.
1034- assertLog ( [ 2 ] ) ;
1020+ assertLog ( [ '2' ] ) ;
10351021 expect ( container . textContent ) . toBe ( '2' ) ;
10361022 } ) ;
10371023
@@ -1040,40 +1026,42 @@ describe('ReactDOMForm', () => {
10401026 test ( 'useFormState supports inline actions' , async ( ) => {
10411027 let increment ;
10421028 function App ( { stepSize} ) {
1043- const [ state , dispatch ] = useFormState ( async prevState => {
1029+ const [ state , dispatch , isPending ] = useFormState ( async prevState => {
10441030 return prevState + stepSize ;
10451031 } , 0 ) ;
10461032 increment = dispatch ;
1047- return < Text text = { state } /> ;
1033+ const pending = isPending ? 'Pending ' : '' ;
1034+ return < Text text = { pending + state } /> ;
10481035 }
10491036
10501037 // Initial render
10511038 const root = ReactDOMClient . createRoot ( container ) ;
10521039 await act ( ( ) => root . render ( < App stepSize = { 1 } /> ) ) ;
1053- assertLog ( [ 0 ] ) ;
1040+ assertLog ( [ '0' ] ) ;
10541041
10551042 // Perform an action. This will increase the state by 1, as defined by the
10561043 // stepSize prop.
10571044 await act ( ( ) => increment ( ) ) ;
1058- assertLog ( [ 1 ] ) ;
1045+ assertLog ( [ 'Pending 0' , '1' ] ) ;
10591046
10601047 // Now increase the stepSize prop to 10. Subsequent steps will increase
10611048 // by this amount.
10621049 await act ( ( ) => root . render ( < App stepSize = { 10 } /> ) ) ;
1063- assertLog ( [ 1 ] ) ;
1050+ assertLog ( [ '1' ] ) ;
10641051
10651052 // Increment again. The state should increase by 10.
10661053 await act ( ( ) => increment ( ) ) ;
1067- assertLog ( [ 11 ] ) ;
1054+ assertLog ( [ 'Pending 1' , '11' ] ) ;
10681055 } ) ;
10691056
10701057 // @gate enableFormActions
10711058 // @gate enableAsyncActions
10721059 test ( 'useFormState: dispatch throws if called during render' , async ( ) => {
10731060 function App ( ) {
1074- const [ state , dispatch ] = useFormState ( async ( ) => { } , 0 ) ;
1061+ const [ state , dispatch , isPending ] = useFormState ( async ( ) => { } , 0 ) ;
10751062 dispatch ( ) ;
1076- return < Text text = { state } /> ;
1063+ const pending = isPending ? 'Pending ' : '' ;
1064+ return < Text text = { pending + state } /> ;
10771065 }
10781066
10791067 const root = ReactDOMClient . createRoot ( container ) ;
@@ -1088,21 +1076,25 @@ describe('ReactDOMForm', () => {
10881076 test ( 'queues multiple actions and runs them in order' , async ( ) => {
10891077 let action ;
10901078 function App ( ) {
1091- const [ state , dispatch ] = useFormState (
1079+ const [ state , dispatch , isPending ] = useFormState (
10921080 async ( s , a ) => await getText ( a ) ,
10931081 'A' ,
10941082 ) ;
10951083 action = dispatch ;
1096- return < Text text = { state } /> ;
1084+ const pending = isPending ? 'Pending ' : '' ;
1085+ return < Text text = { pending + state } /> ;
10971086 }
10981087
10991088 const root = ReactDOMClient . createRoot ( container ) ;
11001089 await act ( ( ) => root . render ( < App /> ) ) ;
11011090 assertLog ( [ 'A' ] ) ;
11021091
11031092 await act ( ( ) => action ( 'B' ) ) ;
1093+ // The first dispatch will update the pending state.
1094+ assertLog ( [ 'Pending A' ] ) ;
11041095 await act ( ( ) => action ( 'C' ) ) ;
11051096 await act ( ( ) => action ( 'D' ) ) ;
1097+ assertLog ( [ ] ) ;
11061098
11071099 await act ( ( ) => resolveText ( 'B' ) ) ;
11081100 await act ( ( ) => resolveText ( 'C' ) ) ;
@@ -1117,51 +1109,56 @@ describe('ReactDOMForm', () => {
11171109 test ( 'useFormState: works if action is sync' , async ( ) => {
11181110 let increment ;
11191111 function App ( { stepSize} ) {
1120- const [ state , dispatch ] = useFormState ( prevState => {
1112+ const [ state , dispatch , isPending ] = useFormState ( prevState => {
11211113 return prevState + stepSize ;
11221114 } , 0 ) ;
11231115 increment = dispatch ;
1124- return < Text text = { state } /> ;
1116+ const pending = isPending ? 'Pending ' : '' ;
1117+ return < Text text = { pending + state } /> ;
11251118 }
11261119
11271120 // Initial render
11281121 const root = ReactDOMClient . createRoot ( container ) ;
11291122 await act ( ( ) => root . render ( < App stepSize = { 1 } /> ) ) ;
1130- assertLog ( [ 0 ] ) ;
1123+ assertLog ( [ '0' ] ) ;
11311124
11321125 // Perform an action. This will increase the state by 1, as defined by the
11331126 // stepSize prop.
11341127 await act ( ( ) => increment ( ) ) ;
1135- assertLog ( [ 1 ] ) ;
1128+ assertLog ( [ 'Pending 0' , '1' ] ) ;
11361129
11371130 // Now increase the stepSize prop to 10. Subsequent steps will increase
11381131 // by this amount.
11391132 await act ( ( ) => root . render ( < App stepSize = { 10 } /> ) ) ;
1140- assertLog ( [ 1 ] ) ;
1133+ assertLog ( [ '1' ] ) ;
11411134
11421135 // Increment again. The state should increase by 10.
11431136 await act ( ( ) => increment ( ) ) ;
1144- assertLog ( [ 11 ] ) ;
1137+ assertLog ( [ 'Pending 1' , '11' ] ) ;
11451138 } ) ;
11461139
11471140 // @gate enableFormActions
11481141 // @gate enableAsyncActions
11491142 test ( 'useFormState: can mix sync and async actions' , async ( ) => {
11501143 let action ;
11511144 function App ( ) {
1152- const [ state , dispatch ] = useFormState ( ( s , a ) => a , 'A' ) ;
1145+ const [ state , dispatch , isPending ] = useFormState ( ( s , a ) => a , 'A' ) ;
11531146 action = dispatch ;
1154- return < Text text = { state } /> ;
1147+ const pending = isPending ? 'Pending ' : '' ;
1148+ return < Text text = { pending + state } /> ;
11551149 }
11561150
11571151 const root = ReactDOMClient . createRoot ( container ) ;
11581152 await act ( ( ) => root . render ( < App /> ) ) ;
11591153 assertLog ( [ 'A' ] ) ;
11601154
11611155 await act ( ( ) => action ( getText ( 'B' ) ) ) ;
1156+ // The first dispatch will update the pending state.
1157+ assertLog ( [ 'Pending A' ] ) ;
11621158 await act ( ( ) => action ( 'C' ) ) ;
11631159 await act ( ( ) => action ( getText ( 'D' ) ) ) ;
11641160 await act ( ( ) => action ( 'E' ) ) ;
1161+ assertLog ( [ ] ) ;
11651162
11661163 await act ( ( ) => resolveText ( 'B' ) ) ;
11671164 await act ( ( ) => resolveText ( 'D' ) ) ;
@@ -1189,14 +1186,15 @@ describe('ReactDOMForm', () => {
11891186
11901187 let action ;
11911188 function App ( ) {
1192- const [ state , dispatch ] = useFormState ( ( s , a ) => {
1189+ const [ state , dispatch , isPending ] = useFormState ( ( s , a ) => {
11931190 if ( a . endsWith ( '!' ) ) {
11941191 throw new Error ( a ) ;
11951192 }
11961193 return a ;
11971194 } , 'A' ) ;
11981195 action = dispatch ;
1199- return < Text text = { state } /> ;
1196+ const pending = isPending ? 'Pending ' : '' ;
1197+ return < Text text = { pending + state } /> ;
12001198 }
12011199
12021200 const root = ReactDOMClient . createRoot ( container ) ;
@@ -1210,7 +1208,13 @@ describe('ReactDOMForm', () => {
12101208 assertLog ( [ 'A' ] ) ;
12111209
12121210 await act ( ( ) => action ( 'Oops!' ) ) ;
1213- assertLog ( [ 'Caught an error: Oops!' , 'Caught an error: Oops!' ] ) ;
1211+ assertLog ( [
1212+ // Action begins, error has not thrown yet.
1213+ 'Pending A' ,
1214+ // Now the action runs and throws.
1215+ 'Caught an error: Oops!' ,
1216+ 'Caught an error: Oops!' ,
1217+ ] ) ;
12141218 expect ( container . textContent ) . toBe ( 'Caught an error: Oops!' ) ;
12151219
12161220 // Reset the error boundary
@@ -1223,7 +1227,7 @@ describe('ReactDOMForm', () => {
12231227 action ( 'Oops!' ) ;
12241228 action ( 'B' ) ;
12251229 } ) ;
1226- assertLog ( [ 'B' ] ) ;
1230+ assertLog ( [ 'Pending A' , ' B'] ) ;
12271231 expect ( container . textContent ) . toBe ( 'B' ) ;
12281232 } ) ;
12291233
@@ -1247,15 +1251,16 @@ describe('ReactDOMForm', () => {
12471251
12481252 let action ;
12491253 function App ( ) {
1250- const [ state , dispatch ] = useFormState ( async ( s , a ) => {
1254+ const [ state , dispatch , isPending ] = useFormState ( async ( s , a ) => {
12511255 const text = await getText ( a ) ;
12521256 if ( text . endsWith ( '!' ) ) {
12531257 throw new Error ( text ) ;
12541258 }
12551259 return text ;
12561260 } , 'A' ) ;
12571261 action = dispatch ;
1258- return < Text text = { state } /> ;
1262+ const pending = isPending ? 'Pending ' : '' ;
1263+ return < Text text = { pending + state } /> ;
12591264 }
12601265
12611266 const root = ReactDOMClient . createRoot ( container ) ;
@@ -1269,7 +1274,8 @@ describe('ReactDOMForm', () => {
12691274 assertLog ( [ 'A' ] ) ;
12701275
12711276 await act ( ( ) => action ( 'Oops!' ) ) ;
1272- assertLog ( [ ] ) ;
1277+ // The first dispatch will update the pending state.
1278+ assertLog ( [ 'Pending A' ] ) ;
12731279 await act ( ( ) => resolveText ( 'Oops!' ) ) ;
12741280 assertLog ( [ 'Caught an error: Oops!' , 'Caught an error: Oops!' ] ) ;
12751281 expect ( container . textContent ) . toBe ( 'Caught an error: Oops!' ) ;
@@ -1284,7 +1290,7 @@ describe('ReactDOMForm', () => {
12841290 action ( 'Oops!' ) ;
12851291 action ( 'B' ) ;
12861292 } ) ;
1287- assertLog ( [ ] ) ;
1293+ assertLog ( [ 'Pending A' ] ) ;
12881294 await act ( ( ) => resolveText ( 'B' ) ) ;
12891295 assertLog ( [ 'B' ] ) ;
12901296 expect ( container . textContent ) . toBe ( 'B' ) ;
0 commit comments