UNPKG

@piscium2010/v-form

Version:

This is not a form, instead it is only a form shell of which the single responsibility is validating and providing error messages. Capable of definding flexiable rules and validating multi fields at a time.

168 lines (145 loc) 6.19 kB
import React, { useState } from 'react' import { render, fireEvent } from '@testing-library/react' import TestRenderer from 'react-test-renderer' import VForm, { v } from '../dist' const Field = VForm.fieldFactory(({ name, message, children }) => { return ( <section> {children} <div>{message}</div> </section> ) }) const validation = v.create({ email: v.expect('email is required').expect('Should be email', c => v.isEmail(c.email)), marriage: [ v.expect('marriage is required').expect('Should be single or married', c => ['single', 'married'].includes(c.marriage)), v.when('marriage', c => c.marriage === 'single').validate('marriage_date') ], marriage_date: v.when('marriage', c => c.marriage === 'married').expect('Required when married') }) function Form(props) { const [messages, setMessages] = useState({}) const [values, setValues] = useState({ email: '', marriage: '', birth_date: new Date() }) const update = value => { const result = validation.test(value, values) setMessages({ ...messages, ...result.messages }) setValues({ ...values, ...value }) } const onSubmit = () => { const result = validation.testAllRules(values) setMessages({ ...messages, ...result.messages }) } return ( <div> <VForm messages={messages}> <Field name='email'> <label htmlFor="email">email</label> <input id="email" onChange={evt => update({ email: evt.target.value })} /> </Field> <Field name='marriage'> <label htmlFor="marriage">marriage</label> <input id="marriage" onChange={evt => update({ marriage: evt.target.value })} /> </Field> <Field name='marriage_date'> <label htmlFor="marriage_date">marriage_date</label> <input id='marriage_date' onChange={evt => update({ marriage_date: evt.target.value })} /> </Field> <button onClick={onSubmit}>Submit</button> </VForm> </div> ) } function FormII(props) { const [values, setValues] = useState({ email: '', marriage: '', birth_date: new Date() }) const update = value => { validation.test(value, values) setValues({ ...values, ...value }) } const onSubmit = () => { validation.testAllRules(values) } return ( <div> <VForm validation={validation} {...props}> <Field name='email'> <label htmlFor="email">email</label> <input id="email" onChange={evt => update({ email: evt.target.value })} /> </Field> <Field name='marriage'> <label htmlFor="marriage">marriage</label> <input id="marriage" onChange={evt => update({ marriage: evt.target.value })} /> </Field> <Field name='marriage_date'> <label htmlFor="marriage_date">marriage_date</label> <input id='marriage_date' onChange={evt => update({ marriage_date: evt.target.value })} /> </Field> <button onClick={onSubmit}>Submit</button> </VForm> </div> ) } test('basic', () => { const { queryByText, getByText } = render(<Form />) fireEvent.click(getByText(/submit/i)) expect(queryByText('email is required')).toBeTruthy() expect(queryByText('marriage is required')).toBeTruthy() expect(queryByText('Required when married')).toBeNull() }) test('Should be email', () => { const { queryByText, getByText, getByLabelText } = render(<Form />) fireEvent.change(getByLabelText(/email/i), { target: { value: '2' } }) expect(queryByText('Should be email')).toBeTruthy() fireEvent.change(getByLabelText(/email/i), { target: { value: '2@2.com' } }) expect(queryByText('Should be email')).toBeNull() }) test('Should be single or married', () => { const { queryByText, getByText, getByLabelText } = render(<Form />) fireEvent.change(getByLabelText('marriage'), { target: { value: '2' } }) expect(queryByText('Should be single or married')).toBeTruthy() fireEvent.change(getByLabelText('marriage'), { target: { value: 'single' } }) expect(queryByText('Should be single or married')).toBeNull() }) test('Required when married', () => { const { queryByText, getByText, getByLabelText } = render(<Form />) fireEvent.change(getByLabelText('marriage'), { target: { value: 'married' } }) fireEvent.click(getByText(/submit/i)) expect(queryByText('Required when married')).toBeTruthy() fireEvent.change(getByLabelText('marriage'), { target: { value: 'single' } }) expect(queryByText('Required when married')).toBeNull() }) test('default messages', () => { const { queryByText, getByText, getByLabelText } = render( <FormII defaultMessages={{ email: 'abcd' }} /> ) expect(queryByText(/abcd/i)).toBeTruthy() fireEvent.click(getByText(/submit/i)) expect(queryByText('email is required')).toBeNull() }) test('messages', () => { const { queryByText, getByText, getByLabelText } = render( <FormII messages={{ email: 'abcd' }} /> ) expect(queryByText(/abcd/i)).toBeTruthy() fireEvent.click(getByText(/submit/i)) expect(queryByText(/abcd/i)).toBeTruthy() }) test('should wrap field components under <VForm/>', () => { const msg = 'Please wrap field components under component VForm' const ins = TestRenderer.create( <TestingError> <Field name='email'></Field> </TestingError> ) const errorMsg = ins.root.findByProps({className:'er'}).children[0] expect(errorMsg).toBe(msg) }) class TestingError extends React.Component { static getDerivedStateFromError(error) { return { hasError: true, error } } state = { hasError: false } render() { return this.state.hasError ? <label className='er'>{this.state.error}</label> : this.props.children } }