Repository: jaredpalmer/formik
Pull request #638 (2018-05-15 13:39:24)

Fix: Guard and test unspecified button warning
My last PR was over warning. These changes should only warn if the form was submitted with a button and the button has no explicit type.

I also added test cases for the warning.


Patch:
diff --git a/src/Formik.tsx b/src/Formik.tsx
index 4cecc33..1a5d156 100644
--- a/src/Formik.tsx
+++ b/src/Formik.tsx
@@ -280,13 +280,17 @@ export class Formik<ExtraProps = {}, Values = object> extends React.Component<
         document.activeElement.attributes &&
         document.activeElement.attributes.getNamedItem('type');
 
-      const submitTriggeredFromButtonWithType =
-        document.activeElement instanceof HTMLButtonElement && type;
+      const submitTriggeredFromButton =
+        document.activeElement instanceof HTMLButtonElement;
 
-      warning(
-        submitTriggeredFromButtonWithType,
-        'You submitted a Formik form using a button with an unspecified type.  Most browsers default button elements to type="submit". If this is not a submit button please add type="button".'
-      );
+      const buttonHasType = submitTriggeredFromButton && !!type;
+
+      if (submitTriggeredFromButton) {
+        warning(
+          buttonHasType,
+          'You submitted a Formik form using a button with an unspecified type.  Most browsers default button elements to type="submit". If this is not a submit button please add type="button".'
+        );
+      }
     }
 
     this.submitForm();


Test patch:
diff --git a/test/Formik.test.tsx b/test/Formik.test.tsx
index 7e4266b..c0c30b0 100644
--- a/test/Formik.test.tsx
+++ b/test/Formik.test.tsx
@@ -3,6 +3,8 @@ import { Formik, FormikProps } from '../src';
 import { shallow, mount } from '@pisano/enzyme';
 import { sleep, noop } from './testHelpers';
 
+jest.spyOn(global.console, 'error');
+
 interface Values {
   name: string;
 }
@@ -1094,4 +1096,106 @@ describe('<Formik>', () => {
       ).toEqual(0);
     });
   });
+
+  it('should warn against buttons with unspecified type', () => {
+    const FormWithNoButtonType = () => (
+      <Formik onSubmit={noop} initialValues={{ opensource: 'yay' }}>
+        {({ handleSubmit, handleChange, values }) => (
+          <form onSubmit={handleSubmit}>
+            <input
+              type="text"
+              onChange={handleChange}
+              value={values.opensource}
+              name="name"
+            />
+            <button>Submit</button>
+          </form>
+        )}
+      </Formik>
+    );
+    const tree = mount(<FormWithNoButtonType />);
+    const preventDefault = jest.fn();
+    const button = tree.find('button').getDOMNode();
+
+    button.focus(); // sets activeElement
+    tree.find('form').simulate('submit', {
+      preventDefault,
+    });
+    expect(global.console.error).toHaveBeenCalledWith(
+      expect.stringMatching(
+        /Warning: You submitted a Formik form using a button with an unspecified type./
+      )
+    );
+
+    button.blur(); // unsets activeElement
+    global.console.error.mockClear();
+  });
+
+  it('should not warn when button has type submit', () => {
+    const FormWithValidButtonType = () => (
+      <Formik onSubmit={noop} initialValues={{ opensource: 'yay' }}>
+        {({ handleSubmit, handleChange, values }) => (
+          <form onSubmit={handleSubmit}>
+            <input
+              type="text"
+              onChange={handleChange}
+              value={values.opensource}
+              name="name"
+            />
+            <button type="submit">Submit</button>
+          </form>
+        )}
+      </Formik>
+    );
+    const tree = mount(<FormWithValidButtonType />);
+    const preventDefault = jest.fn();
+    const button = tree.find('button').getDOMNode();
+
+    button.focus(); // sets activeElement
+    tree.find('form').simulate('submit', {
+      preventDefault,
+    });
+    expect(global.console.error).not.toHaveBeenCalledWith(
+      expect.stringMatching(
+        /Warning: You submitted a Formik form using a button with an unspecified type./
+      )
+    );
+
+    button.blur(); // unsets activeElement
+    global.console.error.mockClear();
+  });
+
+  it('should not warn when activeElement is not a button', () => {
+    const FormWithInput = () => (
+      <Formik onSubmit={noop} initialValues={{ opensource: 'yay' }}>
+        {({ handleSubmit, handleChange, values }) => (
+          <form onSubmit={handleSubmit}>
+            <input
+              type="text"
+              onChange={handleChange}
+              value={values.opensource}
+              name="name"
+            />
+            <button type="submit">Submit</button>
+          </form>
+        )}
+      </Formik>
+    );
+    const tree = mount(<FormWithInput />);
+    const preventDefault = jest.fn();
+    const input = tree.find('input').getDOMNode();
+
+    input.focus(); // sets activeElement
+    tree.find('form').simulate('submit', {
+      preventDefault,
+    });
+    expect(global.console.error).not.toHaveBeenCalledWith(
+      expect.stringMatching(
+        /Warning: You submitted a Formik form using a button with an unspecified type./
+      )
+    );
+
+    input.blur(); // unsets activeElement
+    global.console.error.mockClear();
+  });
 });