import React from 'react'; import TestUtils from 'react-addons-test-utils'; import Formsy from './..'; import TestInput from './utils/TestInput'; import immediate from './utils/immediate'; describe('Formsy', function () { describe('Setting up a form', function () { it('should render a form into the document', function () { const form = TestUtils.renderIntoDocument(); expect(React.findDOMNode(form).tagName).toEqual('FORM'); }); it('should set a class name if passed', function () { const form = TestUtils.renderIntoDocument( ); expect(React.findDOMNode(form).className).toEqual('foo'); }); it('should allow for null/undefined children', function (done) { let model = null; const TestForm = React.createClass({ render() { return ( (model = formModel)}>

Test

{ null } { undefined }
); } }); const form = TestUtils.renderIntoDocument(); immediate(() => { TestUtils.Simulate.submit(React.findDOMNode(form)); expect(model).toEqual({name: 'foo'}); done(); }); }); it('should allow for inputs being added dynamically', function (done) { const inputs = []; let forceUpdate = null; let model = null; const TestForm = React.createClass({ componentWillMount() { forceUpdate = this.forceUpdate.bind(this); }, render() { return ( (model = formModel)}> {inputs} ); } }); const form = TestUtils.renderIntoDocument(); // Wait before adding the input setTimeout(() => { inputs.push(); forceUpdate(() => { // Wait for next event loop, as that does the form immediate(() => { TestUtils.Simulate.submit(React.findDOMNode(form)); expect(model.test).toBeDefined(); done(); }); }); }, 10); }); it('should allow dynamically added inputs to update the form-model', function (done) { const inputs = []; let forceUpdate = null; let model = null; const TestForm = React.createClass({ componentWillMount() { forceUpdate = this.forceUpdate.bind(this); }, render() { return ( (model = formModel)}> {inputs} ); } }); const form = TestUtils.renderIntoDocument(); // Wait before adding the input immediate(() => { inputs.push(); forceUpdate(() => { // Wait for next event loop, as that does the form immediate(() => { TestUtils.Simulate.change(TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT'), {target: {value: 'foo'}}); TestUtils.Simulate.submit(React.findDOMNode(form)); expect(model.test).toBe('foo'); done(); }); }); }); }); it('should allow a dynamically updated input to update the form-model', function (done) { let forceUpdate = null; let model = null; const TestForm = React.createClass({ componentWillMount() { forceUpdate = this.forceUpdate.bind(this); }, render() { const input = ; return ( (model = formModel)}> {input} ); } }); let form = TestUtils.renderIntoDocument(); // Wait before changing the input immediate(() => { form = TestUtils.renderIntoDocument(); forceUpdate(() => { // Wait for next event loop, as that does the form immediate(() => { TestUtils.Simulate.submit(React.findDOMNode(form)); expect(model.test).toBe('bar'); done(); }); }); }); }); describe('validations', function () { let CheckValid, onSubmit, OtherCheckValid; let isValid; const TestForm = React.createClass({ getDefaultProps() { return { inputs: [] }; }, render() { const builtInputs = this.props.inputs.map((input) => ); return ( onSubmit(arg1)} onValid={() => (isValid = true)} onInvalid={() => (isValid = false)}> { builtInputs } ); } }); beforeEach(() => { isValid = true; CheckValid = jasmine.createSpy('CheckValid'); Formsy.addValidationRule('CheckValid', CheckValid); OtherCheckValid = jasmine.createSpy('CheckValid'); Formsy.addValidationRule('OtherCheckValid', OtherCheckValid); onSubmit = jasmine.createSpy('onSubmit'); }); it('should run when the input changes', function () { const inputs = [{name: 'one', validations: 'CheckValid', value: 'foo'}]; const form = TestUtils.renderIntoDocument(); const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input'); TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'bar'}}); expect(CheckValid).toHaveBeenCalledWith({one: 'bar'}, 'bar', true); expect(OtherCheckValid).not.toHaveBeenCalled(); }); it('should allow the validation to be changed', function () { const inputs = [{name: 'one', validations: 'CheckValid', value: 'foo'}]; const form = TestUtils.renderIntoDocument(); form.setProps({inputs: [{name: 'one', validations: 'OtherCheckValid', value: 'foo'}] }); const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input'); TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'bar'}}); expect(OtherCheckValid).toHaveBeenCalledWith({one: 'bar'}, 'bar', true); }); it('should invalidate a form if dynamically inserted input is invalid', function (done) { const inputs = [{name: 'one', validations: 'isEmail', value: 'foo@bar.com'}]; const form = TestUtils.renderIntoDocument(); expect(isValid).toEqual(true); form.setProps({inputs: [ {name: 'one', validations: 'isEmail', value: 'foo@bar.com'}, {name: 'two', validations: 'isEmail', value: 'foo@bar'} ]}, () => { immediate(() => { expect(isValid).toEqual(false); done(); }); }); }); it('should validate a form when removing an invalid input', function (done) { const form = TestUtils.renderIntoDocument(); expect(isValid).toEqual(false); form.setProps({inputs: [{name: 'one', validations: 'isEmail', value: 'foo@bar.com'}]}, () => { immediate(() => { expect(isValid).toEqual(true); done(); }); }); }); it('runs multiple validations', function () { const inputs = [{name: 'one', validations: 'CheckValid,OtherCheckValid', value: 'foo'}]; const form = TestUtils.renderIntoDocument(); const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input'); TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'bar'}}); expect(CheckValid).toHaveBeenCalledWith({one: 'bar'}, 'bar', true); expect(OtherCheckValid).toHaveBeenCalledWith({one: 'bar'}, 'bar', true); }); }); it('should not trigger onChange when form is mounted', function () { const hasChanged = jasmine.createSpy('onChange'); const TestForm = React.createClass({ render() { return ; } }); TestUtils.renderIntoDocument(); expect(hasChanged).not.toHaveBeenCalled(); }); it('should trigger onChange when form element is changed', function () { const hasChanged = jasmine.createSpy('onChange'); const TestForm = React.createClass({ render() { return ( ); } }); const form = TestUtils.renderIntoDocument(); TestUtils.Simulate.change(TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT'), {target: {value: 'bar'}}); expect(hasChanged).toHaveBeenCalled(); }); it('should trigger onChange when new input is added to form', function (done) { const hasChanged = jasmine.createSpy('onChange'); const inputs = []; let forceUpdate = null; const TestForm = React.createClass({ componentWillMount() { forceUpdate = this.forceUpdate.bind(this); }, render() { return ( {inputs} ); } }); TestUtils.renderIntoDocument(); // Wait before adding the input inputs.push(); forceUpdate(() => { // Wait for next event loop, as that does the form immediate(() => { expect(hasChanged).toHaveBeenCalled(); done(); }); }); }); }); describe('Update a form', function () { it('should allow elements to check if the form is disabled', function (done) { const TestForm = React.createClass({ getInitialState() { return { disabled: true }; }, enableForm() { this.setState({ disabled: false }); }, render() { return ( ); } }); const form = TestUtils.renderIntoDocument(); const input = TestUtils.findRenderedComponentWithType(form, TestInput); expect(input.isFormDisabled()).toBe(true); form.enableForm(); immediate(() => { expect(input.isFormDisabled()).toBe(false); done(); }); }); it('should be possible to pass error state of elements by changing an errors attribute', function (done) { const TestForm = React.createClass({ getInitialState() { return { validationErrors: { foo: 'bar' } }; }, onChange(values) { this.setState(values.foo ? { validationErrors: {} } : { validationErrors: {foo: 'bar'} }); }, render() { return ( ); } }); const form = TestUtils.renderIntoDocument(); // Wait for update immediate(() => { const input = TestUtils.findRenderedComponentWithType(form, TestInput); expect(input.getErrorMessage()).toBe('bar'); input.setValue('gotValue'); // Wait for update immediate(() => { expect(input.getErrorMessage()).toBe(null); done(); }); }); }); it('should trigger an onValidSubmit when submitting a valid form', function () { let isCalled = false; const TestForm = React.createClass({ render() { return ( (isCalled = true)}> ); } }); const form = TestUtils.renderIntoDocument(); const FoundForm = TestUtils.findRenderedComponentWithType(form, TestForm); TestUtils.Simulate.submit(React.findDOMNode(FoundForm)); expect(isCalled).toBe(true); }); it('should trigger an onInvalidSubmit when submitting an invalid form', function () { let isCalled = false; const TestForm = React.createClass({ render() { return ( (isCalled = true)}> ); } }); const form = TestUtils.renderIntoDocument( ); const FoundForm = TestUtils.findRenderedComponentWithType(form, TestForm); TestUtils.Simulate.submit(React.findDOMNode(FoundForm)); expect(isCalled).toBe(true); }); }); describe("value === false", function () { let onSubmit; const TestForm = React.createClass({ render() { return ( onSubmit(x)}> ); } }); beforeEach(() => { onSubmit = jasmine.createSpy('onSubmit'); }); it("should call onSubmit correctly", function () { const form = TestUtils.renderIntoDocument(); TestUtils.Simulate.submit(React.findDOMNode(form)); expect(onSubmit).toHaveBeenCalledWith({foo: false}); }); it("should allow dynamic changes to false", function () { const form = TestUtils.renderIntoDocument(); form.setProps({value: false}); TestUtils.Simulate.submit(React.findDOMNode(form)); expect(onSubmit).toHaveBeenCalledWith({foo: false}); }); it("should say the form is submitted", function () { const form = TestUtils.renderIntoDocument(); const input = TestUtils.findRenderedComponentWithType(form, TestInput); expect(input.isFormSubmitted()).toBe(false); TestUtils.Simulate.submit(React.findDOMNode(form)); expect(input.isFormSubmitted()).toBe(true); }); it("should be able to reset the form to its pristine state", function () { const form = TestUtils.renderIntoDocument(); const input = TestUtils.findRenderedComponentWithType(form, TestInput); const formsyForm = TestUtils.findRenderedComponentWithType(form, Formsy.Form); expect(input.getValue()).toBe(true); form.setProps({value: false}); expect(input.getValue()).toBe(false); formsyForm.reset(); expect(input.getValue()).toBe(true); }); it("should be able to reset the form using custom data", function () { const form = TestUtils.renderIntoDocument(); const input = TestUtils.findRenderedComponentWithType(form, TestInput); const formsyForm = TestUtils.findRenderedComponentWithType(form, Formsy.Form); expect(input.getValue()).toBe(true); form.setProps({value: false}); expect(input.getValue()).toBe(false); formsyForm.reset({ foo: 'bar' }); expect(input.getValue()).toBe('bar'); }); }); describe('.isChanged()', function () { let onChange; const TestForm = React.createClass({ getDefaultProps() { return { inputs: [] }; }, render() { const builtInputs = this.props.inputs.map((input) => ); return ( { builtInputs } { this.props.children } ); } }); beforeEach(() => { onChange = jasmine.createSpy('onChange'); }); it('initially returns false', function () { const form = TestUtils.renderIntoDocument(); expect(form.refs.formsy.isChanged()).toEqual(false); expect(onChange).not.toHaveBeenCalled(); }); it('returns true when changed', function () { const form = TestUtils.renderIntoDocument(); const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input'); TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'bar'}}); expect(form.refs.formsy.isChanged()).toEqual(true); expect(onChange).toHaveBeenCalledWith({one: 'bar'}, true); }); it('returns false if changes are undone', function () { const form = TestUtils.renderIntoDocument(); const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input'); TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'bar'}}); expect(onChange).toHaveBeenCalledWith({one: 'bar'}, true); TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'foo'}}); expect(form.refs.formsy.isChanged()).toEqual(false); expect(onChange).toHaveBeenCalledWith({one: 'foo'}, false); }); }); });