Skip to content

Commit

Permalink
Fix typing on Validation spec
Browse files Browse the repository at this point in the history
  • Loading branch information
rkuykendall committed Feb 8, 2020
1 parent a6b1833 commit 70750a4
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 73 deletions.
111 changes: 48 additions & 63 deletions __tests__/Validation-spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,32 @@ import sinon from 'sinon';
import { mount } from 'enzyme';

import Formsy, { withFormsy } from '../src';
import { InputFactory } from '../__test_utils__/TestInput';
import immediate from '../__test_utils__/immediate';
import { InputFactory } from '../__test_utils__/TestInput';
import { WrapperInstanceMethods, PassDownProps } from '../src/Wrapper';

class MyTest extends React.Component {
static defaultProps = { type: 'text' };
class MyTest extends React.Component<{ type?: string } & PassDownProps<string>> {
public static defaultProps = { type: 'text' };

handleChange = event => {
this.props.setValue(event.target.value);
const { setValue } = this.props;
setValue(event.target.value);
};

render() {
return <input type={this.props.type} value={this.props.value || ''} onChange={this.handleChange} />;
const { type, value } = this.props;
return <input type={type} value={value || ''} onChange={this.handleChange} />;
}
}
const FormsyTest = withFormsy(MyTest);
const FormsyTest = withFormsy<{ type?: string }, string>(MyTest);

function getInputInstance(inputComponent) {
return inputComponent.instance() as WrapperInstanceMethods;
}

function getFormInstance(formComponent) {
return formComponent.instance() as Formsy;
}

describe('Validation', () => {
it('should reset only changed form element when external error is passed', () => {
Expand All @@ -31,34 +42,14 @@ describe('Validation', () => {
const input = form.find('input').at(0);
const inputComponents = form.find(FormsyTest);

form.instance().submit();
expect(
inputComponents
.at(0)
.instance()
.isValid(),
).toEqual(false);
expect(
inputComponents
.at(1)
.instance()
.isValid(),
).toEqual(false);
getFormInstance(form).submit();
expect(getInputInstance(inputComponents.at(0)).isValid()).toEqual(false);
expect(getInputInstance(inputComponents.at(1)).isValid()).toEqual(false);

input.simulate('change', { target: { value: 'bar' } });
immediate(() => {
expect(
inputComponents
.at(0)
.instance()
.isValid(),
).toEqual(true);
expect(
inputComponents
.at(1)
.instance()
.isValid(),
).toEqual(false);
expect(getInputInstance(inputComponents.at(0)).isValid()).toEqual(true);
expect(getInputInstance(inputComponents).isValid()).toEqual(false);
});
});

Expand All @@ -72,13 +63,13 @@ describe('Validation', () => {
const input = form.find('input');
const inputComponent = form.find(FormsyTest);

form.instance().submit();
expect(inputComponent.instance().isValid()).toEqual(false);
getFormInstance(form).submit();
expect(getInputInstance(inputComponent).isValid()).toEqual(false);

input.simulate('change', { target: { value: 'bar' } });
immediate(() => {
expect(inputComponent.getValue()).toEqual('bar');
expect(inputComponent.instance().isValid()).toEqual(false);
expect(getInputInstance(inputComponent).getValue()).toEqual('bar');
expect(getInputInstance(inputComponent).isValid()).toEqual(false);
});
});

Expand Down Expand Up @@ -141,58 +132,52 @@ describe('Validation', () => {
});

it('should provide invalidate callback on onValidSubmit', () => {
class TestForm extends React.Component {
render() {
return (
<Formsy onValidSubmit={(model, reset, invalidate) => invalidate({ foo: 'bar' })}>
<FormsyTest name="foo" value="foo" />
</Formsy>
);
}
function TestForm() {
return (
<Formsy onValidSubmit={(model, reset, invalidate) => invalidate({ foo: 'bar' })}>
<FormsyTest name="foo" value="foo" />
</Formsy>
);
}

const form = mount(<TestForm />);

const formEl = form.find('form');
const input = form.find(FormsyTest);
formEl.simulate('submit');
expect(input.instance().isValid()).toEqual(false);
expect(getInputInstance(input).isValid()).toEqual(false);
});

it('should provide invalidate callback on onInvalidSubmit', () => {
class TestForm extends React.Component {
render() {
return (
<Formsy onInvalidSubmit={(model, reset, invalidate) => invalidate({ foo: 'bar' })}>
<FormsyTest name="foo" value="foo" validations="isEmail" />
</Formsy>
);
}
function TestForm() {
return (
<Formsy onInvalidSubmit={(model, reset, invalidate) => invalidate({ foo: 'bar' })}>
<FormsyTest name="foo" value="foo" validations="isEmail" />
</Formsy>
);
}

const form = mount(<TestForm />);
const formEl = form.find('form');
const input = form.find(FormsyTest);
formEl.simulate('submit');
expect(input.instance().getErrorMessage()).toEqual('bar');
expect(getInputInstance(input).getErrorMessage()).toEqual('bar');
});

it('should not invalidate inputs on external errors with preventExternalInvalidation prop', () => {
class TestForm extends React.Component {
render() {
return (
<Formsy preventExternalInvalidation onSubmit={(model, reset, invalidate) => invalidate({ foo: 'bar' })}>
<FormsyTest name="foo" value="foo" />
</Formsy>
);
}
function TestForm() {
return (
<Formsy preventExternalInvalidation onSubmit={(model, reset, invalidate) => invalidate({ foo: 'bar' })}>
<FormsyTest name="foo" value="foo" />
</Formsy>
);
}

const form = mount(<TestForm />);
const formEl = form.find('form');
const input = form.find(FormsyTest);
formEl.simulate('submit');
expect(input.instance().isValid()).toEqual(true);
expect(getInputInstance(input).isValid()).toEqual(true);
});

it('should invalidate inputs on external errors without preventExternalInvalidation prop', () => {
Expand All @@ -210,6 +195,6 @@ describe('Validation', () => {
const formEl = form.find('form');
const input = form.find(FormsyTest);
formEl.simulate('submit');
expect(input.instance().isValid()).toEqual(false);
expect(getInputInstance(input).isValid()).toEqual(false);
});
});
20 changes: 11 additions & 9 deletions src/Wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@ import { RequiredValidation, Validations, WrappedComponentClass } from './interf
const convertValidationsToObject = <V>(validations: false | Validations<V>): Validations<V> => {
if (typeof validations === 'string') {
return validations.split(/,(?![^{[]*[}\]])/g).reduce((validationsAccumulator, validation) => {
let args = validation.split(':');
const validateMethod = args.shift();

if (typeof validateMethod !== 'string') {
throw new Error('Formsy encountered unexpected problem parsing validation string');
}
let args: string[] = validation.split(':');
const validateMethod: string = args.shift();

args = args.map(arg => {
try {
Expand Down Expand Up @@ -88,6 +84,12 @@ export interface InjectedProps<V> {
showRequired: boolean;
}

export interface WrapperInstanceMethods {
isValid: () => boolean;
getValue: () => any;
getErrorMessage: () => any;
}

export type PassDownProps<V> = WrapperProps<V> & InjectedProps<V>;

export { propTypes };
Expand All @@ -103,7 +105,7 @@ function getDisplayName(component: WrappedComponentClass) {
export default function<T, V>(
WrappedComponent: React.ComponentType<T & PassDownProps<V>>,
): React.ComponentType<Omit<T & WrapperProps<V>, keyof InjectedProps<V>>> {
return class extends React.Component<T & WrapperProps<V>, WrapperState<V>> {
return class extends React.Component<T & WrapperProps<V>, WrapperState<V>> implements WrapperInstanceMethods {
public validations?: Validations<V>;

public requiredValidations?: Validations<V>;
Expand Down Expand Up @@ -287,7 +289,7 @@ export default function<T, V>(

public render() {
const { innerRef } = this.props;
const propsForElement: PassDownProps<V> = {
const propsForElement: T & PassDownProps<V> = {
...this.props,
errorMessage: this.getErrorMessage(),
errorMessages: this.getErrorMessages(),
Expand All @@ -310,7 +312,7 @@ export default function<T, V>(
propsForElement.ref = innerRef;
}

return React.createElement(WrappedComponent, propsForElement as any);
return React.createElement(WrappedComponent, propsForElement);
}
};
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ class Formsy extends React.Component<FormsyProps, FormsyState> {
public isChanged = () => !utils.isSame(this.getPristineValues(), this.getCurrentValues());

// Update model, submit to url prop and send the model
public submit = event => {
public submit = (event?: any) => {
const { onSubmit, onValidSubmit, onInvalidSubmit } = this.props;
const { isValid } = this.state;

Expand Down

0 comments on commit 70750a4

Please sign in to comment.