Skip to content

Commit

Permalink
Handle changes to Field validate/warn props (#3094)
Browse files Browse the repository at this point in the history
This will ensure that changes to these functions are reflected in form
validation. Achieved by re-registing the Field with reduxForm when new
validate or warn props are recieved.

See issue: #3012
  • Loading branch information
dmanningnz authored and erikras committed Jun 29, 2017
1 parent 28ed482 commit 0b578c7
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 2 deletions.
95 changes: 95 additions & 0 deletions src/__tests__/Field.spec.js
Expand Up @@ -1800,6 +1800,54 @@ const describeField = (name, structure, combineReducers, expect) => {
expect(usernameInput.calls[2].arguments[0].meta.error).toBe(undefined)
})

it('should update field level validation when validate prop changes', () => {
const store = makeStore()
const usernameInput = createSpy(props => (
<input {...props.input} />
)).andCallThrough()
const required = createSpy(
value => (value == null ? 'Required' : undefined)
).andCallThrough()
class Form extends Component {
constructor() {
super()
this.state = { validate: undefined }
}

render() {
return (
<div>
<Field
name="username"
component={usernameInput}
validate={this.state.validate}
/>
<button onClick={() => this.setState({ validate: required })}>Change</button>
</div>
)
}
}
const TestForm = reduxForm({
form: 'testForm'
})(Form)
const dom = TestUtils.renderIntoDocument(
<Provider store={store}>
<TestForm />
</Provider>
)

// username field is ok
expect(usernameInput.calls[usernameInput.calls.length - 1].arguments[0].meta.valid).toBe(true)

// update validate prop
const button = TestUtils.findRenderedDOMComponentWithTag(dom, 'button')
TestUtils.Simulate.click(button)

// should be invalid now
expect(usernameInput.calls[usernameInput.calls.length - 1].arguments[0].meta.valid).toBe(false)
expect(usernameInput.calls[usernameInput.calls.length - 1].arguments[0].meta.error).toBe('Required')
});

it('should sync warn with field level warning function', () => {
const store = makeStore()
const usernameInput = createSpy(props => (
Expand Down Expand Up @@ -1853,6 +1901,53 @@ const describeField = (name, structure, combineReducers, expect) => {
expect(usernameInput.calls[2].arguments[0].meta.warning).toBe(undefined)
})

it('should update field level warning when warn prop changes', () => {
const store = makeStore()
const usernameInput = createSpy(props => (
<input {...props.input} />
)).andCallThrough()
const required = createSpy(
value => (value == null ? 'Required' : undefined)
).andCallThrough()
class Form extends Component {
constructor() {
super()
this.state = { warn: undefined }
}

render() {
return (
<div>
<Field
name="username"
component={usernameInput}
warn={this.state.warn}
/>
<button onClick={() => this.setState({ warn: required })}>Change</button>
</div>
)
}
}
const TestForm = reduxForm({
form: 'testForm'
})(Form)
const dom = TestUtils.renderIntoDocument(
<Provider store={store}>
<TestForm />
</Provider>
)

// username field is ok
expect(usernameInput.calls[usernameInput.calls.length - 1].arguments[0].meta.warning).toBe(undefined)

// update warn prop
const button = TestUtils.findRenderedDOMComponentWithTag(dom, 'button')
TestUtils.Simulate.click(button)

// should have warning now
expect(usernameInput.calls[usernameInput.calls.length - 1].arguments[0].meta.warning).toBe('Required')
});

it('should not generate any warnings by passing api props into custom', () => {
const store = makeStore()
const renderSpy = createSpy()
Expand Down
10 changes: 8 additions & 2 deletions src/createField.js
Expand Up @@ -38,13 +38,19 @@ const createField = ({ deepEqual, getIn, setIn, toJS }) => {
}

componentWillReceiveProps(nextProps) {
if (this.props.name !== nextProps.name) {
if (
this.props.name !== nextProps.name ||
this.props.validate !== nextProps.validate ||
this.props.warn !== nextProps.warn
) {
// unregister old name
this.context._reduxForm.unregister(this.name)
// register new name
this.context._reduxForm.register(
prefixName(this.context, nextProps.name),
'Field'
'Field',
() => nextProps.validate,
() => nextProps.warn
)
}
}
Expand Down

0 comments on commit 0b578c7

Please sign in to comment.