From bae277a2674d50881641a925f0b2762cc37948e7 Mon Sep 17 00:00:00 2001 From: Erik Rasmussen Date: Thu, 12 Apr 2018 14:23:12 +0200 Subject: [PATCH] Added FormApi to Form and FormSpy props. Deprecated old. --- README.md | 44 +++++++++++++++-- package-lock.json | 40 +++++++++------ package.json | 8 +-- src/Field.js | 27 +++++++++-- src/Field.test.js | 10 ++-- src/FormSpy.js | 97 ++++++++++++++++++++++++++++++++++--- src/FormSpy.test.js | 71 +++++++++++++++++++++++++++ src/ReactFinalForm.js | 99 +++++++++++++++++++++++++++++++++----- src/ReactFinalForm.test.js | 62 ++++++++++++++++++++++-- src/index.d.ts | 5 +- src/types.js.flow | 8 ++- 11 files changed, 415 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 076c3fb0..153a51e1 100644 --- a/README.md +++ b/README.md @@ -649,38 +649,56 @@ as well as: #### `batch: (fn: () => void) => void)` +_**[DEPRECATED]** Use `form.batch()` instead_ + A function that allows batch updates to be done to the form state. [See the 🏁 Final Form docs on `batch`](https://github.com/final-form/final-form#batch-fn---void--void). #### `blur: (name: string) => void` +_**[DEPRECATED]** Use `form.blur()` instead_ + A function to blur (mark inactive) any field. #### `change: (name: string, value: any) => void` +_**[DEPRECATED]** Use `form.change()` instead_ + A function to change the value of any field. #### `focus: (name: string) => void` +_**[DEPRECATED]** Use `form.focus()` instead_ + A function to focus (mark active) any field. +#### `form: FormApi` + +The 🏁 Final Form [`FormApi`](https://github.com/final-form/final-form#formapi). + #### `handleSubmit: (?SyntheticEvent) => void` A function intended for you to give directly to the `
` tag: ``. #### `initialize: (values: Object) => void` +_**[DEPRECATED]** Use `form.initialize()` instead_ + A function that initializes the form values. [See the 🏁 Final Form docs on `initialize`](https://github.com/final-form/final-form#initialize-values-object--void). #### `mutators?: { [string]: Function }` +_**[DEPRECATED]** Use `form.mutators` instead_ + [See the 🏁 Final Form docs on `mutators`](https://github.com/final-form/final-form#mutators--string-function-). -#### `reset: () => void` +#### `reset: (newInitialValues?: Object) => void` + +_**[DEPRECATED]** Use `form.reset()` instead_ A function that resets the form values to their last initialized values. -[See the 🏁 Final Form docs on `reset`](https://github.com/final-form/final-form#reset---void). +[See the 🏁 Final Form docs on `reset`](https://github.com/final-form/final-form#reset-initialvalues-object--void). ### `FormSpyProps` @@ -734,34 +752,52 @@ subscribed to with the #### `batch: (fn: () => void) => void)` +_**[DEPRECATED]** Use `form.batch()` instead_ + A function that allows batch updates to be done to the form state. [See the 🏁 Final Form docs on `batch`](https://github.com/final-form/final-form#batch-fn---void--void). #### `blur: (name: string) => void` +_**[DEPRECATED]** Use `form.blur()` instead_ + A function to blur (mark inactive) any field. #### `change: (name: string, value: any) => void` +_**[DEPRECATED]** Use `form.change()` instead_ + A function to change the value of any field. #### `focus: (name: string) => void` +_**[DEPRECATED]** Use `form.focus()` instead_ + A function to focus (mark active) any field. +#### `form: FormApi` + +The 🏁 Final Form [`FormApi`](https://github.com/final-form/final-form#formapi). + #### `initialize: (values: Object) => void` +_**[DEPRECATED]** Use `form.initialize()` instead_ + A function that initializes the form values. [See the 🏁 Final Form docs on `initialize`](https://github.com/final-form/final-form#initialize-values-object--void). #### `mutators?: { [string]: Function }` +_**[DEPRECATED]** Use `form.mutators` instead_ + [See the 🏁 Final Form docs on `mutators`](https://github.com/final-form/final-form#mutators--string-function-). -#### `reset: () => void` +#### `reset: (newInitialValues?: Object) => void` + +_**[DEPRECATED]** Use `form.reset()` instead_ A function that resets the form values to their last initialized values. -[See the 🏁 Final Form docs on `reset`](https://github.com/final-form/final-form#reset---void). +[See the 🏁 Final Form docs on `reset`](https://github.com/final-form/final-form#reset-initialvalues-object--void). ## Contributors diff --git a/package-lock.json b/package-lock.json index 8920c554..1416e345 100644 --- a/package-lock.json +++ b/package-lock.json @@ -132,10 +132,10 @@ "dev": true }, "@types/react": { - "version": "16.3.8", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.3.8.tgz", + "version": "16.3.9", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.3.9.tgz", "integrity": - "sha512-2jiXVXqx/zxbKT9Dn10EVtD8Uwgna//3xpmDAMHnLKCwumpHvPziTqucAfzMCpFuFn3/xM28A3edzC6ykrm1Ug==", + "sha512-QtRjpa6iGquGr3sxCw7nnQpNHXfx/rE82SJjbvMEiu/oegZCxafd4QBO1cLzsrDCYwnGpAhTEOcFXQKMoeDBeQ==", "dev": true, "requires": { "csstype": "2.2.0" @@ -4022,13 +4022,12 @@ } }, "eslint-plugin-import": { - "version": "2.10.0", + "version": "2.11.0", "resolved": - "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.10.0.tgz", - "integrity": "sha1-+gkIPVp1KI35xsfQn+EiVZhWVec=", + "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz", + "integrity": "sha1-Fa7qN6Z0mdhI6OmBgG1GJ7VQOBY=", "dev": true, "requires": { - "builtin-modules": "1.1.1", "contains-path": "0.1.0", "debug": "2.6.9", "doctrine": "1.5.0", @@ -4037,7 +4036,8 @@ "has": "1.0.1", "lodash": "4.17.5", "minimatch": "3.0.4", - "read-pkg-up": "2.0.0" + "read-pkg-up": "2.0.0", + "resolve": "1.7.1" }, "dependencies": { "debug": { @@ -4107,6 +4107,16 @@ "read-pkg": "2.0.0" } }, + "resolve": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", + "integrity": + "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, "strip-bom": { "version": "3.0.0", "resolved": @@ -4506,11 +4516,11 @@ } }, "final-form": { - "version": "4.5.1", + "version": "4.5.2", "resolved": - "https://registry.npmjs.org/final-form/-/final-form-4.5.1.tgz", + "https://registry.npmjs.org/final-form/-/final-form-4.5.2.tgz", "integrity": - "sha512-WOOwtx12Mq3ixlVNqDVn9alVDh7NEn+CMMOLu31JasDaShEiP2oktkHS7wnuprM9c/AxtEVv2YC6FZQw/2aGYw==", + "sha512-fhHoRf43816Htq43YLkseqHRfq1Kc3rwMIqpDkaL+IFEyDRrkjqxC5MaMB/NzF9PrH2SEoUdOFwlYgObKBpZdw==", "dev": true }, "find-parent-dir": { @@ -10792,10 +10802,10 @@ "dev": true }, "prettier": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.11.1.tgz", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.12.0.tgz", "integrity": - "sha512-T/KD65Ot0PB97xTrG8afQ46x3oiVhnfGjGESSI9NWYcG92+OUPZKkwHqGWXH2t9jK1crnQjubECW0FuOth+hxw==", + "sha512-Wz0SMncgaglBzDcohH3ZIAi4nVpzOIEweFzCOmgVEoRSeO72b4dcKGfgxoRGVMaFlh1r7dlVaJ+f3CIHfeH6xg==", "dev": true }, "prettier-eslint": { @@ -10813,7 +10823,7 @@ "indent-string": "3.2.0", "lodash.merge": "4.6.1", "loglevel-colored-level-prefix": "1.0.0", - "prettier": "1.11.1", + "prettier": "1.12.0", "pretty-format": "22.4.0", "require-relative": "0.8.7", "typescript": "2.8.1", diff --git a/package.json b/package.json index 1e678a10..738a74d2 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "homepage": "https://github.com/final-form/react-final-form#readme", "devDependencies": { - "@types/react": "^16.3.8", + "@types/react": "^16.3.9", "babel-eslint": "^8.0.3", "babel-jest": "^22.4.3", "babel-plugin-external-helpers": "^6.22.0", @@ -41,10 +41,10 @@ "eslint-config-react-app": "^2.1.0", "eslint-plugin-babel": "^5.0.0", "eslint-plugin-flowtype": "^2.46.1", - "eslint-plugin-import": "^2.10.0", + "eslint-plugin-import": "^2.11.0", "eslint-plugin-jsx-a11y": "^6.0.2", "eslint-plugin-react": "^7.7.0", - "final-form": "^4.5.1", + "final-form": "^4.5.2", "flow-bin": "^0.69.0", "glow": "^1.2.2", "husky": "^0.14.3", @@ -53,7 +53,7 @@ "nps": "^5.9.0", "nps-utils": "^1.5.0", "opencollective": "^1.0.3", - "prettier": "^1.11.1", + "prettier": "^1.12.0", "prettier-eslint-cli": "^4.7.1", "prop-types": "^15.6.1", "react": "^16.3.1", diff --git a/src/Field.js b/src/Field.js index 02bf5f35..e2652f80 100644 --- a/src/Field.js +++ b/src/Field.js @@ -4,7 +4,11 @@ import PropTypes from 'prop-types' import { fieldSubscriptionItems } from 'final-form' import diffSubscription from './diffSubscription' import type { FieldSubscription, FieldState } from 'final-form' -import type { FieldProps as Props, ReactContext } from './types' +import type { + FieldProps as Props, + FieldRenderProps, + ReactContext +} from './types' import renderComponent from './renderComponent' import isReactNative from './isReactNative' import getValue from './getValue' @@ -160,8 +164,24 @@ export default class Field extends React.Component { value: _value, ...rest } = this.props - let { blur, change, focus, value, name: ignoreName, ...meta } = + let { blur, change, focus, value, name: ignoreName, ...otherState } = this.state.state || {} + const meta = { + // this is to appease the Flow gods + active: otherState.active, + dirty: otherState.dirty, + dirtySinceLastSubmit: otherState.dirtySinceLastSubmit, + error: otherState.error, + initial: otherState.initial, + invalid: otherState.invalid, + pristine: otherState.pristine, + submitError: otherState.submitError, + submitFailed: otherState.submitFailed, + submitSucceeded: otherState.submitSucceeded, + touched: otherState.touched, + valid: otherState.valid, + visited: otherState.visited + } if (format) { value = format(value, name) } @@ -191,8 +211,9 @@ export default class Field extends React.Component { // ignore meta, combine input with any other props return React.createElement(component, { ...input, children, ...rest }) } + const renderProps: FieldRenderProps = { input, meta } // assign to force Flow check return renderComponent( - { input, meta, children, component, ...rest }, + { ...renderProps, children, component, ...rest }, `Field(${name})` ) } diff --git a/src/Field.test.js b/src/Field.test.js index a6112ac3..e48e8849 100644 --- a/src/Field.test.js +++ b/src/Field.test.js @@ -422,7 +422,9 @@ describe('Field', () => { const requiredUppercase = value => !value ? 'Required' - : value.toUpperCase() === value ? undefined : 'Must be uppercase' + : value.toUpperCase() === value + ? undefined + : 'Must be uppercase' class FieldsContainer extends React.Component { state = { uppercase: false } @@ -454,7 +456,9 @@ describe('Field', () => { expect(input).toHaveBeenCalledTimes(2) expect(input.mock.calls[1][0].meta.error).toBe('Required') - const { input: { onChange } } = input.mock.calls[1][0] + const { + input: { onChange } + } = input.mock.calls[1][0] onChange('hi') @@ -584,7 +588,7 @@ describe('Field', () => { expect(barInput.checked).toBe(true) expect(bazInput.checked).toBe(false) - render.mock.calls[0][0].change('foo', 'Baz') + render.mock.calls[0][0].form.change('foo', 'Baz') expect(barInput.checked).toBe(false) expect(bazInput.checked).toBe(true) diff --git a/src/FormSpy.js b/src/FormSpy.js index 94402d9e..d577427e 100644 --- a/src/FormSpy.js +++ b/src/FormSpy.js @@ -4,7 +4,11 @@ import PropTypes from 'prop-types' import { formSubscriptionItems } from 'final-form' import diffSubscription from './diffSubscription' import renderComponent from './renderComponent' -import type { FormSpyProps as Props, ReactContext } from './types' +import type { + FormSpyProps as Props, + FormSpyRenderProps, + ReactContext +} from './types' import type { FormState } from 'final-form' import { all } from './ReactFinalForm' @@ -86,19 +90,96 @@ export default class FormSpy extends React.Component { render() { const { onChange, subscription, ...rest } = this.props const { reactFinalForm } = this.context + const renderProps: FormSpyRenderProps = { + batch: + reactFinalForm && + ((fn: () => void) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.batch() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.batch() instead. Check your FormSpy render prop.` + ) + } + return reactFinalForm.batch(fn) + }), + blur: + reactFinalForm && + ((name: string) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.blur() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.blur() instead. Check your FormSpy render prop.` + ) + } + return reactFinalForm.blur(name) + }), + change: + reactFinalForm && + ((name: string, value: any) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.change() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.change() instead. Check your FormSpy render prop.` + ) + } + return reactFinalForm.change(name, value) + }), + focus: + reactFinalForm && + ((name: string) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.focus() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.focus() instead. Check your FormSpy render prop.` + ) + } + return reactFinalForm.focus(name) + }), + form: reactFinalForm, + initialize: + reactFinalForm && + ((values: Object) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.initialize() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.initialize() instead. Check your FormSpy render prop.` + ) + } + return reactFinalForm.initialize(values) + }), + mutators: + reactFinalForm && + Object.keys(reactFinalForm.mutators).reduce((result, key) => { + result[key] = (...args) => { + reactFinalForm.mutators[key](...args) + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.mutators is deprecated and will be removed in the next major version of React Final Form. Use: props.form.mutators instead. Check your FormSpy render prop.` + ) + } + } + return result + }, {}), + reset: + reactFinalForm && + ((values?: Object) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.reset() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.reset() instead. Check your FormSpy render prop.` + ) + } + return reactFinalForm.reset(values) + }) + } return onChange ? null : renderComponent( { ...rest, ...(this.state ? this.state.state : {}), - mutators: reactFinalForm && reactFinalForm.mutators, - batch: reactFinalForm && reactFinalForm.batch, - blur: reactFinalForm && reactFinalForm.blur, - change: reactFinalForm && reactFinalForm.change, - focus: reactFinalForm && reactFinalForm.focus, - initialize: reactFinalForm && reactFinalForm.initialize, - reset: reactFinalForm && reactFinalForm.reset + ...renderProps }, 'FormSpy' ) diff --git a/src/FormSpy.test.js b/src/FormSpy.test.js index cb30fdf1..87c540d8 100644 --- a/src/FormSpy.test.js +++ b/src/FormSpy.test.js @@ -344,4 +344,75 @@ describe('FormSpy', () => { expect(onChange).toHaveBeenCalledTimes(1) expect(render).not.toHaveBeenCalled() }) + + const deprecatedFns = { + // map from name to args + batch: [() => {}], + blur: ['foo'], + change: ['foo', 'bar'], + focus: [], + initialize: [{ foo: 'bar' }], + reset: [] + } + + Object.keys(deprecatedFns).forEach(key => { + it(`should warn if deprecated function props.${key}() is called`, async () => { + const spy = jest + .spyOn(global.console, 'error') + .mockImplementation(() => {}) + const dom = TestUtils.renderIntoDocument( + + {() => ( + + {props => ( + + )} + + )} + + ) + const button = TestUtils.findRenderedDOMComponentWithTag(dom, 'button') + TestUtils.Simulate.click(button) + spy.mockRestore() + }) + }) + + it(`should warn if deprecated function props.mutators.whatever() is called`, async () => { + const spy = jest.spyOn(global.console, 'error').mockImplementation(() => {}) + const mutator = jest.fn() + TestUtils.renderIntoDocument( +
+ {() => ( + + {props => { + expect(spy).not.toHaveBeenCalled() + expect(mutator).not.toHaveBeenCalled() + props.mutators.whatever() + expect(mutator).toHaveBeenCalled() + expect(mutator).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalled() + expect(spy).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalledWith( + `Warning: As of React Final Form v3.3.0, props.mutators is deprecated and will be removed in the next major version of React Final Form. Use: props.form.mutators instead. Check your FormSpy render prop.` + ) + return
+ }} + + )} + + ) + spy.mockRestore() + }) }) diff --git a/src/ReactFinalForm.js b/src/ReactFinalForm.js index a474471f..761deddb 100644 --- a/src/ReactFinalForm.js +++ b/src/ReactFinalForm.js @@ -16,6 +16,7 @@ import type { import type { FormProps as Props, ReactContext } from './types' import shallowEqual from './shallowEqual' import renderComponent from './renderComponent' +import type { FormRenderProps } from './types.js.flow' export const version = '3.2.1' const versions = { @@ -47,8 +48,6 @@ export default class ReactFinalForm extends React.Component { reactFinalForm: PropTypes.object } - static displayName = `ReactFinalForm(${ffVersion})(${version})` - constructor(props: Props) { super(props) const { @@ -179,18 +178,96 @@ export default class ReactFinalForm extends React.Component { validateOnBlur, ...props } = this.props + const renderProps: FormRenderProps = { + // assign to force Flow check + ...(this.state ? this.state.state : {}), + batch: + this.form && + ((fn: () => void) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.batch() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.batch() instead. Check your ReactFinalForm render prop.` + ) + } + return this.form.batch(fn) + }), + blur: + this.form && + ((name: string) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.blur() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.blur() instead. Check your ReactFinalForm render prop.` + ) + } + return this.form.blur(name) + }), + change: + this.form && + ((name: string, value: any) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.change() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.change() instead. Check your ReactFinalForm render prop.` + ) + } + return this.form.change(name, value) + }), + focus: + this.form && + ((name: string) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.focus() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.focus() instead. Check your ReactFinalForm render prop.` + ) + } + return this.form.focus(name) + }), + form: this.form, + handleSubmit: this.handleSubmit, + initialize: + this.form && + ((values: Object) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.initialize() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.initialize() instead. Check your ReactFinalForm render prop.` + ) + } + return this.form.initialize(values) + }), + mutators: + this.form && + Object.keys(this.form.mutators).reduce((result, key) => { + result[key] = (...args) => { + this.form.mutators[key](...args) + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.mutators is deprecated and will be removed in the next major version of React Final Form. Use: props.form.mutators instead. Check your ReactFinalForm render prop.` + ) + } + } + return result + }, {}), + reset: + this.form && + ((values?: Object) => { + // istanbul ignore next + if (process.env.NODE_ENV !== 'production') { + console.error( + `Warning: As of React Final Form v3.3.0, props.reset() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.reset() instead. Check your ReactFinalForm render prop.` + ) + } + return this.form.reset(values) + }) + } return renderComponent( { ...props, - ...(this.state ? this.state.state : {}), - mutators: this.form && this.form.mutators, - batch: this.form && this.form.batch, - blur: this.form && this.form.blur, - change: this.form && this.form.change, - focus: this.form && this.form.focus, - handleSubmit: this.handleSubmit, - initialize: this.form && this.form.initialize, - reset: this.form && this.form.reset, + ...renderProps, __versions: versions }, 'ReactFinalForm' diff --git a/src/ReactFinalForm.test.js b/src/ReactFinalForm.test.js index f876b72b..1c012ab3 100644 --- a/src/ReactFinalForm.test.js +++ b/src/ReactFinalForm.test.js @@ -383,6 +383,62 @@ describe('ReactFinalForm', () => { spy.mockRestore() }) + const deprecatedFns = { + // map from name to args + batch: [() => {}], + blur: ['foo'], + change: ['foo', 'bar'], + focus: [], + initialize: [{ foo: 'bar' }], + reset: [] + } + + Object.keys(deprecatedFns).forEach(key => { + it(`should warn if deprecated function props.${key}() is called`, async () => { + const spy = jest + .spyOn(global.console, 'error') + .mockImplementation(() => {}) + TestUtils.renderIntoDocument( +
+ {props => { + expect(spy).not.toHaveBeenCalled() + props[key](...deprecatedFns[key]) + expect(spy).toHaveBeenCalled() + expect(spy).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalledWith( + `Warning: As of React Final Form v3.3.0, props.${key}() is deprecated and will be removed in the next major version of React Final Form. Use: props.form.${key}() instead. Check your ReactFinalForm render prop.` + ) + return
+ }} + + ) + spy.mockRestore() + }) + }) + + it(`should warn if deprecated function props.mutators.whatever() is called`, async () => { + const spy = jest.spyOn(global.console, 'error').mockImplementation(() => {}) + const mutator = jest.fn() + TestUtils.renderIntoDocument( +
+ {props => { + expect(spy).not.toHaveBeenCalled() + expect(mutator).not.toHaveBeenCalled() + props.mutators.whatever() + expect(mutator).toHaveBeenCalled() + expect(mutator).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalled() + expect(spy).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalledWith( + `Warning: As of React Final Form v3.3.0, props.mutators is deprecated and will be removed in the next major version of React Final Form. Use: props.form.mutators instead. Check your ReactFinalForm render prop.` + ) + return
+ }} + + ) + spy.mockRestore() + }) + it('should return a promise from handleSubmit when submission is async', async () => { const onSubmit = jest.fn() let promise @@ -527,11 +583,7 @@ describe('ReactFinalForm', () => { {({ invalid }) => { render(invalid) return ( - (value ? undefined : 'Required')} - /> + 'Required'} /> ) }} diff --git a/src/index.d.ts b/src/index.d.ts index d223c6d4..f12e77e4 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -51,10 +51,13 @@ export interface SubsetFormApi { export interface FormRenderProps extends FormState, SubsetFormApi { batch: (fn: () => void) => void + form: FormApi handleSubmit: (event?: React.SyntheticEvent) => void } -export interface FormSpyRenderProps extends FormState, SubsetFormApi {} +export interface FormSpyRenderProps extends FormState, SubsetFormApi { + form: FormApi +} export interface RenderableProps { children?: ((props: T) => React.ReactNode) | React.ReactNode diff --git a/src/types.js.flow b/src/types.js.flow index d3df45cf..f1947631 100644 --- a/src/types.js.flow +++ b/src/types.js.flow @@ -53,11 +53,15 @@ export type SubsetFormApi = { } & FormState export type FormRenderProps = { - handleSubmit: (SyntheticEvent) => void + handleSubmit: (SyntheticEvent) => ?Promise, + form: FormApi } & FormState & SubsetFormApi -export type FormSpyRenderProps = SubsetFormApi & FormState +export type FormSpyRenderProps = { + form: FormApi +} & SubsetFormApi & + FormState export type RenderableProps = { children?: ((props: T) => React.Node) | React.Node,