Skip to content

Instantly share code, notes, and snippets.

@brunoguerra
Last active August 17, 2018 18:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brunoguerra/967fb53b40e1fadb9cf20066a844983a to your computer and use it in GitHub Desktop.
Save brunoguerra/967fb53b40e1fadb9cf20066a844983a to your computer and use it in GitHub Desktop.
import React from 'react'
import FormValidate, { ErrorComponent, identity, ruleValidate, validator } from '../Form_HOC'
import { mount } from 'enzyme'
import { withHandlers } from 'recompose'
import { Stateful } from 'react-mock'
describe('FormValidate', () => {
let Form
let wrapper
let stateful
let onChange
beforeEach(() => {
Form = FormValidate({
form: {
name: 'Bruno',
}
}, {
name: [{ rule: identity, message: 'Name must be provided' }]
})( Stateful )
wrapper = mount(<Form />)
stateful = wrapper.find(Stateful)
onChange = stateful.prop('onChange')
})
const formState = () => stateful.prop('form')
const errorsState = () => stateful.prop('errors')
it('Change input fields', () => {
expect(formState().name).toBe('Bruno')
onChange('name')('John')
expect(formState().name).toBe('John')
})
it('rule evaluation', () => {
const rule = { rule: (val) => val && val.length > 2, message: 'Name must have at least 3 characters' }
const value = '12'
const error = ruleValidate(value)(rule)
expect(error).toBe(rule.message)
})
it('validationRules', () => {
const validationRules = {
name: [
{ rule: identity, message: 'Name must be provided' },
{ rule: (val) => val && val.length > 2, message: 'Name must have at least 3 characters' }
]
}
const validate = validator(validationRules)
const name = 'name'
const value = '12'
const errors = validate({ name, value })
expect( errors.length ).toBe(1)
expect( errors[0] ).toBe( validationRules.name[1].message )
})
it('Expect validation error', () => {
onChange('name')('')
expect( formState().name).toBe('')
expect( errorsState().name).toBeDefined()
console.log( errorsState().name )
expect( errorsState().name.props.errors ).toBeDefined()
expect( errorsState().name.props.errors[0] ).toBe('Name must be provided')
expect( errorsState().name.type ).toBe(ErrorComponent)
})
})
// Version of https://medium.com/javascript-inside/form-validation-as-a-higher-order-component-pt-2-1edb7881870d#.v8qtw3b8v
import React, { PropTypes } from 'react'
import { compose, withState, mapProps } from 'recompose'
export const ErrorComponent = ({ errors }) => (
<ul className='form-errors'>
{ errors.map( ( error, index ) => (
<li className='form-errors-item' key={ index }>{ error }</li>
) ) }
</ul>
)
ErrorComponent.propTypes = {
errors: PropTypes.array.isRequired,
}
export const getValue = (fw) => (e) => fw(e.target.value)
export const identity = (it) => it
export const notNull = ( arr ) => arr.filter(identity)
export const ruleValidate = ( value ) => ({ rule, message }) => rule(value)? null : message
export const validator = ( validationRules ) => ({ name, value }) =>
validationRules[name]? notNull(validationRules[name].map(ruleValidate(value))) : null
const getError = ( errors ) => errors.length>0? <ErrorComponent errors={ errors } /> : null
const FormValidate = ( initialState, validationRules = {} ) => {
const validate = validator(validationRules)
return compose(
withState('state', 'updateState', { ...initialState, errors: {} }),
mapProps( ({ updateState, state, ...rest }) => ({
onChange: ( name ) => ( value ) =>
updateState( ( state ) => {
const errors = getError( validate({ name, value }) )
return {
...state,
form: { ...state.form, [name]: value },
errors: { ...state.errors, [name]: errors },
}
} ),
form: state.form,
errors: state.errors,
...rest,
}) ),
)
}
export default FormValidate
import Helmet from 'react-helmet';
import React from 'react';
import Relay from 'react-relay';
import { FormArea, TextField } from '../webapp'
import { FormValidate, identity, getValue } from '../webapp/components/Form_HOC'
export const Author = ( props ) => {
const { Viewer: { author } } = props
const Form = FormValidate( { form: author }, {
description: [{ rule: identity, message: 'Description must be provided' }]
} )( AuthorForm )
return (
<Form {...props} />
)
}
export const AuthorForm = ({ form, onChange, Viewer: { author }, errors = {} }) => (
<FormArea>
<Helmet
title={ author.description }
meta={ [
{ name: 'description', content: author.description },
] }
/>
<TextField name='description' value={ form.description } onChange={ getValue( onChange('description') ) } />
{ errors.description }
{ '[...]' }
</FormArea>
)
export default Relay.createContainer( Author, {
initialVariables:
{
id: null,
},
prepareVariables( { id } )
{
return { id };
},
fragments: {
Viewer: () => Relay.QL`
fragment on Viewer {
author( id: $id ){
id,
description,
type,
}
}
`,
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment