@@ -190,6 +190,8 @@ describe('ReactDOMForm', () => {
190190 ( submitter && submitter . getAttribute ( 'formaction' ) ) || form . action ;
191191 if ( ! / \s * j a v a s c r i p t : / i. test ( action ) ) {
192192 throw new Error ( 'Navigate to: ' + action ) ;
193+ } else {
194+ Function ( action . substr ( 11 ) ) ( ) ;
193195 }
194196 } ) ;
195197 }
@@ -922,4 +924,66 @@ describe('ReactDOMForm', () => {
922924 await act ( ( ) => resolveText ( 'Wait' ) ) ;
923925 assertLog ( [ 'Async action finished' , 'No pending action' ] ) ;
924926 } ) ;
927+
928+ function emulateForceSubmit ( submitter ) {
929+ const form = submitter . form || submitter ;
930+ const action =
931+ ( submitter && submitter . getAttribute ( 'formaction' ) ) || form . action ;
932+ if ( ! / \s * j a v a s c r i p t : / i. test ( action ) ) {
933+ throw new Error ( 'Navigate to: ' + action ) ;
934+ } else {
935+ Function ( action . substr ( 11 ) ) ( ) ;
936+ }
937+ }
938+
939+ // @gate enableFormActions
940+ it ( 'should error if submitting a form manually' , async ( ) => {
941+ const ref = React . createRef ( ) ;
942+ let foo ;
943+
944+ function action ( formData ) {
945+ foo = formData . get ( 'foo' ) ;
946+ }
947+
948+ let error = null ;
949+ let result = null ;
950+
951+ function emulateForceSubmit ( submitter ) {
952+ const form = submitter . form || submitter ;
953+ const action =
954+ ( submitter && submitter . getAttribute ( 'formaction' ) ) || form . action ;
955+ if ( ! / \s * j a v a s c r i p t : / i. test ( action ) ) {
956+ throw new Error ( 'Navigate to: ' + action ) ;
957+ } else {
958+ try {
959+ result = Function ( action . substr ( 11 ) ) ( ) ;
960+ } catch ( x ) {
961+ error = x ;
962+ }
963+ }
964+ }
965+
966+ const root = ReactDOMClient . createRoot ( container ) ;
967+ await act ( async ( ) => {
968+ root . render (
969+ < form
970+ action = { action }
971+ ref = { ref }
972+ onSubmit = { e => {
973+ e . preventDefault ( ) ;
974+ emulateForceSubmit ( e . target ) ;
975+ } } >
976+ < input type = "text" name = "foo" defaultValue = "bar" />
977+ </ form > ,
978+ ) ;
979+ } ) ;
980+
981+ // This submits the form, which gets blocked and then resubmitted. It's a somewhat
982+ // common idiom but we don't support this pattern unless it uses requestSubmit().
983+ await submit ( ref . current ) ;
984+ expect ( result ) . toBe ( null ) ;
985+ expect ( error . message ) . toContain (
986+ 'A React form was unexpectedly submitted. If you called form.submit()' ,
987+ ) ;
988+ } ) ;
925989} ) ;
0 commit comments