diff --git a/__test_utils__/DynamicInputForm.tsx b/__test_utils__/DynamicInputForm.tsx index efe165c2..f607ab57 100644 --- a/__test_utils__/DynamicInputForm.tsx +++ b/__test_utils__/DynamicInputForm.tsx @@ -18,7 +18,7 @@ class DynamicInputForm extends React.Component { const { inputName } = this.props; this.setState({ - input: , + input: , }); }; @@ -28,11 +28,11 @@ class DynamicInputForm extends React.Component - + {input} {children} - diff --git a/__test_utils__/TestInput.tsx b/__test_utils__/TestInput.tsx index b1dbe4d5..93b24937 100644 --- a/__test_utils__/TestInput.tsx +++ b/__test_utils__/TestInput.tsx @@ -4,7 +4,8 @@ import React from 'react'; import { withFormsy } from '../src'; import { PassDownProps } from '../src/withFormsy'; -export type FormsyInputProps = Omit, 'required' | 'value'> & PassDownProps; +export type FormsyInputProps = Omit, 'required' | 'value'> & + PassDownProps & { testId?: string }; class TestInput extends React.Component { updateValue = (event) => { @@ -12,7 +13,21 @@ class TestInput extends React.Component { }; render() { - return ; + return ( + + ); } } diff --git a/__test_utils__/TestInputHoc.tsx b/__test_utils__/TestInputHoc.tsx index bf0e9d4f..a67d37d0 100644 --- a/__test_utils__/TestInputHoc.tsx +++ b/__test_utils__/TestInputHoc.tsx @@ -1,10 +1,14 @@ import React from 'react'; import { withFormsy } from '../src'; +import { PassDownProps } from '../src/withFormsy'; -class TestComponent extends React.Component { +type TestComponentProps = { testId?: string; name?: string } & PassDownProps; + +class TestComponent extends React.Component { render() { - return ; + const { testId, name } = this.props; + return ; } } -export default withFormsy(TestComponent as any); +export default withFormsy(TestComponent); diff --git a/__test_utils__/expectIsValid.tsx b/__test_utils__/expectIsValid.tsx deleted file mode 100644 index b6b51b74..00000000 --- a/__test_utils__/expectIsValid.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; - -import Formsy from '../src'; -import { InputFactory } from './TestInput'; -import { getWrapperInstance } from './getInput'; - -const TestInput = InputFactory({ - render() { - const { value } = this.props; - return ; - }, -}); - -function ValidationForm(props: { validations: string; value?: any }) { - const { validations, value } = props; - - return ( - - - - ); -} - -export function expectIsValid(testForm: React.ComponentElement) { - const form = mount(testForm); - const inputComponent = form.find('Formsy(TestInput)'); - return expect(getWrapperInstance(inputComponent).isValid()); -} - -export default ValidationForm; diff --git a/__test_utils__/getInput.ts b/__test_utils__/getInput.ts deleted file mode 100644 index 8d54378c..00000000 --- a/__test_utils__/getInput.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { WrapperInstanceMethods } from '../src/withFormsy'; -import Formsy from '../src'; - -export function getWrapperInstance(inputComponent) { - return inputComponent.instance() as WrapperInstanceMethods; -} - -export function getInputInstance(inputComponent) { - return inputComponent.instance() as HTMLInputElement; -} - -export function getFormInstance(formComponent) { - return formComponent.instance() as Formsy; -} diff --git a/__test_utils__/getValidState.tsx b/__test_utils__/getValidState.tsx new file mode 100644 index 00000000..f4712da0 --- /dev/null +++ b/__test_utils__/getValidState.tsx @@ -0,0 +1,31 @@ +import { render } from '@testing-library/react'; +import React from 'react'; + +import Formsy from '../src'; +import { InputFactory } from './TestInput'; + +const TestInput = InputFactory({ + render() { + const { value, isValid, testId } = this.props; + return ; + }, +}); + +function ValidationForm(props: { validations: string; value?: any }) { + const { validations, value } = props; + + return ( + + + + ); +} + +export async function getValidState(testForm: React.ComponentElement) { + const form = render(testForm); + const inputComponent = await form.findByTestId('test-input'); + + return inputComponent.dataset.isValid === 'true'; +} + +export default ValidationForm; diff --git a/__test_utils__/immediate.ts b/__test_utils__/immediate.ts deleted file mode 100644 index ed311ae3..00000000 --- a/__test_utils__/immediate.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default function (fn) { - setTimeout(fn, 0); -} diff --git a/__tests__/Element.spec.tsx b/__tests__/Element.spec.tsx index 8b43a511..d8defb50 100644 --- a/__tests__/Element.spec.tsx +++ b/__tests__/Element.spec.tsx @@ -1,50 +1,59 @@ -import { mount } from 'enzyme'; -import React from 'react'; -import { getFormInstance, getInputInstance, getWrapperInstance } from '../__test_utils__/getInput'; -import immediate from '../__test_utils__/immediate'; +import { fireEvent, render } from '@testing-library/react'; +import React, { useState } from 'react'; import TestInput, { FormsyInputProps, InputFactory } from '../__test_utils__/TestInput'; import Formsy, { withFormsy } from '../src'; describe('Element', () => { it('should pass down correct value prop after using setValue()', () => { - const form = mount( + const screen = render( - + , ); - const input = form.find('input'); - expect(getInputInstance(input).value).toEqual('foo'); - input.simulate('change', { target: { value: 'foobar' } }); - expect(getInputInstance(input).value).toEqual('foobar'); + const input = screen.getByTestId('test-input') as HTMLInputElement; + expect(input.value).toEqual('foo'); + + fireEvent.change(input, { target: { value: 'foobar' } }); + expect(input.value).toEqual('foobar'); }); it('withFormsy: should only set the value and not validate when calling setValue(val, false)', () => { const Input = withFormsy( class NoValidateInput extends React.Component { updateValue = (event) => { - this.props.setValue(event.target.value, false); + this.props.setValue(event.target.value, false); // disables validation }; render() { - return ; + return ( + + ); } }, ); - const form = mount( + + const screen = render( - + , ); - const inputComponent = form.find('Formsy(NoValidateInput)'); - const setStateSpy = jest.spyOn(getWrapperInstance(inputComponent) as any, 'setState'); - const inputElement = form.find('input'); - - expect(setStateSpy).not.toHaveBeenCalled(); - inputElement.simulate('change', { target: { value: 'foobar' } }); - expect(setStateSpy).toHaveBeenCalledTimes(1); - expect(setStateSpy).toHaveBeenCalledWith({ value: 'foobar' }); + + const inputElement = screen.getByTestId('test-input') as HTMLInputElement; + + expect(inputElement.dataset.isvalid).toEqual('true'); + + fireEvent.change(inputElement, { target: { value: '' } }); + + expect(inputElement.value).toEqual(''); // new value set + expect(inputElement.dataset.isvalid).toEqual('true'); // validation not changed; }); it('should set back to pristine value when running reset', () => { @@ -54,26 +63,27 @@ describe('Element', () => { reset = this.props.resetValue; }, }); - const form = mount( + const screen = render( - + , ); - const input = form.find('input'); - input.simulate('change', { target: { value: 'foobar' } }); + const input = screen.getByTestId('test-input') as HTMLInputElement; + fireEvent.change(input, { target: { value: 'foobar' } }); reset(); - expect(getInputInstance(input).value).toEqual('foo'); + expect(input.value).toEqual('foo'); }); it('should return error message passed when calling getErrorMessage()', () => { - let errorMessage = null; + let errorMessage; const Input = InputFactory({ componentDidUpdate() { errorMessage = this.props.errorMessage; }, }); - mount( + + render( , @@ -82,33 +92,14 @@ describe('Element', () => { expect(errorMessage).toEqual('Has to be email'); }); - it('should return true or false when calling isValid() depending on valid state', () => { - let isValid = null; - const Input = InputFactory({ - componentDidUpdate() { - isValid = this.props.isValid; - }, - }); - const form = mount( - - - , - ); - - expect(isValid).toEqual(false); - const input = form.find('input'); - input.simulate('change', { target: { value: 'foo@foo.com' } }); - expect(isValid).toEqual(true); - }); - it('should return true or false when calling isRequired() depending on passed required attribute', () => { - const isRequireds = []; + const isRequires = []; const Input = InputFactory({ componentDidMount() { - isRequireds.push(this.props.isRequired); + isRequires.push(this.props.isRequired); }, }); - mount( + render( @@ -116,19 +107,19 @@ describe('Element', () => { , ); - expect(isRequireds[0]).toEqual(false); - expect(isRequireds[1]).toEqual(true); - expect(isRequireds[2]).toEqual(true); + expect(isRequires[0]).toEqual(false); + expect(isRequires[1]).toEqual(true); + expect(isRequires[2]).toEqual(true); }); it('should return true or false when calling showRequired() depending on input being empty and required is passed, or not', () => { - const showRequireds = []; + const showRequires = []; const Input = InputFactory({ componentDidMount() { - showRequireds.push(this.props.showRequired); + showRequires.push(this.props.showRequired); }, }); - mount( + render( @@ -136,26 +127,30 @@ describe('Element', () => { , ); - expect(showRequireds[0]).toEqual(false); - expect(showRequireds[1]).toEqual(true); - expect(showRequireds[2]).toEqual(false); + expect(showRequires[0]).toEqual(false); + expect(showRequires[1]).toEqual(true); + expect(showRequires[2]).toEqual(false); }); it('should return true or false when calling isPristine() depending on input has been "touched" or not', () => { const Input = InputFactory({}); - const form = mount( + const screen = render( - + , ); - expect(getFormInstance(form).inputs[0].isPristine()).toEqual(true); - const input = form.find('input'); - input.simulate('change', { target: { value: 'foo' } }); - expect(getFormInstance(form).inputs[0].isPristine()).toEqual(false); + const input = screen.getByTestId('test-input'); + expect(input.dataset.isPristine).toEqual('true'); + + fireEvent.change(input, { target: { value: 'foobar' } }); + + expect(input.dataset.isPristine).toEqual('false'); }); it('should allow an undefined value to be updated to a value', () => { + const newValue = 'foo'; + class TestForm extends React.Component<{}, { value?: string }> { constructor(props) { super(props); @@ -166,42 +161,49 @@ describe('Element', () => { changeValue = () => { this.setState({ - value: 'foo', + value: newValue, }); }; render() { return ( - + + ); } } - const form = mount(); + const screen = render(); + const btn = screen.getByTestId('btn'); + const input = screen.getByTestId('test-input') as HTMLInputElement; - form.instance().changeValue(); - const input = form.find('input'); - immediate(() => { - expect(getInputInstance(input).value).toEqual('foo'); - }); + expect(input.value).toEqual(''); + + fireEvent.click(btn); + + expect(input.value).toEqual(newValue); }); it('should be able to test a values validity', () => { function TestForm() { return ( - + ); } - const form = mount(); + const screen = render(); + const input = screen.getByTestId('test-input'); - const input = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(input).isValidValue('foo@bar.com')).toEqual(true); - expect(getWrapperInstance(input).isValidValue('foo@bar')).toEqual(false); + fireEvent.change(input, { target: { value: 'foo@bar.com' } }); + expect(input.dataset.isValid).toEqual('true'); + fireEvent.change(input, { target: { value: 'foo@bar' } }); + expect(input.dataset.isValid).toEqual('false'); }); it('should be able to use an object as validations property', () => { @@ -213,16 +215,19 @@ describe('Element', () => { validations={{ isEmail: true, }} + testId="test-input" /> ); } - const form = mount(); + const screen = render(); + const input = screen.getByTestId('test-input'); - const input = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(input).isValidValue('foo@bar.com')).toEqual(true); - expect(getWrapperInstance(input).isValidValue('foo@bar')).toEqual(false); + fireEvent.change(input, { target: { value: 'foo@bar.com' } }); + expect(input.dataset.isValid).toEqual('true'); + fireEvent.change(input, { target: { value: 'foo@bar' } }); + expect(input.dataset.isValid).toEqual('false'); }); it('should be able to pass complex values to a validation rule', () => { @@ -234,19 +239,19 @@ describe('Element', () => { validations={{ matchRegexp: /foo/, }} - value="foo" + testId="test-input" /> ); } - const form = mount(); + const screen = render(); + const input = screen.getByTestId('test-input'); - const inputComponent = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(inputComponent).isValid()).toEqual(true); - const input = form.find('input'); - input.simulate('change', { target: { value: 'bar' } }); - expect(getWrapperInstance(inputComponent).isValid()).toEqual(false); + fireEvent.change(input, { target: { value: 'foo' } }); + expect(input.dataset.isValid).toEqual('true'); + fireEvent.change(input, { target: { value: 'bar' } }); + expect(input.dataset.isValid).toEqual('false'); }); it('should be able to run a function to validate', () => { @@ -267,6 +272,7 @@ describe('Element', () => { custom: customValidationA, }} value="foo" + testId="text-input-1" /> { custom: customValidationB, }} value="foo" + testId="text-input-2" /> ); } - const form = mount(); + const screen = render(); + + const input1 = screen.getByTestId('text-input-1'); + const input2 = screen.getByTestId('text-input-2'); + + expect(input1.dataset.isValid).toEqual('true'); + expect(input2.dataset.isValid).toEqual('true'); - const inputComponent = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(inputComponent.at(0)).isValid()).toEqual(true); - expect(getWrapperInstance(inputComponent.at(1)).isValid()).toEqual(true); - const input = form.find('input'); - input.at(0).simulate('change', { target: { value: 'bar' } }); - expect(getWrapperInstance(inputComponent.at(0)).isValid()).toEqual(false); - expect(getWrapperInstance(inputComponent.at(1)).isValid()).toEqual(false); + fireEvent.change(input1, { target: { value: 'bar' } }); + + expect(input1.dataset.isValid).toEqual('false'); + expect(input2.dataset.isValid).toEqual('false'); }); it('should not override error messages with error messages passed by form if passed error messages is an empty object', () => { @@ -302,15 +312,16 @@ describe('Element', () => { validationError="bar2" validationErrors={{ isEmail: 'bar3' }} value="foo" + testId="test-input" /> ); } - const form = mount(); + const screen = render(); + const input = screen.getByTestId('test-input'); - const inputComponent = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(inputComponent).getErrorMessage()).toEqual('bar3'); + expect(input.dataset.errorMessage).toEqual('bar3'); }); it('should handle multiple validation error messages passed from validators', () => { @@ -324,7 +335,7 @@ describe('Element', () => { function TestForm() { return ( - + { customValidationB, }} value="foo" + testId="test-input" /> ); } - const form = mount(); - const inputComponent = form.find('Formsy(TestInput)'); + const screen = render(); + const input = screen.getByTestId('test-input'); - const formEl = form.find('form'); - formEl.simulate('submit'); + const form = screen.getByTestId('form'); + fireEvent.submit(form); - expect(getWrapperInstance(inputComponent).getErrorMessage()).toEqual('error message one'); - expect(getWrapperInstance(inputComponent).getErrorMessages()).toEqual(['error message one', 'error message two']); + expect(input.dataset.errorMessage).toEqual('error message one'); + expect(input.dataset.errorMessages.split(';')).toEqual(['error message one', 'error message two']); }); it('should override all error messages with error messages passed by form', () => { @@ -359,15 +371,16 @@ describe('Element', () => { validationError="bar2" validationErrors={{ isEmail: 'bar3' }} value="foo" + testId="test-input" /> ); } - const form = mount(); + const screen = render(); - const inputComponent = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(inputComponent).getErrorMessage()).toEqual('bar'); + const input = screen.getByTestId('test-input'); + expect(input.dataset.errorMessage).toEqual('bar'); }); it('should override validation rules with required rules', () => { @@ -385,15 +398,16 @@ describe('Element', () => { required={{ isLength: 1, }} + testId="test-input" /> ); } - const form = mount(); + const screen = render(); + const input = screen.getByTestId('test-input'); - const inputComponent = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(inputComponent).getErrorMessage()).toEqual('bar3'); + expect(input.dataset.errorMessage).toEqual('bar3'); }); it('should fall back to default error message when non exist in validationErrors map', () => { @@ -408,46 +422,47 @@ describe('Element', () => { validationError="bar1" validationErrors={{ foo: 'bar2' }} value="foo" + testId="test-input" /> ); } - const form = mount(); + const screen = render(); + const input = screen.getByTestId('test-input'); - const inputComponent = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(inputComponent).getErrorMessage()).toEqual('bar1'); + expect(input.dataset.errorMessage).toEqual('bar1'); }); it('should not be valid if it is required and required rule is true', () => { function TestForm() { return ( - + ); } - const form = mount(); + const screen = render(); - const inputComponent = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(inputComponent).isValid()).toEqual(false); + const input = screen.getByTestId('test-input'); + expect(input.dataset.isValid).toEqual('false'); }); it('should return the validationError if the field is invalid and required rule is true', () => { function TestForm() { return ( - + ); } - const form = mount(); + const screen = render(); - const inputComponent = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(inputComponent).isValid()).toEqual(false); - expect(getWrapperInstance(inputComponent).getErrorMessage()).toEqual('Field is required'); + const input = screen.getByTestId('test-input'); + expect(input.dataset.isValid).toEqual('false'); + expect(input.dataset.errorMessage).toEqual('Field is required'); }); it('should handle objects and arrays as values', () => { @@ -460,26 +475,33 @@ describe('Element', () => { }; } + changeData = () => { + this.setState({ + foo: { foo: 'foo' }, + bar: ['bar'], + }); + }; + render() { return ( - - + + + @@ -134,18 +129,18 @@ describe('Setting up a form', () => { } } - const form = mount(); + const screen = render(); + const form = screen.getByTestId('form'); + const updateBtn = screen.getByTestId('update-btn'); - form.simulate('submit'); + fireEvent.submit(form); - expect(model).toHaveProperty('test', 'foo'); + expect(submitSpy).toHaveBeenCalledWith({ test: 'foo' }); - form.find('button').simulate('click'); - form.update(); - form.simulate('submit'); - form.update(); + fireEvent.click(updateBtn); + fireEvent.submit(form); - expect(model).toHaveProperty('test', 'bar'); + expect(submitSpy).toHaveBeenCalledWith({ test: 'bar' }); }); }); @@ -159,15 +154,17 @@ describe('mapModel', () => { function TestForm() { return ( - + ); } - const form = mount(); + const screen = render(); + const form = screen.getByTestId('form'); + + fireEvent.submit(form); - form.simulate('submit'); expect(mapping).toHaveBeenCalledWith({ 'parent.child': 'test' }); expect(onSubmit).toHaveBeenCalledWith( { 'parent.child': 'test', testChange: true }, @@ -186,14 +183,14 @@ describe('validations', () => { addValidationRule('runRule', runRule); addValidationRule('notRunRule', notRunRule); - const form = mount( + const screen = render( - + , ); - const input = form.find('input'); - input.simulate('change', { + const input = screen.getByTestId('test-input'); + fireEvent.change(input, { target: { value: 'bar' }, }); @@ -222,23 +219,29 @@ describe('validations', () => { render() { return ( - + + ); } - const form = mount(); - form.simulate('submit'); + const screen = render(); + const form = screen.getByTestId('form'); + + fireEvent.submit(form); + expect(onSubmit).toHaveBeenCalledWith( { foo: false }, expect.any(Function), @@ -577,25 +626,31 @@ describe('value === false', () => { }; } - changeValue() { + changeValue = () => { this.setState({ value: false, }); - } + }; render() { return ( - + - + ); } } - const form = mount(); - (form.instance() as TestForm).changeValue(); - form.simulate('submit'); + const screen = render(); + const form = screen.getByTestId('form'); + const changeValueBtn = screen.getByTestId('change-value-btn'); + + fireEvent.click(changeValueBtn); + fireEvent.submit(form); + expect(onSubmit).toHaveBeenCalledWith( { foo: false }, expect.any(Function), @@ -608,17 +663,23 @@ describe('value === false', () => { function TestForm() { return ( - - + + ); } - const form = mount(); - const input = form.find('Formsy(TestInput)'); - expect(getWrapperInstance(input).isFormSubmitted()).toEqual(false); - form.simulate('submit'); - expect(getWrapperInstance(input).isFormSubmitted()).toEqual(true); + const screen = render(); + const input = screen.getByTestId('test-input'); + const submitBtn = screen.getByTestId('submit-btn'); + + expect(input.dataset.isFormSubmitted).toEqual('false'); + + fireEvent.click(submitBtn); + + expect(input.dataset.isFormSubmitted).toEqual('true'); }); it('should be able to reset the form to its pristine state', () => { @@ -630,34 +691,47 @@ describe('value === false', () => { }; } - changeValue() { + changeValue = () => { this.setState({ value: false, }); - } + }; render() { return ( - - + + + ); } } - const form = mount(); - const input = form.find('Formsy(TestInput)'); - const formsyForm = form.find(Formsy); - expect(getWrapperInstance(input).getValue()).toEqual(true); - (form.instance() as TestForm).changeValue(); - expect(getWrapperInstance(input).getValue()).toEqual(false); - getFormInstance(formsyForm).reset(); - expect(getWrapperInstance(input).getValue()).toEqual(true); + const screen = render(); + const input = screen.getByTestId('test-input') as HTMLInputElement; + const changeValueBtn = screen.getByTestId('change-value-btn'); + const resetBtn = screen.getByTestId('reset-btn'); + + expect(input.dataset.value).toEqual('true'); + + fireEvent.click(changeValueBtn); + + expect(input.dataset.value).toEqual('false'); + + fireEvent.click(resetBtn); + + expect(input.dataset.value).toEqual('true'); }); it('should be able to set a value to components with updateInputsWithValue', () => { class TestForm extends React.Component<{}, { valueFoo: boolean; valueBar: boolean }> { + formRef = React.createRef(); + constructor(props) { super(props); this.state = { @@ -666,29 +740,39 @@ describe('value === false', () => { }; } + updateInputsWithValue = () => { + this.formRef.current.updateInputsWithValue({ foo: false }); + }; + render() { return ( - - - - + + + + + + + + + + + + + + + ); } - const form = mount(); - const input = form.find('Formsy(TestInput)'); - const formsyForm = form.find(Formsy); + const screen = render(); + const input = screen.getByTestId('test-input') as HTMLInputElement; + const resetBtn = screen.getByTestId('reset-btn'); - getFormInstance(formsyForm).reset({ - foo: '', - }); - expect(getWrapperInstance(input).getValue()).toEqual(''); + fireEvent.click(resetBtn); + + expect(input.value).toEqual(''); }); it('should be able to reset the form using a button', () => { function TestForm() { return ( - - + + ); } - const form = mount(); - const input = form.find('Formsy(TestInput)'); - const formsyForm = form.find(Formsy); + const screen = render(); + const input = screen.getByTestId('test-input') as HTMLInputElement; + const resetBtn = screen.getByTestId('reset-btn'); + + expect(input.value).toEqual('foo'); + + fireEvent.change(input, { target: { value: 'foobar' } }); + + expect(input.value).toEqual('foobar'); + + fireEvent.click(resetBtn); - expect(getWrapperInstance(input).getValue()).toEqual('foo'); - input.simulate('change', { target: { value: 'foobar' } }); - expect(getWrapperInstance(input).getValue()).toEqual('foobar'); - formsyForm.simulate('reset'); - expect(getWrapperInstance(input).getValue()).toEqual('foo'); + expect(input.value).toEqual('foo'); }); }); describe('.isChanged()', () => { it('initially returns false', () => { const hasOnChanged = jest.fn(); - const form = mount( - + const formRef = React.createRef(); + render( + , ); - expect(getFormInstance(form).isChanged()).toEqual(false); + + expect(formRef.current.isChanged()).toEqual(false); expect(hasOnChanged).not.toHaveBeenCalled(); }); it('returns true when changed', () => { const hasOnChanged = jest.fn(); - const form = mount( + const screen = render( - + , ); - const input = form.find('input'); - input.simulate('change', { + const input = screen.getByTestId('test-input'); + fireEvent.change(input, { target: { value: 'bar' }, }); - expect(getFormInstance(form).isChanged()).toEqual(true); + expect(hasOnChanged).toHaveBeenCalledWith({ one: 'bar' }, true); }); it('returns false if changes are undone', () => { const hasOnChanged = jest.fn(); - const form = mount( + const screen = render( - + , ); - const input = form.find('input'); - input.simulate('change', { + const input = screen.getByTestId('test-input'); + fireEvent.change(input, { target: { value: 'bar' }, }); expect(hasOnChanged).toHaveBeenCalledWith({ one: 'bar' }, true); - input.simulate('change', { + fireEvent.change(input, { target: { value: 'foo' }, }); - - expect(getFormInstance(form).isChanged()).toEqual(false); expect(hasOnChanged).toHaveBeenCalledWith({ one: 'foo' }, false); }); }); @@ -880,17 +998,23 @@ describe('form valid state', () => { render() { return ( - + ); } } - const form = mount(); + const screen = render(); + const form = screen.getByTestId('form'); expect(isValid).toEqual(true); - form.simulate('submit'); + fireEvent.submit(form); expect(isValid).toEqual(false); }); @@ -901,22 +1025,36 @@ describe('form valid state', () => { // do nothing }); + const errorSpy = jest.fn(); + class TestForm extends React.Component { onValidSubmit = (_model, _reset, updateInputsWithError) => { - updateInputsWithError({ bar: 'bar' }, true); + try { + updateInputsWithError({ bar: 'bar' }, true); + } catch (e) { + errorSpy(e.message); + } }; + public componentDidCatch(error: Error) { + errorSpy(error); + } + render() { return ( - - + + ); } } - const form = mount(); - expect(() => form.simulate('submit')).toThrow(); + const screen = render(); + const form = screen.getByTestId('form'); + fireEvent.submit(form); + expect(errorSpy).toHaveBeenCalledWith( + expect.stringContaining('You are trying to update an input that does not exist'), + ); mockConsoleError.mockRestore(); }); @@ -947,15 +1085,17 @@ describe('form valid state', () => { return ( + {Array.from(Array(counter)).map((_, index) => ( @@ -1029,13 +1172,14 @@ describe('form valid state', () => { ); }; jest.useFakeTimers(); - const form = mount(); - const plusButton = form.find('#add'); + const screen = render(); + const plusButton = screen.getByTestId('add-btn'); + jest.runAllTimers(); expect(isValid).toBe(true); - plusButton.simulate('click'); + fireEvent.click(plusButton); expect(isValid).toBe(false); }); @@ -1051,7 +1195,7 @@ describe('form valid state', () => { ); - mount(); + render(); expect(validSpy).toHaveBeenCalledTimes(1 + 1); // one for form mount & 1 for all attachToForm calls }); @@ -1062,20 +1206,21 @@ describe('onSubmit/onValidSubmit/onInvalidSubmit', () => { it(`should pass submit event to "${key}"`, () => { const submitSpy = jest.fn(); - const form = mount( + const screen = render( - +