diff --git a/packages/react-dom-bindings/src/client/ReactDOMComponent.js b/packages/react-dom-bindings/src/client/ReactDOMComponent.js index 6454ee7c2d424..b0f452b29c59e 100644 --- a/packages/react-dom-bindings/src/client/ReactDOMComponent.js +++ b/packages/react-dom-bindings/src/client/ReactDOMComponent.js @@ -501,7 +501,7 @@ function setProp( // eslint-disable-next-line no-script-url "javascript:throw new Error('" + 'A React form was unexpectedly submitted. If you called form.submit() manually, ' + - "consider using form.requestSubmit() instead. If you're trying to use " + + "consider using form.requestSubmit() instead. If you\\'re trying to use " + 'event.stopPropagation() in a submit event handler, consider also calling ' + 'event.preventDefault().' + "')", diff --git a/packages/react-dom/src/__tests__/ReactDOMForm-test.js b/packages/react-dom/src/__tests__/ReactDOMForm-test.js index 50ef3d0212875..2cb2144f532aa 100644 --- a/packages/react-dom/src/__tests__/ReactDOMForm-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMForm-test.js @@ -922,4 +922,51 @@ describe('ReactDOMForm', () => { await act(() => resolveText('Wait')); assertLog(['Async action finished', 'No pending action']); }); + + // @gate enableFormActions + it('should error if submitting a form manually', async () => { + const ref = React.createRef(); + + let error = null; + let result = null; + + function emulateForceSubmit(submitter) { + const form = submitter.form || submitter; + const action = + (submitter && submitter.getAttribute('formaction')) || form.action; + try { + if (!/\s*javascript:/i.test(action)) { + throw new Error('Navigate to: ' + action); + } else { + // eslint-disable-next-line no-new-func + result = Function(action.slice(11))(); + } + } catch (x) { + error = x; + } + } + + const root = ReactDOMClient.createRoot(container); + await act(async () => { + root.render( +
{}} + ref={ref} + onSubmit={e => { + e.preventDefault(); + emulateForceSubmit(e.target); + }}> + +
, + ); + }); + + // This submits the form, which gets blocked and then resubmitted. It's a somewhat + // common idiom but we don't support this pattern unless it uses requestSubmit(). + await submit(ref.current); + expect(result).toBe(null); + expect(error.message).toContain( + 'A React form was unexpectedly submitted. If you called form.submit()', + ); + }); });