Repository: jaredpalmer/formik (ts)

Issue:
Add enableReinitialize option and set it to false by default
Currently, if you pass `initialValues`, you can overwrite them by passing another value - the form will update its values.

This brings a problem when your data is stored for example in redux or in another component. You get this data and pass into form. Once this values are changed (in redux / another component) - your form *magically* updates and removes all data you've changed.

In redux-form there is a nice [enableReinitialize](https://redux-form.com/7.0.4/docs/api/reduxform.md/#-code-enablereinitialize-boolean-code-optional-) option which is `false` by default. You can set it to `true` and your form will update itself.

I think, the same behavior and option should be added to formik so your data won't suddenly disappear.

---

Related issues - https://github.com/jaredpalmer/formik/issues/163, https://github.com/jaredpalmer/formik/issues/164

For the first related issue, there is [keepDirtyOnReinitialize](https://redux-form.com/7.0.4/docs/api/reduxform.md/#-code-keepdirtyonreinitialize-boolean-code-optional-) option which prevents form from refreshing dirty values on `initialValues` change.

Pull request description:
Add enableReinitialize option

- Adds a `enableReinitialize`  option, default is `false`. If true, form will reset when `initialValues` (or the result of `mapPropsToValues` in HoC land) is different (using deep equality). (#168 , #188) 
- Adds readonly `initialValues` prop to the Formik bag (#161)

Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..b9557e8
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,10 @@
+# Contributing to Formik
+
+1. Fork this repository to your own GitHub account and then clone it to your local device.
+2. Install the dependencies: `yarn install`
+3. Run `yarn link` to link the local repo to NPM
+4. Run `yarn start` to build and watch for code changes
+5. Run `yarn test` to start Jest
+7. Then npm link this repo inside any other project on your local dev with `yarn link formik`
+8. Then you can use your local version of Formik within your project
+
diff --git a/README.md b/README.md
index 687b43d..05e41d0 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ By now, you might be thinking, "Why didn't you just use [Redux-Form](https://git
  1. According to our prophet Dan Abramov, [**form state is inherently emphemeral and local**, so tracking it in Redux is  unecessary](https://github.com/reactjs/redux/issues/1287#issuecomment-175351978)
  2. Redux-Form calls your entire top-level reducer multiple times ON EVERY KEYSTROKE. This is fine for small apps, but as your Redux app grows, input latency will continue increase if you use Redux-Form
  3. I no longer use [Redux](https://github.com/reactjs/redux) or [MobX](https://mobx.js.org/), just React's setState.
- 4. Redux-Form is 22.5 kB minified gzipped (Formik is 8.9 kB)
+ 4. Redux-Form is 22.5 kB minified gzipped (Formik is 9.2 kB)
 
 My goal with Formik was to create a scalable, performant, form helper with a minimal API that does the really really annoying stuff, and leaves the rest up to you.
 
@@ -252,35 +252,33 @@ npm install yup --save
     - [`component`](#component)
     - [`render: (props: FormikProps<Values>) => ReactNode`](#render-props-formikpropsvalues--reactnode)
     - [`children: func`](#children-func)
-    - [`onSubmit: (values: Values, formikBag: FormikBag) => void`](#onsubmit-values-values-formikbag-formikbag--void)
+    - [`enableReinitialize?: boolean`](#enablereinitialize-boolean)
     - [`isInitialValid?: boolean`](#isinitialvalid-boolean)
     - [`initialValues?: Values`](#initialvalues-values)
-    - [`validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`](#validate-values-values-props-props--formikerrorvalues--promiseany)
+    - [`onSubmit: (values: Values, formikBag: FormikBag) => void`](#onsubmit-values-values-formikbag-formikbag--void)
+    - [`validate?: (values: Values) => FormikError<Values> | Promise<any>`](#validate-values-values--formikerrorvalues--promiseany)
     - [`validateOnBlur?: boolean`](#validateonblur-boolean)
     - [`validateOnChange?: boolean`](#validateonchange-boolean)
-    - [`validationSchema?: Schema | ((props: Props) => Schema)`](#validationschema-schema--props-props--schema)
+    - [`validationSchema?: Schema | (() => Schema)`](#validationschema-schema----schema)
   - [`<Field />`](#field-)
   - [`<Form />`](#form-)
   - [`withFormik(options)`](#withformikoptions)
     - [`options`](#options)
       - [`displayName?: string`](#displayname-string)
+      - [`enableReinitialize?: boolean`](#enablereinitialize-boolean-1)
       - [`handleSubmit: (values: Values, formikBag: FormikBag) => void`](#handlesubmit-values-values-formikbag-formikbag--void)
         - [The "FormikBag":](#the-formikbag)
       - [`isInitialValid?: boolean | (props: Props) => boolean`](#isinitialvalid-boolean--props-props--boolean)
       - [`mapPropsToValues?: (props: Props) => Values`](#mappropstovalues-props-props--values)
-      - [`validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`](#validate-values-values-props-props--formikerrorvalues--promiseany-1)
+      - [`validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`](#validate-values-values-props-props--formikerrorvalues--promiseany)
       - [`validateOnBlur?: boolean`](#validateonblur-boolean-1)
       - [`validateOnChange?: boolean`](#validateonchange-boolean-1)
-      - [`validationSchema?: Schema | ((props: Props) => Schema)`](#validationschema-schema--props-props--schema-1)
+      - [`validationSchema?: Schema | ((props: Props) => Schema)`](#validationschema-schema--props-props--schema)
     - [Injected props and methods](#injected-props-and-methods)
 - [Guides](#guides)
   - [React Native](#react-native)
     - [Why use `setFieldValue` instead of `handleChange`?](#why-use-setfieldvalue-instead-of-handlechange)
     - [Avoiding a Render Callback](#avoiding-a-render-callback)
-  - [Testing Formik](#testing-formik)
-    - [Dummy Form](#dummy-form)
-    - [Simulating input](#simulating-input)
-    - [Simulating form submission](#simulating-form-submission)
 - [Organizations and projects using Formik](#organizations-and-projects-using-formik)
 - [Authors](#authors)
 - [Contributors](#contributors)
@@ -646,11 +644,9 @@ const ContactForm = ({ handleSubmit, handleChange, handleBlur, values, errors })
 ```
 
 
+#### `enableReinitialize?: boolean`
 
-#### `onSubmit: (values: Values, formikBag: FormikBag) => void`
-Your form submission handler. It is passed your forms [`values`] and the "FormikBag", which includes an object containing a subset of the [injected props and methods](/#injected-props-and-methods) (i.e. all the methods with names that start with `set<Thing>` + `resetForm`) and any props that were passed to the the wrapped component.
-
-Note: [`errors`], [`touched`], [`status`] and all event handlers are NOT included in the `FormikBag`.
+Default is `false`. Control whether Formik should reset the form if [`initialValues`] changes (using deep equality).
 
 #### `isInitialValid?: boolean`
 
@@ -658,11 +654,18 @@ Default is `false`. Control the initial value of [`isValid`] prop prior to mount
 
 #### `initialValues?: Values`
 
-If this option is specified, then Formik will transfer its results into updatable form state and make these values available to the new component as [`props.values`][`values`]. If `mapPropsToValues` is not specified, then Formik will map all props that are not functions to the inner component's [`props.values`][`values`]. That is, if you omit it, Formik will only pass `props` where `typeof props[k] !== 'function'`, where `k` is some key.
+Initial field values of the form, Formik will make these values available to render methods component as [`props.values`][`values`]. 
 
-Even if your form is not receiving any props from its parent, use `mapPropsToValues` to initialize your forms empty state.
+Even if your form is empty by default, you must initialize all fields with initial values otherwise React will throw an error saying that you have changed an input from uncontrolled to controlled.
 
-#### `validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`
+Note: `initialValues` not available to the higher-order component, use [`mapPropsToValues`] instead.
+
+#### `onSubmit: (values: Values, formikBag: FormikBag) => void`
+Your form submission handler. It is passed your forms [`values`] and the "FormikBag", which includes an object containing a subset of the [injected props and methods](/#injected-props-and-methods) (i.e. all the methods with names that start with `set<Thing>` + `resetForm`) and any props that were passed to the the wrapped component.
+
+Note: [`errors`], [`touched`], [`status`] and all event handlers are NOT included in the `FormikBag`.
+
+#### `validate?: (values: Values) => FormikError<Values> | Promise<any>`
 
 _Note: I suggest using [`validationSchema`] and Yup for validation. However, `validate` is a dependency-free, straightforward way to validate your forms._
 
@@ -714,7 +717,7 @@ Default is `true`. Use this option to run validations on `blur` events. More spe
 
 Default is `true`. Use this option to tell Formik to run validations on `change` events and `change`-related methods. More specifically, when either [`handleChange`], [`setFieldValue`], or [`setValues`] are called.
 
-#### `validationSchema?: Schema | ((props: Props) => Schema)`
+#### `validationSchema?: Schema | (() => Schema)`
 
 [A Yup schema](https://github.com/jquense/yup) or a function that returns a Yup schema. This is used for validation. Errors are mapped by key to the inner component's [`errors`]. Its keys should match those of [`values`].
 
@@ -815,6 +818,10 @@ Create a higher-order React component class that passes props and form handlers
 ##### `displayName?: string`
 When your inner form component is a stateless functional component, you can use the `displayName` option to give the component a proper name so you can more easily find it in [React DevTools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en). If specified, your wrapped form will show up as `Formik(displayName)`. If omitted, it will show up as `Formik(Component)`. This option is not required for class components (e.g. `class XXXXX extends React.Component {..}`).
 
+##### `enableReinitialize?: boolean`
+
+Default is `false`. Control whether Formik should reset the form if the wrapped component props change (using deep equality).
+
 ##### `handleSubmit: (values: Values, formikBag: FormikBag) => void`
 Your form submission handler. It is passed your forms [`values`] and the "FormikBag", which includes an object containing a subset of the [injected props and methods](/#injected-props-and-methods) (i.e. all the methods with names that start with `set<Thing>` + `resetForm`) and any props that were passed to the the wrapped component.
 
@@ -1069,182 +1076,6 @@ const MyReactNativeForm = props => (
 export default MyReactNativeForm
 ```
 
-### Testing Formik
-
-_This section is a work in progress._
-
-The suggested approach to testing Formik forms is with Airbnb's [Enzyme](https://github.com/airbnb/enzyme) test utility library.
-
-The documentation and examples in this guide use Facebook's [Jest](https://facebook.github.io/jest) test runner. However, feel free to use [mocha](https://mochajs.org/) and [chai](http://chaijs.com/) if you prefer that.
-
-To get started with Enzyme, you can simply install it with npm:
-
-```bash
-npm i  enzyme --save-dev
-```
-
-If you are using React >=15.5, in addition to enzyme, you will have to ensure that you also have the following npm modules installed if they were not already:
-
-```bash
-npm i react-test-renderer react-dom  --save-dev
-```
-
-####  Dummy Form
-Imagine we have a basic form with one field `name`.
-
-```js
-// MyForm.js
-import { Formik } from 'formik';
-import Yup from 'yup';
-
-export const validationSchema = Yup.object().shape({
-  name: Yup.string()
-    .min(2, 'Must be longer than 2 characters')
-    .max(30, "No one's name is that long")
-    .required('Required'),
-});
-
-export const handleSubmit = (values, { setSubmitting }) => {
-  setTimeout(() => {
-    setSubmitting(false);
-  }, 1000);
-};
-
-export const mapPropsToValues = props => ({ name: '' });
-
-export const MyFormInner = ({
-  values,
-  handleSubmit,
-  handleChange,
-  handleBlur,
-  setStatus,
-  status,
-  errors,
-  isSubmitting,
-}) => {
-  return (
-    <form onSubmit={handleSubmit}>
-      <input
-        type="text"
-        onChange={handleChange}
-        onBlur={handleBlur}
-        value={values.name}
-        name="name"
-      />
-      {errors.name &&
-        <div id="feedback">
-          {errors.name}
-        </div>}
-      {isSubmitting && <div id="submitting">Submitting</div>}
-      {status &&
-        !!status.myStatusMessage &&
-        <div id="status">
-          {status.myStatusMessage}
-        </div>}
-      <button type="submit">Submit</button>
-    </form>
-  );
-};
-
-export default Formik({
-  mapPropsToValues,
-  validationSchema,
-  handleSubmit,
-})(MyFormInner);
-```
-
-#### Simulating input
-
-We can test that our UI is updating properly by using Enzyme's `shallow` renderer in addition to its `dive()` and `simulate()` methods. This lets us render the Formik-enhanced form, but then jump down and run simulations and assertions from the perspective of your inner form.
-
-```js
-// MyForm.test.js
-import MyForm, { MyInnerForm } from './MyForm';
-
-describe('MyForm', () => {
-  test('should update an input when it is changed', () => {
-    const tree = shallow(<MyForm />);
-
-    tree.find(MyInnerForm).dive().find('input').simulate('change', {
-      // you must add this next line as (Formik calls e.persist() internally)
-      persist: () => {},
-      // simulate changing e.target.name and e.target.value
-      target: {
-        name: 'name',
-        value: 'ian',
-      },
-    });
-
-    const newValue = tree.find(MyInnerForm).dive().find('input').props().value;
-
-    expect(newValue).toEqual('ian');
-  });
-});
-
-```
-
-#### Simulating form submission
-
-```js
-// MyForm.test.js
-import MyForm, { MyInnerForm, validationSchema } from './MyForm';
-
-describe('MyForm', () => {
-  test('submits the form', () => {
-    const tree = shallow(<MyForm />);
-    expect(tree.find(MyInnerForm).dive().find('#submitting')).toHaveLength(0);
-
-    // simulate submit event. this is always sync! async calls to setState are swallowed.
-    // be careful of false positives
-    tree.find(MyInnerForm).dive().find('form').simulate('submit', {
-      preventDefault: () => {}, // no op
-    });
-
-    // Because the simulated event is 100% sync, we can use it to test the synchronous changes
-    // here. Any async stuff you do inside handleSubmit will be swallowed. Thus our UI
-    // will see the following changes:
-    // - isSubmitting -> true (even if you set it to false asynchronously in your handleSubmit)
-    // - touched: all fields
-    expect(tree.find(Form).dive().find('#submitting')).toHaveLength(1);
-    expect(
-      tree.find(Form).dive().find('button[type="submit"]').props().disabled
-    ).toBe(true);
-  });
-
-  test('what happens when the form is submitted', async () => {
-    const tree = shallow(<MyForm />);
-
-    expect(tree.find(MyInnerForm).dive().find('#submitting')).toHaveLength(0);
-
-    await mockCallsToMyApi();
-    await tree.find(MyInnerForm).props().submitForm();
-
-    // check that ui has completely updated
-    expect(
-      tree.find(MyInnerForm).update().dive().find('#submitting')
-    ).toHaveLength(0);
-    expect(tree.find(MyInnerForm).update().dive().find('#status').text).toEqual(
-      'Success!'
-    );
-    expect(
-      tree
-        .find(MyInnerForm)
-        .update()
-        .dive()
-        .find('button[type="submit"]')
-        .props().disabled
-    ).toBe(false);
-
-    // check that props have updated
-    expect(tree.find(MyInnerForm).props().status).toEqual({
-      myStatusMessage: 'Success!',
-    });
-    expect(tree.find(MyInnerForm).props().errors).toEqual({});
-    expect(tree.find(MyInnerForm).props().touched).toEqual({ name: true }); // submit will touch all fields
-  });
-});
-```
-
 ## Organizations and projects using Formik
 
 [List of organizations and projects using Formik](https://github.com/jaredpalmer/formik/issues/87)
diff --git a/package.json b/package.json
index 7835323..bb88c37 100644
--- a/package.json
+++ b/package.json
@@ -18,9 +18,7 @@
   "main": "dist/formik.js",
   "module": "dist/formik.es6.js",
   "typings": "dist/formik.d.ts",
-  "files": [
-    "dist"
-  ],
+  "files": ["dist"],
   "scripts": {
     "test": "jest --env=jsdom",
     "test:watch": "npm run test -- --watch",
@@ -79,15 +77,18 @@
     "yup": "0.21.3"
   },
   "lint-staged": {
-    "*.(ts|tsx)": [
+    "**/*.{ts,tsx}": [
       "prettier --trailing-comma es5 --single-quote --write",
       "git add"
     ]
   },
+  "prettier": {
+    "trailingComma": "es5",
+    "singleQuote": true,
+    "semi": true
+  },
   "jest": {
-    "collectCoverageFrom": [
-      "src/**/*.{ts,tsx}"
-    ],
+    "collectCoverageFrom": ["src/**/*.{ts,tsx}"],
     "transform": {
       ".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
     },
@@ -95,14 +96,7 @@
       "<rootDir>/test/**/*.ts?(x)",
       "<rootDir>/test/**/?(*.)(spec|test).ts?(x)"
     ],
-    "transformIgnorePatterns": [
-      "[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$"
-    ],
-    "moduleFileExtensions": [
-      "ts",
-      "tsx",
-      "js",
-      "json"
-    ]
+    "transformIgnorePatterns": ["[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$"],
+    "moduleFileExtensions": ["ts", "tsx", "js", "json"]
   }
 }
diff --git a/src/formik.tsx b/src/formik.tsx
index 18a5291..ccb468b 100644
--- a/src/formik.tsx
+++ b/src/formik.tsx
@@ -51,11 +51,13 @@ export interface FormikState<Values> {
 /**
  * Formik computed properties. These are read-only.
  */
-export interface FormikComputedProps {
+export interface FormikComputedProps<Values> {
   /** True if any input has been touched. False otherwise. */
   readonly dirty: boolean;
   /** Result of isInitiallyValid on mount, then whether true values pass validation. */
   readonly isValid: boolean;
+  /** initialValues */
+  readonly initialValues: Values;
 }
 
 /**
@@ -115,6 +117,8 @@ export interface FormikSharedConfig {
   validateOnBlur?: boolean;
   /** Tell Formik if initial form values are valid or not on first render */
   isInitialValid?: boolean | ((props: object) => boolean | undefined);
+  /** Should Formik reset the form when new initialValues change */
+  enableReinitialize?: boolean;
 }
 
 /**
@@ -165,7 +169,7 @@ export interface FormikConfig extends FormikSharedConfig {
 export type FormikProps<Values> = FormikState<Values> &
   FormikActions<Values> &
   FormikHandlers &
-  FormikComputedProps;
+  FormikComputedProps<Values>;
 
 const isEmptyChildren = (children: any) => React.Children.count(children) === 0;
 
@@ -176,6 +180,7 @@ export class Formik<
     validateOnChange: true,
     validateOnBlur: true,
     isInitialValid: false,
+    enableReinitialize: false,
   };
 
   static propTypes = {
@@ -189,12 +194,15 @@ export class Formik<
     component: PropTypes.func,
     render: PropTypes.func,
     children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
+    enableReinitialize: PropTypes.bool,
   };
 
   static childContextTypes = {
     formik: PropTypes.object,
   };
 
+  initialValues: any;
+
   getChildContext() {
     const dirty =
       values<boolean>(this.state.touched).filter(Boolean).length > 0;
@@ -225,6 +233,7 @@ export class Formik<
         setSubmitting: this.setSubmitting,
         resetForm: this.resetForm,
         submitForm: this.submitForm,
+        initialValues: this.initialValues,
       },
     };
   }
@@ -237,11 +246,17 @@ export class Formik<
       touched: {},
       isSubmitting: false,
     };
+
+    this.initialValues = props.initialValues || ({} as any);
   }
 
   componentWillReceiveProps(nextProps: Props) {
     // If the initialValues change, reset the form
-    if (!isEqual(nextProps.initialValues, this.props.initialValues)) {
+    if (
+      this.props.enableReinitialize &&
+      !isEqual(nextProps.initialValues, this.props.initialValues)
+    ) {
+      this.initialValues = nextProps.initialValues;
       this.resetForm(nextProps.initialValues);
     }
   }
@@ -491,16 +506,16 @@ Formik cannot determine which value to update. For more info see https://github.
 
   executeSubmit = () => {
     this.props.onSubmit(this.state.values, {
-      setStatus: this.setStatus,
-      setTouched: this.setTouched,
-      setErrors: this.setErrors,
+      resetForm: this.resetForm,
       setError: this.setError,
-      setValues: this.setValues,
+      setErrors: this.setErrors,
       setFieldError: this.setFieldError,
-      setFieldValue: this.setFieldValue,
       setFieldTouched: this.setFieldTouched,
+      setFieldValue: this.setFieldValue,
+      setStatus: this.setStatus,
       setSubmitting: this.setSubmitting,
-      resetForm: this.resetForm,
+      setTouched: this.setTouched,
+      setValues: this.setValues,
       submitForm: this.submitForm,
     });
   };
@@ -582,20 +597,21 @@ Formik cannot determine which value to update. For more info see https://github.
         : isInitialValid !== false && isFunction(isInitialValid)
           ? (isInitialValid as (props: Props) => boolean)(this.props)
           : isInitialValid as boolean,
-      handleSubmit: this.handleSubmit,
-      handleChange: this.handleChange,
       handleBlur: this.handleBlur,
+      handleChange: this.handleChange,
       handleReset: this.handleReset,
-      setStatus: this.setStatus,
-      setTouched: this.setTouched,
-      setErrors: this.setErrors,
+      handleSubmit: this.handleSubmit,
+      initialValues: this.initialValues,
+      resetForm: this.resetForm,
       setError: this.setError,
-      setValues: this.setValues,
+      setErrors: this.setErrors,
       setFieldError: this.setFieldError,
-      setFieldValue: this.setFieldValue,
       setFieldTouched: this.setFieldTouched,
+      setFieldValue: this.setFieldValue,
+      setStatus: this.setStatus,
       setSubmitting: this.setSubmitting,
-      resetForm: this.resetForm,
+      setTouched: this.setTouched,
+      setValues: this.setValues,
       submitForm: this.submitForm,
     };
     return component
diff --git a/src/withFormik.tsx b/src/withFormik.tsx
index 1c572bb..c821cfb 100644
--- a/src/withFormik.tsx
+++ b/src/withFormik.tsx
@@ -22,7 +22,7 @@ export type InjectedFormikProps<Props, Values> = Props &
   FormikState<Values> &
   FormikActions<Values> &
   FormikHandlers &
-  FormikComputedProps;
+  FormikComputedProps<Values>;
 
 /**
  * Formik actions + { props }


Test patch:
diff --git a/test/formik.test.tsx b/test/formik.test.tsx
index b07d1a5..1fdd265 100644
--- a/test/formik.test.tsx
+++ b/test/formik.test.tsx
@@ -659,16 +659,21 @@ describe('Formik Next', () => {
   });
 
   describe('componentWillReceiveProps', () => {
-    let form, initialValues;
+    let form, defaultForm, initialValues;
     beforeEach(() => {
       initialValues = {
         name: 'formik',
         github: { repoUrl: 'https://github.com/jaredpalmer/formik' },
         watchers: ['ian', 'sam'],
       };
-      form = new Formik({ initialValues, onSubmit: jest.fn() });
+      form = new Formik({
+        initialValues,
+        onSubmit: jest.fn(),
+        enableReinitialize: true,
+      });
       form.resetForm = jest.fn();
     });
+
     it('should not resetForm if new initialValues are the same as previous', () => {
       const newInitialValues = Object.assign({}, initialValues);
       form.componentWillReceiveProps({
@@ -679,9 +684,10 @@ describe('Formik Next', () => {
     });
 
     it('should resetForm if new initialValues are different than previous', () => {
-      const newInitialValues = Object.assign({}, initialValues, {
+      const newInitialValues = {
+        ...initialValues,
         watchers: ['jared', 'ian', 'sam'],
-      });
+      };
       form.componentWillReceiveProps({
         initialValues: newInitialValues,
         onSubmit: jest.fn(),
@@ -690,14 +696,32 @@ describe('Formik Next', () => {
     });
 
     it('should resetForm if new initialValues are deeply different than previous', () => {
-      const newInitialValues = Object.assign({}, initialValues, {
+      const newInitialValues = {
+        ...initialValues,
         github: { repoUrl: 'different' },
-      });
+      };
       form.componentWillReceiveProps({
         initialValues: newInitialValues,
         onSubmit: jest.fn(),
       });
       expect(form.resetForm).toHaveBeenCalled();
     });
+
+    it('should NOT resetForm without enableReinitialize flag', () => {
+      form = new Formik({
+        initialValues,
+        onSubmit: jest.fn(),
+      });
+      form.resetForm = jest.fn();
+      const newInitialValues = {
+        ...initialValues,
+        watchers: ['jared', 'ian', 'sam'],
+      };
+      form.componentWillReceiveProps({
+        initialValues: newInitialValues,
+        onSubmit: jest.fn(),
+      });
+      expect(form.resetForm).not.toHaveBeenCalled();
+    });
   });
 });